xfsprogs-5.3.0/.gitignore0000644000175000017500000000210713435336036015242 0ustar nathansnathans# object files *.o .dep .ltdep # build system .census .gitcensus /include/platform_defs.h /include/builddefs /install-sh # magic directory symlinks /include/disk /include/xfs # packaging /doc/CHANGES.gz /xfsprogs-* /xfsprogs_* /xfslibs-dev_* # autoconf generated files /aclocal.m4 /m4/libtool.m4 /m4/ltoptions.m4 /m4/ltsugar.m4 /m4/ltversion.m4 /m4/lt~obsolete.m4 /autom4te.cache/ /config.guess /config.log /config.status /config.sub /configure # libtool /libtool /ltmain.sh *.lo *.la .libs # gettext /po/de.mo /po/pl.mo /po/xfsprogs.pot # cscope stuff cscope.* # quilt stuff /.pc/ /patches/ # binaries /copy/xfs_copy /db/xfs_db /estimate/xfs_estimate /fsr/xfs_fsr /growfs/xfs_growfs /io/xfs_io /logprint/xfs_logprint /mdrestore/xfs_mdrestore /mkfs/fstyp /mkfs/mkfs.xfs /quota/xfs_quota /repair/xfs_repair /rtcp/xfs_rtcp /spaceman/xfs_spaceman /scrub/xfs_scrub /scrub/xfs_scrub@.service /scrub/xfs_scrub_all /scrub/xfs_scrub_all.cron /scrub/xfs_scrub_all.service /scrub/xfs_scrub_fail@.service # generated crc files /libfrog/crc32selftest /libfrog/crc32table.h /libfrog/gen_crc32table xfsprogs-5.3.0/LICENSES/GPL-2.00000644000175000017500000004445113570057155015333 0ustar nathansnathansValid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0+ Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: SPDX-License-Identifier: GPL-2.0 or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0+ or SPDX-License-Identifier: GPL-2.0-or-later License-Text: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. xfsprogs-5.3.0/LICENSES/LGPL-2.10000644000175000017500000006542513435336036015452 0ustar nathansnathansValid-License-Identifier: LGPL-2.1 Valid-License-Identifier: LGPL-2.1+ SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU Lesser General Public License (LGPL) version 2.1 only' use: SPDX-License-Identifier: LGPL-2.1 For 'GNU Lesser General Public License (LGPL) version 2.1 or any later version' use: SPDX-License-Identifier: LGPL-2.1+ License-Text: GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. one line to give the library's name and an idea of what it does. Copyright (C) year name of author This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. signature of Ty Coon, 1 April 1990 Ty Coon, President of Vice That's all there is to it! xfsprogs-5.3.0/Makefile0000644000175000017500000001233413570057155014717 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. # ifeq ("$(origin V)", "command line") BUILD_VERBOSE = $(V) endif ifndef BUILD_VERBOSE BUILD_VERBOSE = 0 endif ifeq ($(BUILD_VERBOSE),1) Q = else Q = @ endif CHECK=sparse CHECK_OPTS=-Wsparse-all -Wbitwise -Wno-transparent-union -Wno-return-void -Wno-undef \ -Wno-non-pointer-null -D__CHECK_ENDIAN__ -D__linux__ ifeq ("$(origin C)", "command line") CHECK_CMD=$(CHECK) $(CHECK_OPTS) CHECKSRC=$(C) else CHECK_CMD=@true CHECKSRC=0 endif export CHECK_CMD CHECKSRC MAKEOPTS = --no-print-directory Q=$(Q) TOPDIR = . HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) ifeq ($(HAVE_BUILDDEFS), yes) include $(TOPDIR)/include/builddefs endif SRCDIR = $(PKG_NAME)-$(PKG_VERSION) SRCTAR = $(PKG_NAME)-$(PKG_VERSION).tar.gz SRCTARXZ = $(PKG_NAME)-$(PKG_VERSION).tar.xz CONFIGURE = aclocal.m4 configure config.guess config.sub install-sh ltmain.sh LSRCFILES = configure.ac release.sh README VERSION $(CONFIGURE) SRCTARINC = m4/libtool.m4 m4/lt~obsolete.m4 m4/ltoptions.m4 m4/ltsugar.m4 \ m4/ltversion.m4 po/xfsprogs.pot .gitcensus $(CONFIGURE) LDIRT = config.log .ltdep .dep config.status config.cache confdefs.h \ conftest* built .census install.* install-dev.* *.gz *.xz \ autom4te.cache/* libtool include/builddefs include/platform_defs.h ifeq ($(HAVE_BUILDDEFS), yes) LDIRDIRT = $(SRCDIR) LDIRT += $(SRCTAR) $(SRCTARXZ) endif # header install rules to populate include/xfs correctly HDR_SUBDIRS = include libxfs LIBFROG_SUBDIR = libfrog DLIB_SUBDIRS = libxlog libxcmd libhandle LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS) TOOL_SUBDIRS = copy db estimate fsck fsr growfs io logprint mkfs quota \ mdrestore repair rtcp m4 man doc debian spaceman ifeq ("$(ENABLE_SCRUB)","yes") TOOL_SUBDIRS += scrub endif ifneq ("$(XGETTEXT)","") TOOL_SUBDIRS += po endif # If we are on OS X, use glibtoolize from MacPorts, as OS X doesn't have # libtoolize binary itself. LIBTOOLIZE_TEST=$(shell libtoolize --version >/dev/null 2>&1 && echo found) LIBTOOLIZE_BIN=libtoolize ifneq ("$(LIBTOOLIZE_TEST)","found") LIBTOOLIZE_BIN=glibtoolize endif # include is listed last so it is processed last in clean rules. SUBDIRS = $(LIBFROG_SUBDIR) $(LIB_SUBDIRS) $(TOOL_SUBDIRS) include default: include/builddefs include/platform_defs.h ifeq ($(HAVE_BUILDDEFS), no) $(Q)$(MAKE) $(MAKEOPTS) -C . $@ else $(Q)$(MAKE) $(MAKEOPTS) headers $(Q)$(MAKE) $(MAKEOPTS) $(SUBDIRS) endif # tool/lib dependencies # note: include/xfs is set up by libxfs, too, so everything is dependent on it. $(LIBFROG_SUBDIR): include $(LIB_SUBDIRS) $(TOOL_SUBDIRS): include libfrog $(DLIB_SUBDIRS) $(TOOL_SUBDIRS): libxfs db logprint: libxlog fsr: libhandle growfs: libxcmd io: libxcmd libhandle quota: libxcmd repair: libxlog libxcmd copy: libxlog mkfs: libxcmd spaceman: libxcmd scrub: libhandle libxcmd rtcp: libfrog ifeq ($(HAVE_BUILDDEFS), yes) include $(BUILDRULES) else clean: # if configure hasn't run, nothing to clean endif # Recent versions of libtool require the -i option for copying auxiliary # files (config.sub, config.guess, install-sh, ltmain.sh), while older # versions will copy those files anyway, and don't understand -i. LIBTOOLIZE_INSTALL = `$(LIBTOOLIZE_BIN) -n -i >/dev/null 2>/dev/null && echo -i` configure: configure.ac $(LIBTOOLIZE_BIN) -c $(LIBTOOLIZE_INSTALL) -f cp include/install-sh . aclocal -I m4 autoconf include/builddefs: configure ./configure $$LOCAL_CONFIGURE_OPTIONS include/platform_defs.h: include/builddefs ## Recover from the removal of $@ @if test -f $@; then :; else \ rm -f include/builddefs; \ $(MAKE) $(MAKEOPTS) $(AM_MAKEFLAGS) include/builddefs; \ fi install: $(addsuffix -install,$(SUBDIRS)) $(INSTALL) -m 755 -d $(PKG_DOC_DIR) $(INSTALL) -m 644 README $(PKG_DOC_DIR) install-dev: $(addsuffix -install-dev,$(SUBDIRS)) %-install: @echo "Installing $@" $(Q)$(MAKE) $(MAKEOPTS) -C $* install %-install-dev: @echo "Installing $@" $(Q)$(MAKE) $(MAKEOPTS) -C $* install-dev distclean: clean $(Q)rm -f $(LDIRT) realclean: distclean $(Q)rm -f $(CONFIGURE) .gitcensus # # All this gunk is to allow for a make dist on an unconfigured tree # dist: include/builddefs include/platform_defs.h default ifeq ($(HAVE_BUILDDEFS), no) $(Q)$(MAKE) $(MAKEOPTS) -C . $@ else $(Q)$(MAKE) $(MAKEOPTS) $(SRCTAR) endif deb: include/builddefs include/platform_defs.h ifeq ($(HAVE_BUILDDEFS), no) $(Q)$(MAKE) $(MAKEOPTS) -C . $@ else # need to build translations before the source tarball $(Q)$(MAKE) $(MAKEOPTS) -C po $(Q)$(MAKE) $(MAKEOPTS) $(SRCDIR) $(Q)rm -f $(PKG_NAME)_$(PKG_VERSION).orig.tar.gz $(Q)$(LN_S) $(SRCTAR) $(PKG_NAME)_$(PKG_VERSION).orig.tar.gz $(Q)cd $(SRCDIR) && dpkg-buildpackage $$LOCAL_DPKG_OPTIONS # -sa -S endif $(SRCDIR) : $(_FORCE) $(SRCTAR) rm -fr $@ $(Q)$(TAR) -zxvf $(SRCTAR) $(SRCTAR) : default $(SRCTARINC) .gitcensus $(Q)$(TAR) --transform "s,^,$(SRCDIR)/," -zcf $(SRCDIR).tar.gz \ `cat .gitcensus` $(SRCTARINC) echo Wrote: $@ $(SRCTARXZ) : default $(SRCTARINC) .gitcensus $(Q)$(TAR) --transform "s,^,$(SRCDIR)/," -Jcf $(SRCDIR).tar.xz \ `cat .gitcensus` $(SRCTARINC) echo Wrote: $@ .gitcensus: $(_FORCE) $(Q)if test -d .git; then \ git ls-files > .gitcensus && echo "new .gitcensus"; \ fi xfsprogs-5.3.0/README0000644000175000017500000000055213242461543014132 0ustar nathansnathansXFS User Tools README _____________________ See the file doc/INSTALL for build, installation and post- install configuration steps. Refer to the xfs(5) manual page for general XFS information and references to other XFS manual pages. For more information and details on how to contribute to the XFS project see the web pages at: https://xfs.wiki.kernel.org/ xfsprogs-5.3.0/VERSION0000644000175000017500000000016313570057155014324 0ustar nathansnathans# # This file is used by configure to get version information # PKG_MAJOR=5 PKG_MINOR=3 PKG_REVISION=0 PKG_BUILD=1 xfsprogs-5.3.0/configure.ac0000644000175000017500000001506613570057155015552 0ustar nathansnathansAC_INIT([xfsprogs], [5.3.0], [linux-xfs@vger.kernel.org]) AC_PREREQ(2.50) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([include/libxfs.h]) AC_CONFIG_HEADER(include/platform_defs.h) AC_PREFIX_DEFAULT(/usr) AC_PROG_INSTALL AC_PROG_LIBTOOL AC_PROG_CC AC_ARG_VAR(BUILD_CC, [C compiler for build tools]) if test "${BUILD_CC+set}" != "set"; then if test $cross_compiling = no; then BUILD_CC="$CC" else AC_CHECK_PROGS(BUILD_CC, gcc cc) fi fi AC_ARG_VAR(BUILD_CFLAGS, [C compiler flags for build tools]) if test "${BUILD_CFLAGS+set}" != "set"; then if test $cross_compiling = no; then BUILD_CFLAGS="$CFLAGS" else BUILD_CFLAGS="-g -O2" fi fi AC_ARG_ENABLE(shared, [ --enable-shared=[yes/no] Enable use of shared libraries [default=yes]],, enable_shared=yes) AC_SUBST(enable_shared) AC_ARG_ENABLE(gettext, [ --enable-gettext=[yes/no] Enable alternate language support [default=yes]],, enable_gettext=yes) AC_SUBST(enable_gettext) AC_ARG_ENABLE(blkid, [ --enable-blkid=[yes/no] Enable use of block device id library [default=yes]],, enable_blkid=yes) AC_SUBST(enable_blkid) AC_ARG_ENABLE(readline, [ --enable-readline=[yes/no] Enable readline command editing [default=no]], test $enable_readline = yes && libreadline="-lreadline", enable_readline=no) AC_SUBST(libreadline) AC_SUBST(enable_readline) AC_ARG_ENABLE(editline, [ --enable-editline=[yes/no] Enable editline command editing [default=no]], test $enable_editline = yes && libeditline="-ledit", enable_editline=no) AC_SUBST(libeditline) AC_SUBST(enable_editline) AC_ARG_ENABLE(termcap, [ --enable-termcap=[yes/no] Enable terminal capabilities library [default=no]], test $enable_termcap = yes && libtermcap="-ltermcap",) AC_SUBST(libtermcap) AC_ARG_ENABLE(lib64, [ --enable-lib64=[yes/no] Enable lib64 support [default=yes]],, enable_lib64=yes) AC_SUBST(enable_lib64) AC_ARG_ENABLE(librt, [ --enable-librt=[yes/no] Enable librt support [default=yes]],, enable_librt=yes) AC_SUBST(enable_librt) # Enable UBSAN; set enable_ubsan=probe below to enable autoprobe. AC_ARG_ENABLE(ubsan, [ --enable-ubsan=[yes/no] Enable Undefined Behavior Sanitizer (UBSAN) [default=no]],, enable_ubsan=no) AC_SUBST(enable_ubsan) # Enable ADDRSAN; set enable_addrsan=probe below to enable autoprobe. AC_ARG_ENABLE(addrsan, [ --enable-addrsan=[yes/no] Enable Address Sanitizer (ADDRSAN) [default=no]],, enable_addrsan=no) AC_SUBST(enable_addrsan) # Enable THREADSAN; set enable_threadsan=probe to enable autoprobe. AC_ARG_ENABLE(threadsan, [ --enable-threadsan=[yes/no] Enable Thread Sanitizer (THREADSAN) [default=no]],, enable_threadsan=no) AC_SUBST(enable_threadsan) AC_ARG_ENABLE(lto, [ --enable-lto=[yes/no] Enable link time optimization (LTO) [default=no]],, enable_lto=no) AC_SUBST(enable_lto) # Enable xfs_scrub build AC_ARG_ENABLE(scrub, [ --enable-scrub=[yes/no] Enable build of xfs_scrub utility [default=yes]],, enable_scrub=yes) AC_SUBST(enable_scrub) # Enable libicu for xfs_scrubbing of malicious unicode sequences in names AC_ARG_ENABLE(libicu, [ --enable-libicu=[yes/no] Enable Unicode name scanning in xfs_scrub (libicu) [default=probe]],, enable_libicu=probe) # # If the user specified a libdir ending in lib64 do not append another # 64 to the library names. # base_libdir=`basename "$libdir"` case $base_libdir in lib64) enable_lib64=no esac # # Some important tools should be installed into the root partitions. # # Check whether exec_prefix=/usr: and install them to /sbin in that # case. If the user choses a different prefix assume he just wants # a local install for testing and not a system install. # case $exec_prefix:$prefix in NONE:NONE | NONE:/usr | /usr:*) root_sbindir='/sbin' root_libdir="/${base_libdir}" ;; *) root_sbindir="${sbindir}" root_libdir="${libdir}" ;; esac AC_SUBST([root_sbindir]) AC_SUBST([root_libdir]) # Find localized files. Don't descend into any "dot directories" # (like .git or .pc from quilt). Strangely, the "-print" argument # to "find" is required, to avoid including such directories in the # list. LOCALIZED_FILES="" for lfile in `find ${srcdir} -path './.??*' -prune -o -name '*.c' -type f -print || exit 1`; do LOCALIZED_FILES="$LOCALIZED_FILES \$(TOPDIR)/$lfile" done AC_SUBST(LOCALIZED_FILES) AC_PACKAGE_GLOBALS(xfsprogs) AC_PACKAGE_UTILITIES(xfsprogs) AC_MULTILIB($enable_lib64) AC_RT($enable_librt) AC_PACKAGE_NEED_UUID_H AC_PACKAGE_NEED_UUIDCOMPARE AC_PACKAGE_NEED_PTHREAD_H AC_PACKAGE_NEED_PTHREADMUTEXINIT AC_HAVE_FADVISE AC_HAVE_MADVISE AC_HAVE_MINCORE AC_HAVE_SENDFILE AC_HAVE_GETMNTENT AC_HAVE_FALLOCATE AC_HAVE_FIEMAP AC_HAVE_PWRITEV2 AC_HAVE_PREADV AC_HAVE_COPY_FILE_RANGE AC_HAVE_SYNC_FILE_RANGE AC_HAVE_SYNCFS AC_HAVE_MNTENT AC_HAVE_FLS AC_HAVE_READDIR AC_HAVE_FSETXATTR AC_HAVE_MREMAP AC_NEED_INTERNAL_FSXATTR AC_HAVE_GETFSMAP AC_HAVE_STATFS_FLAGS AC_HAVE_MAP_SYNC AC_HAVE_DEVMAPPER AC_HAVE_MALLINFO AC_PACKAGE_WANT_ATTRIBUTES_H AC_HAVE_LIBATTR if test "$enable_scrub" = "yes"; then if test "$enable_libicu" = "yes" || test "$enable_libicu" = "probe"; then AC_HAVE_LIBICU fi if test "$enable_libicu" = "yes" && test "$have_libicu" != "yes"; then AC_MSG_ERROR([libicu not found.]) fi fi AC_HAVE_OPENAT AC_HAVE_FSTATAT AC_HAVE_SG_IO AC_HAVE_HDIO_GETGEO AC_CONFIG_SYSTEMD_SYSTEM_UNIT_DIR AC_CONFIG_CROND_DIR if test "$enable_blkid" = yes; then AC_HAVE_BLKID_TOPO fi if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then AC_PACKAGE_CHECK_UBSAN fi if test "$enable_ubsan" = "yes" && test "$have_ubsan" != "yes"; then AC_MSG_ERROR([UBSAN not supported by compiler.]) fi if test "$enable_addrsan" = "yes" || test "$enable_addrsan" = "probe"; then AC_PACKAGE_CHECK_ADDRSAN fi if test "$enable_addrsan" = "yes" && test "$have_addrsan" != "yes"; then AC_MSG_ERROR([ADDRSAN not supported by compiler.]) fi if test "$enable_threadsan" = "yes" || test "$enable_threadsan" = "probe"; then AC_PACKAGE_CHECK_THREADSAN fi if test "$enable_threadsan" = "yes" && test "$have_threadsan" != "yes"; then AC_MSG_ERROR([THREADSAN not supported by compiler.]) fi if test "$have_threadsan" = "yes" && test "$have_addrsan" = "yes"; then AC_MSG_WARN([ADDRSAN and THREADSAN are not known to work together.]) fi if test "$enable_lto" = "yes" || test "$enable_lto" = "probe"; then AC_PACKAGE_CHECK_LTO fi if test "$enable_lto" = "yes" && test "$have_lto" != "yes"; then AC_MSG_ERROR([LTO not supported by compiler.]) fi AC_CHECK_SIZEOF([long]) AC_CHECK_SIZEOF([char *]) AC_TYPE_UMODE_T AC_MANUAL_FORMAT AC_CONFIG_FILES([include/builddefs]) AC_OUTPUT xfsprogs-5.3.0/copy/Makefile0000644000175000017500000000106413435336036015665 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_copy CFILES = xfs_copy.c HFILES = xfs_copy.h LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBPTHREAD) $(LIBRT) LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG) $(LIBFROG) LLDFLAGS = -static-libtool-libs default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/copy/xfs_copy.c0000644000175000017500000010101513435336036016220 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include #include #include #include #include "xfs_copy.h" #include "libxlog.h" #define rounddown(x, y) (((x)/(y))*(y)) #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) extern int platform_check_ismounted(char *, char *, struct stat *, int); static char *logfile_name; static FILE *logerr; static char LOGFILE_NAME[] = "/var/tmp/xfs_copy.log.XXXXXX"; static char *source_name; static int source_fd; static unsigned int source_blocksize; /* source filesystem blocksize */ static unsigned int source_sectorsize; /* source disk sectorsize */ static xfs_agblock_t first_agbno; static uint64_t barcount[11]; static unsigned int num_targets; static target_control *target; static wbuf w_buf; static wbuf btree_buf; static unsigned int kids; static thread_control glob_masks; static thread_args *targ; static pthread_mutex_t mainwait; #define ACTIVE 1 #define INACTIVE 2 xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp); xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp); static int format_logs(struct xfs_mount *); /* general purpose message reporting routine */ #define OUT 0x01 /* use stdout stream */ #define ERR 0x02 /* use stderr stream */ #define LOG 0x04 /* use logerr stream */ #define PRE 0x08 /* append strerror string */ #define LAST 0x10 /* final message we print */ static void signal_maskfunc(int addset, int newset) { sigset_t set; sigemptyset(&set); sigaddset(&set, addset); sigprocmask(newset, &set, NULL); } static void do_message(int flags, int code, const char *fmt, ...) { va_list ap; int eek = 0; if (flags & LOG) { va_start(ap, fmt); if (vfprintf(logerr, fmt, ap) <= 0) eek = 1; va_end(ap); } if (eek) flags |= ERR; /* failed, force stderr */ if (flags & ERR) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } else if (flags & OUT) { va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); } if (flags & PRE) { do_message(flags & ~PRE, 0, ": %s\n", strerror(code)); if (flags & LAST) fprintf(stderr, _("Check logfile \"%s\" for more details\n"), logfile_name); } /* logfile is broken, force a write to stderr */ if (eek) { fprintf(stderr, _("%s: could not write to logfile \"%s\".\n"), progname, logfile_name); fprintf(stderr, _("Aborting XFS copy -- logfile error -- reason: %s\n"), strerror(errno)); pthread_exit(NULL); } } #define do_out(args...) do_message(OUT|LOG, 0, ## args) #define do_log(args...) do_message(ERR|LOG, 0, ## args) #define do_warn(args...) do_message(LOG, 0, ## args) #define do_error(e,s) do_message(ERR|LOG|PRE, e, s) #define do_fatal(e,s) do_message(ERR|LOG|PRE|LAST, e, s) #define do_vfatal(e,s,args...) do_message(ERR|LOG|PRE|LAST, e, s, ## args) #define die_perror() \ do { \ do_message(ERR|LOG|PRE|LAST, errno, \ _("Aborting XFS copy - reason")); \ exit(1); \ } while (0) /* workaround craziness in the xlog routines */ int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p) { return 0; } static void check_errors(void) { int i, first_error = 0; for (i = 0; i < num_targets; i++) { if (target[i].state == INACTIVE) { if (first_error == 0) { first_error++; do_log( _("THE FOLLOWING COPIES FAILED TO COMPLETE\n")); } do_log(" %s -- ", target[i].name); if (target[i].err_type == 0) do_log(_("write error")); else do_log(_("lseek error")); do_log(_(" at offset %lld\n"), target[i].position); } } if (first_error == 0) { fprintf(stdout, _("All copies completed.\n")); fflush(NULL); } else { fprintf(stderr, _("See \"%s\" for more details.\n"), logfile_name); exit(1); } } /* * don't have to worry about alignment and mins because those * are taken care of when the buffer's read in */ static int do_write( thread_args *args, wbuf *buf) { int res; int error = 0; if (!buf) buf = &w_buf; if (target[args->id].position != buf->position) { if (lseek(args->fd, buf->position, SEEK_SET) < 0) { error = target[args->id].err_type = 1; } else { target[args->id].position = buf->position; } } if ((res = write(target[args->id].fd, buf->data, buf->length)) == buf->length) { target[args->id].position += res; } else { error = 2; } if (error) { target[args->id].error = errno; target[args->id].position = buf->position; } return error; } static void * begin_reader(void *arg) { thread_args *args = arg; for (;;) { pthread_mutex_lock(&args->wait); if (do_write(args, NULL)) goto handle_error; pthread_mutex_lock(&glob_masks.mutex); if (--glob_masks.num_working == 0) pthread_mutex_unlock(&mainwait); pthread_mutex_unlock(&glob_masks.mutex); } /* NOTREACHED */ handle_error: /* error will be logged by primary thread */ pthread_mutex_lock(&glob_masks.mutex); target[args->id].state = INACTIVE; if (--glob_masks.num_working == 0) pthread_mutex_unlock(&mainwait); pthread_mutex_unlock(&glob_masks.mutex); pthread_exit(NULL); return NULL; } static void handler(int sig) { pid_t pid; int status, i; pid = wait(&status); kids--; for (i = 0; i < num_targets; i++) { if (target[i].pid == pid) { if (target[i].state == INACTIVE) { /* thread got an I/O error */ if (target[i].err_type == 0) { do_warn( _("%s: write error on target %d \"%s\" at offset %lld\n"), progname, i, target[i].name, target[i].position); } else { do_warn( _("%s: lseek error on target %d \"%s\" at offset %lld\n"), progname, i, target[i].name, target[i].position); } do_vfatal(target[i].error, _("Aborting target %d - reason"), i); if (kids == 0) { do_log( _("Aborting XFS copy - no more targets.\n")); check_errors(); pthread_exit(NULL); } signal(SIGCHLD, handler); return; } else { /* it just croaked it bigtime, log it */ do_warn( _("%s: thread %d died unexpectedly, target \"%s\" incomplete\n"), progname, i, target[i].name); do_warn(_("%s: offset was probably %lld\n"), progname, target[i].position); do_fatal(target[i].error, _("Aborting XFS copy - reason")); pthread_exit(NULL); } } } /* unknown child -- something very wrong */ do_warn(_("%s: Unknown child died (should never happen!)\n"), progname); die_perror(); pthread_exit(NULL); signal(SIGCHLD, handler); } static void usage(void) { fprintf(stderr, _("Usage: %s [-bdV] [-L logfile] source target [target ...]\n"), progname); exit(1); } static void init_bar(uint64_t source_blocks) { int i; for (i = 0; i < 11; i++) barcount[i] = (source_blocks/10)*i; } static int bump_bar(int tenths, uint64_t numblocks) { static char *bar[11] = { " 0% ", " ... 10% ", " ... 20% ", " ... 30% ", " ... 40% ", " ... 50% ", " ... 60% ", " ... 70% ", " ... 80% ", " ... 90% ", " ... 100%\n\n", }; if (tenths > 10) { printf("%s", bar[10]); fflush(stdout); } else { while (tenths < 10 && numblocks > barcount[tenths]) { printf("%s", bar[tenths]); fflush(stdout); tenths++; } } return tenths; } static xfs_off_t source_position = -1; static wbuf * wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id) { ASSERT(data_size % BBSIZE == 0); while ((buf->data = memalign(data_align, data_size)) == NULL) { data_size >>= 1; if (data_size < min_io_size) return NULL; } ASSERT(min_io_size % BBSIZE == 0); buf->data_align = data_align; buf->min_io_size = min_io_size; buf->size = data_size; buf->id = id; return buf; } static void read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp) { int res = 0; xfs_off_t lres = 0; xfs_off_t newpos; size_t diff; newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size); if (newpos != buf->position) { diff = buf->position - newpos; buf->position = newpos; buf->length += diff; } if (source_position != buf->position) { lres = lseek(fd, buf->position, SEEK_SET); if (lres < 0LL) { do_warn(_("%s: lseek failure at offset %lld\n"), progname, source_position); die_perror(); } source_position = buf->position; } ASSERT(source_position % source_sectorsize == 0); /* round up length for direct I/O if necessary */ if (buf->length % buf->min_io_size != 0) buf->length = roundup(buf->length, buf->min_io_size); if (buf->length > buf->size) { do_warn(_("assert error: buf->length = %d, buf->size = %d\n"), buf->length, buf->size); exit(1); } if ((res = read(fd, buf->data, buf->length)) < 0) { do_warn(_("%s: read failure at offset %lld\n"), progname, source_position); die_perror(); } if (res < buf->length && source_position + res == mp->m_sb.sb_dblocks * source_blocksize) res = buf->length; else ASSERT(res == buf->length); source_position += res; buf->length = res; } static void read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag, xfs_mount_t *mp, int blocksize, int sectorsize) { xfs_daddr_t off; int length; xfs_off_t newpos; size_t diff; /* initial settings */ diff = 0; off = XFS_AG_DADDR(mp, agno, XFS_SB_DADDR); buf->position = (xfs_off_t) off * (xfs_off_t) BBSIZE; length = buf->length = first_agbno * blocksize; if (length == 0) { do_log(_("ag header buffer invalid!\n")); exit(1); } /* handle alignment stuff */ newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size); if (newpos != buf->position) { diff = buf->position - newpos; buf->position = newpos; buf->length += diff; } /* round up length for direct I/O if necessary */ if (buf->length % buf->min_io_size != 0) buf->length = roundup(buf->length, buf->min_io_size); read_wbuf(fd, buf, mp); ASSERT(buf->length >= length); ag->xfs_sb = (xfs_dsb_t *) (buf->data + diff); ASSERT(be32_to_cpu(ag->xfs_sb->sb_magicnum) == XFS_SB_MAGIC); ag->xfs_agf = (xfs_agf_t *) (buf->data + diff + sectorsize); ASSERT(be32_to_cpu(ag->xfs_agf->agf_magicnum) == XFS_AGF_MAGIC); ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2 * sectorsize); ASSERT(be32_to_cpu(ag->xfs_agi->agi_magicnum) == XFS_AGI_MAGIC); ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3 * sectorsize); } static void write_wbuf(void) { int i; int badness = 0; /* verify target threads */ for (i = 0; i < num_targets; i++) if (target[i].state != INACTIVE) glob_masks.num_working++; /* release target threads */ for (i = 0; i < num_targets; i++) if (target[i].state != INACTIVE) pthread_mutex_unlock(&targ[i].wait); /* wake up */ else badness++; /* * If all the targets are inactive then there won't be any io * threads left to release mainwait. We're screwed, so bail out. */ if (badness == num_targets) { check_errors(); exit(1); } signal_maskfunc(SIGCHLD, SIG_UNBLOCK); pthread_mutex_lock(&mainwait); signal_maskfunc(SIGCHLD, SIG_BLOCK); } static void sb_update_uuid( xfs_sb_t *sb, /* Original fs superblock */ ag_header_t *ag_hdr, /* AG hdr to update for this copy */ thread_args *tcarg) /* Args for this thread, with UUID */ { /* * If this filesystem has CRCs, the original UUID is stamped into * all metadata. If we don't have an existing meta_uuid field in the * the original filesystem and we are changing the UUID in this copy, * we must copy the original sb_uuid to the sb_meta_uuid slot and set * the incompat flag for the feature on this copy. */ if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb) && !uuid_equal(&tcarg->uuid, &sb->sb_uuid)) { uint32_t feat; feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat); feat |= XFS_SB_FEAT_INCOMPAT_META_UUID; ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat); platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid, &sb->sb_uuid); } /* Copy the (possibly new) fs-identifier UUID into sb_uuid */ platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid); /* We may have changed the UUID, so update the superblock CRC */ if (xfs_sb_version_hascrc(sb)) xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize, XFS_SB_CRC_OFF); } int main(int argc, char **argv) { int i, j; int logfd; int howfar = 0; int open_flags; xfs_off_t pos; size_t length; int c; uint64_t size, sizeb; uint64_t numblocks = 0; int wblocks = 0; int num_threads = 0; struct dioattr d; int wbuf_size; int wbuf_align; int wbuf_miniosize; int source_is_file = 0; int buffered_output = 0; int duplicate = 0; uint btree_levels, current_level; ag_header_t ag_hdr; xfs_mount_t *mp; xfs_mount_t mbuf; struct xlog xlog; xfs_buf_t *sbp; xfs_sb_t *sb; xfs_agnumber_t num_ags, agno; xfs_agblock_t bno; xfs_daddr_t begin, next_begin, ag_begin, new_begin, ag_end; struct xfs_btree_block *block; xfs_alloc_ptr_t *ptr; xfs_alloc_rec_t *rec_ptr; extern char *optarg; extern int optind; libxfs_init_t xargs; thread_args *tcarg; struct stat statbuf; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); while ((c = getopt(argc, argv, "bdL:V")) != EOF) { switch (c) { case 'b': buffered_output = 1; break; case 'd': duplicate = 1; break; case 'L': logfile_name = optarg; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); case '?': usage(); } } if (argc - optind < 2) usage(); if (logfile_name) { logfd = open(logfile_name, O_CREAT|O_WRONLY|O_EXCL, 0600); } else { logfile_name = LOGFILE_NAME; logfd = mkstemp(logfile_name); } if (logfd < 0) { fprintf(stderr, _("%s: couldn't open log file \"%s\"\n"), progname, logfile_name); perror(_("Aborting XFS copy - reason")); exit(1); } if ((logerr = fdopen(logfd, "w")) == NULL) { fprintf(stderr, _("%s: couldn't set up logfile stream\n"), progname); perror(_("Aborting XFS copy - reason")); exit(1); } source_name = argv[optind]; source_fd = -1; optind++; num_targets = argc - optind; if ((target = malloc(sizeof(target_control) * num_targets)) == NULL) { do_log(_("Couldn't allocate target array\n")); die_perror(); } for (i = 0; optind < argc; i++, optind++) { target[i].name = argv[optind]; target[i].fd = -1; target[i].position = -1; target[i].state = INACTIVE; target[i].error = 0; target[i].err_type = 0; } /* open up source -- is it a file? */ open_flags = O_RDONLY; if ((source_fd = open(source_name, open_flags)) < 0) { do_log(_("%s: couldn't open source \"%s\"\n"), progname, source_name); die_perror(); } if (fstat(source_fd, &statbuf) < 0) { do_log(_("%s: couldn't stat source \"%s\"\n"), progname, source_name); die_perror(); } if (S_ISREG(statbuf.st_mode)) source_is_file = 1; if (source_is_file && platform_test_xfs_fd(source_fd)) { if (fcntl(source_fd, F_SETFL, open_flags | O_DIRECT) < 0) { do_log(_("%s: Cannot set direct I/O flag on \"%s\".\n"), progname, source_name); die_perror(); } if (xfsctl(source_name, source_fd, XFS_IOC_DIOINFO, &d) < 0) { do_log(_("%s: xfsctl on file \"%s\" failed.\n"), progname, source_name); die_perror(); } wbuf_align = d.d_mem; wbuf_size = min(d.d_maxiosz, 1 * 1024 * 1024); wbuf_miniosize = d.d_miniosz; } else { /* set arbitrary I/O params, miniosize at least 1 disk block */ wbuf_align = getpagesize(); wbuf_size = 1 * 1024 * 1024; wbuf_miniosize = -1; /* set after mounting source fs */ } if (!source_is_file) { /* * check to make sure a filesystem isn't mounted * on the device */ if (platform_check_ismounted(source_name, NULL, &statbuf, 0)) { do_log( _("%s: Warning -- a filesystem is mounted on the source device.\n"), progname); do_log( _("\t\tGenerated copies may be corrupt unless the source is\n")); do_log( _("\t\tunmounted or mounted read-only. Copy proceeding...\n")); } } /* prepare the libxfs_init structure */ memset(&xargs, 0, sizeof(xargs)); xargs.isdirect = LIBXFS_DIRECT; xargs.isreadonly = LIBXFS_ISREADONLY; if (source_is_file) { xargs.dname = source_name; xargs.disfile = 1; } else xargs.volname = source_name; if (!libxfs_init(&xargs)) { do_log(_("%s: couldn't initialize XFS library\n" "%s: Aborting.\n"), progname, progname); exit(1); } memset(&mbuf, 0, sizeof(xfs_mount_t)); /* We don't yet know the sector size, so read maximal size */ libxfs_buftarg_init(&mbuf, xargs.ddev, xargs.logdev, xargs.rtdev); sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR, 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL); sb = &mbuf.m_sb; libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp)); /* Do it again, now with proper length and verifier */ libxfs_putbuf(sbp); libxfs_purgebuf(sbp); sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR, 1 << (sb->sb_sectlog - BBSHIFT), 0, &xfs_sb_buf_ops); libxfs_putbuf(sbp); mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0); if (mp == NULL) { do_log(_("%s: %s filesystem failed to initialize\n" "%s: Aborting.\n"), progname, source_name, progname); exit(1); } else if (mp->m_sb.sb_inprogress) { do_log(_("%s %s filesystem failed to initialize\n" "%s: Aborting.\n"), progname, source_name, progname); exit(1); } else if (mp->m_sb.sb_logstart == 0) { do_log(_("%s: %s has an external log.\n%s: Aborting.\n"), progname, source_name, progname); exit(1); } else if (mp->m_sb.sb_rextents != 0) { do_log(_("%s: %s has a real-time section.\n" "%s: Aborting.\n"), progname, source_name, progname); exit(1); } /* * Set up the mount pointer to access the log and check whether the log * is clean. Fail on a dirty or corrupt log in non-duplicate mode * because the log is formatted as part of the copy and we don't want to * destroy data. We also need the current log cycle to format v5 * superblock logs correctly. */ memset(&xlog, 0, sizeof(struct xlog)); mp->m_log = &xlog; c = xlog_is_dirty(mp, mp->m_log, &xargs, 0); if (!duplicate) { if (c == 1) { do_log(_( "Error: source filesystem log is dirty. Mount the filesystem to replay the\n" "log, unmount and retry xfs_copy.\n")); exit(1); } else if (c < 0) { do_log(_( "Error: could not determine the log head or tail of the source filesystem.\n" "Mount the filesystem to replay the log or run xfs_repair.\n")); exit(1); } } source_blocksize = mp->m_sb.sb_blocksize; source_sectorsize = mp->m_sb.sb_sectsize; if (wbuf_miniosize == -1) wbuf_miniosize = source_sectorsize; ASSERT(source_blocksize % source_sectorsize == 0); ASSERT(source_sectorsize % BBSIZE == 0); if (source_blocksize < source_sectorsize) { do_log(_("Error: filesystem block size is smaller than the" " disk sectorsize.\nAborting XFS copy now.\n")); exit(1); } first_agbno = XFS_AGFL_BLOCK(mp) + 1; /* now open targets */ open_flags = O_RDWR; for (i = 0; i < num_targets; i++) { int write_last_block = 0; if (stat(target[i].name, &statbuf) < 0) { /* ok, assume it's a file and create it */ do_out(_("Creating file %s\n"), target[i].name); open_flags |= O_CREAT; if (!buffered_output) open_flags |= O_DIRECT; write_last_block = 1; } else if (S_ISREG(statbuf.st_mode)) { open_flags |= O_TRUNC; if (!buffered_output) open_flags |= O_DIRECT; write_last_block = 1; } else { /* * check to make sure a filesystem isn't mounted * on the device */ if (platform_check_ismounted(target[i].name, NULL, &statbuf, 0)) { do_log(_("%s: a filesystem is mounted " "on target device \"%s\".\n" "%s cannot copy to mounted filesystems." " Aborting\n"), progname, target[i].name, progname); exit(1); } } target[i].fd = open(target[i].name, open_flags, 0644); if (target[i].fd < 0) { do_log(_("%s: couldn't open target \"%s\"\n"), progname, target[i].name); die_perror(); } if (write_last_block) { /* ensure regular files are correctly sized */ if (ftruncate(target[i].fd, mp->m_sb.sb_dblocks * source_blocksize)) { do_log(_("%s: cannot grow data section.\n"), progname); die_perror(); } if (platform_test_xfs_fd(target[i].fd)) { if (xfsctl(target[i].name, target[i].fd, XFS_IOC_DIOINFO, &d) < 0) { do_log( _("%s: xfsctl on \"%s\" failed.\n"), progname, target[i].name); die_perror(); } else { wbuf_align = max(wbuf_align, d.d_mem); wbuf_size = min(d.d_maxiosz, wbuf_size); wbuf_miniosize = max(d.d_miniosz, wbuf_miniosize); } } } else { char *lb[XFS_MAX_SECTORSIZE] = { NULL }; off64_t off; /* ensure device files are sufficiently large */ off = mp->m_sb.sb_dblocks * source_blocksize; off -= sizeof(lb); if (pwrite(target[i].fd, lb, sizeof(lb), off) < 0) { do_log(_("%s: failed to write last block\n"), progname); do_log(_("\tIs target \"%s\" too small?\n"), target[i].name); die_perror(); } } } /* initialize locks and bufs */ if (pthread_mutex_init(&glob_masks.mutex, NULL) != 0) { do_log(_("Couldn't initialize global thread mask\n")); die_perror(); } glob_masks.num_working = 0; if (wbuf_init(&w_buf, wbuf_size, wbuf_align, wbuf_miniosize, 0) == NULL) { do_log(_("Error initializing wbuf 0\n")); die_perror(); } wblocks = wbuf_size / BBSIZE; if (wbuf_init(&btree_buf, max(source_blocksize, wbuf_miniosize), wbuf_align, wbuf_miniosize, 1) == NULL) { do_log(_("Error initializing btree buf 1\n")); die_perror(); } if (pthread_mutex_init(&mainwait,NULL) != 0) { do_log(_("Error creating first semaphore.\n")); die_perror(); exit(1); } /* need to start out blocking */ pthread_mutex_lock(&mainwait); /* set up sigchild signal handler */ signal(SIGCHLD, handler); signal_maskfunc(SIGCHLD, SIG_BLOCK); /* make children */ if ((targ = malloc(num_targets * sizeof(thread_args))) == NULL) { do_log(_("Couldn't malloc space for thread args\n")); die_perror(); exit(1); } for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) { if (!duplicate) platform_uuid_generate(&tcarg->uuid); else platform_uuid_copy(&tcarg->uuid, &mp->m_sb.sb_uuid); if (pthread_mutex_init(&tcarg->wait, NULL) != 0) { do_log(_("Error creating thread mutex %d\n"), i); die_perror(); exit(1); } /* need to start out blocking */ pthread_mutex_lock(&tcarg->wait); } for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) { tcarg->id = i; tcarg->fd = target[i].fd; target[i].state = ACTIVE; num_threads++; if (pthread_create(&target[i].pid, NULL, begin_reader, (void *)tcarg)) { do_log(_("Error creating thread for target %d\n"), i); die_perror(); } } ASSERT(num_targets == num_threads); /* set up statistics */ num_ags = mp->m_sb.sb_agcount; init_bar(mp->m_sb.sb_blocksize / BBSIZE * ((uint64_t)mp->m_sb.sb_dblocks - (uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags)); kids = num_targets; for (agno = 0; agno < num_ags && kids > 0; agno++) { /* read in first blocks of the ag */ read_ag_header(source_fd, agno, &w_buf, &ag_hdr, mp, source_blocksize, source_sectorsize); /* set the in_progress bit for the first AG */ if (agno == 0) ag_hdr.xfs_sb->sb_inprogress = 1; /* save what we need (agf) in the btree buffer */ memmove(btree_buf.data, ag_hdr.xfs_agf, source_sectorsize); ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data; btree_buf.length = source_blocksize; /* write the ag header out */ write_wbuf(); /* traverse btree until we get to the leftmost leaf node */ bno = be32_to_cpu(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]); current_level = 0; btree_levels = be32_to_cpu(ag_hdr.xfs_agf-> agf_levels[XFS_BTNUM_BNOi]); ag_end = XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(ag_hdr.xfs_agf->agf_length) - 1) + source_blocksize / BBSIZE; for (;;) { /* none of this touches the w_buf buffer */ if (current_level >= btree_levels) { do_log( _("Error: current level %d >= btree levels %d\n"), current_level, btree_levels); exit(1); } current_level++; btree_buf.position = pos = (xfs_off_t) XFS_AGB_TO_DADDR(mp,agno,bno) << BBSHIFT; btree_buf.length = source_blocksize; read_wbuf(source_fd, &btree_buf, mp); block = (struct xfs_btree_block *) ((char *)btree_buf.data + pos - btree_buf.position); if (be32_to_cpu(block->bb_magic) != (xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) { do_log(_("Bad btree magic 0x%x\n"), be32_to_cpu(block->bb_magic)); exit(1); } if (be16_to_cpu(block->bb_level) == 0) break; ptr = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); bno = be32_to_cpu(ptr[0]); } /* align first data copy but don't overwrite ag header */ pos = w_buf.position >> BBSHIFT; length = w_buf.length >> BBSHIFT; next_begin = pos + length; ag_begin = next_begin; ASSERT(w_buf.position % source_sectorsize == 0); /* handle the rest of the ag */ for (;;) { if (be16_to_cpu(block->bb_level) != 0) { do_log( _("WARNING: source filesystem inconsistent.\n")); do_log( _(" A leaf btree rec isn't a leaf. Aborting now.\n")); exit(1); } rec_ptr = XFS_ALLOC_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++, rec_ptr++) { /* calculate in daddr's */ begin = next_begin; /* * protect against pathological case of a * hole right after the ag header in a * mis-aligned case */ if (begin < ag_begin) begin = ag_begin; /* * round size up to ensure we copy a * range bigger than required */ sizeb = XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(rec_ptr->ar_startblock)) - begin; size = roundup(sizeb < 0) { /* copy extent */ w_buf.position = (xfs_off_t) begin << BBSHIFT; while (size > 0) { /* * let lower layer do alignment */ if (size > w_buf.size) { w_buf.length = w_buf.size; size -= w_buf.size; sizeb -= wblocks; numblocks += wblocks; } else { w_buf.length = size; numblocks += sizeb; size = 0; } read_wbuf(source_fd, &w_buf, mp); write_wbuf(); w_buf.position += w_buf.length; howfar = bump_bar( howfar, numblocks); } } /* round next starting point down */ new_begin = XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(rec_ptr->ar_startblock) + be32_to_cpu(rec_ptr->ar_blockcount)); next_begin = rounddown(new_begin, w_buf.min_io_size >> BBSHIFT); } if (be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK) break; /* read in next btree record block */ btree_buf.position = pos = (xfs_off_t) XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu( block->bb_u.s.bb_rightsib)) << BBSHIFT; btree_buf.length = source_blocksize; /* let read_wbuf handle alignment */ read_wbuf(source_fd, &btree_buf, mp); block = (struct xfs_btree_block *) ((char *) btree_buf.data + pos - btree_buf.position); ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC || be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC); } /* * write out range of used blocks after last range * of free blocks in AG */ if (next_begin < ag_end) { begin = next_begin; sizeb = ag_end - begin; size = roundup(sizeb << BBSHIFT, wbuf_miniosize); if (size > 0) { /* copy extent */ w_buf.position = (xfs_off_t) begin << BBSHIFT; while (size > 0) { /* * let lower layer do alignment */ if (size > w_buf.size) { w_buf.length = w_buf.size; size -= w_buf.size; sizeb -= wblocks; numblocks += wblocks; } else { w_buf.length = size; numblocks += sizeb; size = 0; } read_wbuf(source_fd, &w_buf, mp); write_wbuf(); w_buf.position += w_buf.length; howfar = bump_bar(howfar, numblocks); } } } } if (kids > 0) { if (!duplicate) /* write a clean log using the specified UUID */ format_logs(mp); else num_ags = 1; /* reread and rewrite superblocks (UUID and in-progress) */ /* [backwards, so inprogress bit only updated when done] */ for (i = num_ags - 1; i >= 0; i--) { read_ag_header(source_fd, i, &w_buf, &ag_hdr, mp, source_blocksize, source_sectorsize); if (i == 0) ag_hdr.xfs_sb->sb_inprogress = 0; /* do each thread in turn, each has its own UUID */ for (j = 0, tcarg = targ; j < num_targets; j++) { sb_update_uuid(sb, &ag_hdr, tcarg); do_write(tcarg, NULL); tcarg++; } } bump_bar(100, 0); } check_errors(); libxfs_umount(mp); libxfs_destroy(); return 0; } static char * next_log_chunk(char *p, int offset, void *private) { wbuf *buf = (wbuf *)private; if (buf->length < (int)(p - buf->data) + offset) { /* need to flush this one, then start afresh */ do_write(buf->owner, NULL); memset(buf->data, 0, buf->length); return buf->data; } return p + offset; } /* * Writes a log header at the start of the log (with the real * filesystem UUID embedded into it), and writes to all targets. * * Returns the next buffer-length-aligned disk address. */ xfs_off_t write_log_header(int fd, wbuf *buf, xfs_mount_t *mp) { char *p = buf->data; xfs_off_t logstart; int offset; logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT; buf->position = rounddown(logstart, (xfs_off_t)buf->length); memset(p, 0, buf->size); if (logstart % buf->length) { /* unaligned */ read_wbuf(fd, buf, mp); offset = logstart - buf->position; p += offset; memset(p, 0, buf->length - offset); } offset = libxfs_log_header(p, &buf->owner->uuid, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN, NULLCOMMITLSN, next_log_chunk, buf); do_write(buf->owner, NULL); return roundup(logstart + offset, buf->length); } /* * May do an aligned read of the last buffer in the log (& zero * the start of that buffer). Returns the disk address at the * end of last aligned buffer in the log. */ xfs_off_t write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp) { xfs_off_t logend; int offset; logend = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT; logend += XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks); buf->position = rounddown(logend, (xfs_off_t)buf->length); if (logend % buf->length) { /* unaligned */ read_wbuf(fd, buf, mp); offset = (int)(logend - buf->position); memset(buf->data, 0, offset); do_write(buf->owner, NULL); } return buf->position; } /* * Clear a log by writing a record at the head, the tail and zeroing everything * in between. */ static void clear_log( struct xfs_mount *mp, thread_args *tcarg) { xfs_off_t pos; xfs_off_t end_pos; w_buf.owner = tcarg; w_buf.length = rounddown(w_buf.size, w_buf.min_io_size); pos = write_log_header(source_fd, &w_buf, mp); end_pos = write_log_trailer(source_fd, &w_buf, mp); w_buf.position = pos; memset(w_buf.data, 0, w_buf.length); while (w_buf.position < end_pos) { do_write(tcarg, NULL); w_buf.position += w_buf.length; } } /* * Format the log to a particular cycle number. This is required for version 5 * superblock filesystems to provide metadata LSN validity guarantees. */ static void format_log( struct xfs_mount *mp, thread_args *tcarg, wbuf *buf) { int logstart; int length; int cycle = XLOG_INIT_CYCLE; buf->owner = tcarg; buf->length = buf->size; buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT; logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart); length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); /* * Bump the cycle number on v5 superblock filesystems to guarantee that * all existing metadata LSNs are valid (behind the current LSN) on the * target fs. */ if (xfs_sb_version_hascrc(&mp->m_sb)) cycle = mp->m_log->l_curr_cycle + 1; /* * Format the entire log into the memory buffer and write it out. If the * write fails, mark the target inactive so the failure is reported. */ libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true); if (do_write(buf->owner, buf)) target[tcarg->id].state = INACTIVE; } static int format_logs( struct xfs_mount *mp) { thread_args *tcarg; int i; wbuf logbuf; int logsize; if (xfs_sb_version_hascrc(&mp->m_sb)) { logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks); if (!wbuf_init(&logbuf, logsize, w_buf.data_align, w_buf.min_io_size, w_buf.id)) return -ENOMEM; } for (i = 0, tcarg = targ; i < num_targets; i++) { if (xfs_sb_version_hascrc(&mp->m_sb)) format_log(mp, tcarg, &logbuf); else clear_log(mp, tcarg); tcarg++; } if (xfs_sb_version_hascrc(&mp->m_sb)) free(logbuf.data); return 0; } xfsprogs-5.3.0/copy/xfs_copy.h0000644000175000017500000000456313435336036016237 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ /* * An on-disk allocation group header is composed of 4 structures, * each of which is 1 disk sector long where the sector size is at * least 512 bytes long (BBSIZE). * * There's one ag_header per ag and the superblock in the first ag * is the contains the real data for the entire filesystem (although * most of the relevant data won't change anyway even on a growfs). * * The filesystem superblock specifies the number of AG's and * the AG size. That splits the filesystem up into N pieces, * each of which is an AG and has an ag_header at the beginning. */ typedef struct ag_header { xfs_dsb_t *xfs_sb; /* superblock for filesystem or AG */ xfs_agf_t *xfs_agf; /* free space info */ xfs_agi_t *xfs_agi; /* free inode info */ xfs_agfl_t *xfs_agfl; /* AG freelist */ char *residue; int residue_length; } ag_header_t; /* * The position/buf_position, length/buf_length, data/buffer pairs * exist because of alignment constraints for direct I/O and dealing * with scenarios where either the source or target or both is a file * and the blocksize of the filesystem where file resides is different * from that of the filesystem image being duplicated. You can get * alignment problems resulting from things like AG's starting on * non-aligned points in the filesystem. So you have to be able * to read from points "before" the requested starting point and * read in more data than requested. */ struct t_args; typedef struct { int id; /* buffer ID */ size_t size; /* size of buffer -- fixed */ size_t min_io_size; /* for direct I/O */ int data_align; /* data buffer alignment */ xfs_off_t position; /* requested position (bytes) */ size_t length; /* requested length (bytes) */ char *data; /* pointer to data buffer */ struct t_args *owner; /* for non-parallel writes */ } wbuf; typedef struct t_args { int id; uuid_t uuid; pthread_mutex_t wait; int fd; } thread_args; typedef struct { pthread_mutex_t mutex; int num_working; wbuf *buffer; } thread_control; typedef int thread_id; typedef int tm_index; /* index into thread mask array */ typedef uint32_t thread_mask; /* a thread mask */ typedef struct { char *name; int fd; xfs_off_t position; pthread_t pid; int state; int error; int err_type; } target_control; xfsprogs-5.3.0/db/Makefile0000644000175000017500000000263013570057155015302 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_db HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ btblock.h bmroot.h check.h command.h crc.h debug.h \ dir2.h dir2sf.h dquot.h echo.h faddr.h field.h \ flist.h fprint.h frag.h freesp.h hash.h help.h init.h inode.h input.h \ io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \ sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \ fuzz.h CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG) $(LIBFROG) LLDFLAGS += -static-libtool-libs ifeq ($(ENABLE_READLINE),yes) LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP) CFLAGS += -DENABLE_READLINE endif ifeq ($(ENABLE_EDITLINE),yes) LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP) CFLAGS += -DENABLE_EDITLINE endif default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) $(INSTALL) -m 755 xfs_admin.sh $(PKG_SBIN_DIR)/xfs_admin $(INSTALL) -m 755 xfs_ncheck.sh $(PKG_SBIN_DIR)/xfs_ncheck $(INSTALL) -m 755 xfs_metadump.sh $(PKG_SBIN_DIR)/xfs_metadump install-dev: -include .dep xfsprogs-5.3.0/db/addr.c0000644000175000017500000000425413435336036014722 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "addr.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "io.h" #include "flist.h" #include "inode.h" #include "output.h" static int addr_f(int argc, char **argv); static void addr_help(void); static const cmdinfo_t addr_cmd = { "addr", "a", addr_f, 0, 1, 1, N_("[field-expression]"), N_("set current address"), addr_help }; static void addr_help(void) { dbprintf(_( "\n" " 'addr' uses the given field to set the filesystem address and type\n" "\n" " Examples:\n" "\n" " sb\n" " a rootino - set the type to inode and set position to the root inode\n" " a u.bmx[0].startblock (for inode with blockmap)\n" "\n" )); } static int addr_f( int argc, char **argv) { adfnc_t adf; const ftattr_t *fa; flist_t *fl; const field_t *fld; typnm_t next; flist_t *tfl; if (argc == 1) { print_iocur("current", iocur_top); return 0; } if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } fld = cur_typ->fields; if (fld != NULL && fld->name[0] == '\0') { fa = &ftattrtab[fld->ftyp]; ASSERT(fa->ftyp == fld->ftyp); fld = fa->subfld; } if (fld == NULL) { dbprintf(_("no fields for type %s\n"), cur_typ->name); return 0; } fl = flist_scan(argv[1]); if (fl == NULL) return 0; if (!flist_parse(fld, fl, iocur_top->data, 0)) goto out; flist_print(fl); for (tfl = fl; tfl->child != NULL; tfl = tfl->child) { if ((tfl->flags & FL_OKLOW) && tfl->low < tfl->high) { dbprintf(_("array not allowed for addr command\n")); goto out; } } fld = tfl->fld; next = fld->next; if (next == TYP_INODATA) next = inode_next_type(); if (next == TYP_NONE) { dbprintf(_("no next type for field %s\n"), fld->name); goto out; } fa = &ftattrtab[fld->ftyp]; ASSERT(fa->ftyp == fld->ftyp); adf = fa->adfunc; if (adf == NULL) { dbprintf(_("no addr function for field %s (type %s)\n"), fld->name, fa->name); goto out; } (*adf)(iocur_top->data, tfl->offset, next); out: flist_free(fl); return 0; } void addr_init(void) { add_command(&addr_cmd); } xfsprogs-5.3.0/db/addr.h0000644000175000017500000000023013435336036014715 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void addr_init(void); xfsprogs-5.3.0/db/agf.c0000644000175000017500000000753013435336036014545 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "io.h" #include "bit.h" #include "output.h" #include "init.h" #include "agf.h" static int agf_f(int argc, char **argv); static void agf_help(void); static const cmdinfo_t agf_cmd = { "agf", NULL, agf_f, 0, 1, 1, N_("[agno]"), N_("set address to agf header"), agf_help }; const field_t agf_hfld[] = { { "", FLDT_AGF, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(xfs_agf_t, agf_ ## f)) #define SZ(f) bitszof(xfs_agf_t, agf_ ## f) const field_t agf_flds[] = { { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, { "versionnum", FLDT_UINT32D, OI(OFF(versionnum)), C1, 0, TYP_NONE }, { "seqno", FLDT_AGNUMBER, OI(OFF(seqno)), C1, 0, TYP_NONE }, { "length", FLDT_AGBLOCK, OI(OFF(length)), C1, 0, TYP_NONE }, { "roots", FLDT_AGBLOCK, OI(OFF(roots)), CI(XFS_BTNUM_AGF), FLD_ARRAY|FLD_SKIPALL, TYP_NONE }, { "bnoroot", FLDT_AGBLOCK, OI(OFF(roots) + XFS_BTNUM_BNO * SZ(roots[XFS_BTNUM_BNO])), C1, 0, TYP_BNOBT }, { "cntroot", FLDT_AGBLOCK, OI(OFF(roots) + XFS_BTNUM_CNT * SZ(roots[XFS_BTNUM_CNT])), C1, 0, TYP_CNTBT }, { "rmaproot", FLDT_AGBLOCKNZ, OI(OFF(roots) + XFS_BTNUM_RMAP * SZ(roots[XFS_BTNUM_RMAP])), C1, 0, TYP_RMAPBT }, { "refcntroot", FLDT_AGBLOCKNZ, OI(OFF(refcount_root)), C1, 0, TYP_REFCBT }, { "levels", FLDT_UINT32D, OI(OFF(levels)), CI(XFS_BTNUM_AGF), FLD_ARRAY|FLD_SKIPALL, TYP_NONE }, { "bnolevel", FLDT_UINT32D, OI(OFF(levels) + XFS_BTNUM_BNO * SZ(levels[XFS_BTNUM_BNO])), C1, 0, TYP_NONE }, { "cntlevel", FLDT_UINT32D, OI(OFF(levels) + XFS_BTNUM_CNT * SZ(levels[XFS_BTNUM_CNT])), C1, 0, TYP_NONE }, { "rmaplevel", FLDT_UINT32D, OI(OFF(levels) + XFS_BTNUM_RMAP * SZ(levels[XFS_BTNUM_RMAP])), C1, 0, TYP_NONE }, { "refcntlevel", FLDT_UINT32D, OI(OFF(refcount_level)), C1, 0, TYP_NONE }, { "rmapblocks", FLDT_UINT32D, OI(OFF(rmap_blocks)), C1, 0, TYP_NONE }, { "refcntblocks", FLDT_UINT32D, OI(OFF(refcount_blocks)), C1, 0, TYP_NONE }, { "flfirst", FLDT_UINT32D, OI(OFF(flfirst)), C1, 0, TYP_NONE }, { "fllast", FLDT_UINT32D, OI(OFF(fllast)), C1, 0, TYP_NONE }, { "flcount", FLDT_UINT32D, OI(OFF(flcount)), C1, 0, TYP_NONE }, { "freeblks", FLDT_EXTLEN, OI(OFF(freeblks)), C1, 0, TYP_NONE }, { "longest", FLDT_EXTLEN, OI(OFF(longest)), C1, 0, TYP_NONE }, { "btreeblks", FLDT_UINT32D, OI(OFF(btreeblks)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, { NULL } }; static void agf_help(void) { dbprintf(_( "\n" " set allocation group free block list\n" "\n" " Example:\n" "\n" " agf 2 - move location to AGF in 2nd filesystem allocation group\n" "\n" " Located in the second sector of each allocation group, the AGF\n" " contains the root of two different freespace btrees:\n" " The 'cnt' btree keeps track freespace indexed on section size.\n" " The 'bno' btree tracks sections of freespace indexed on block number.\n" )); } static int agf_f( int argc, char **argv) { xfs_agnumber_t agno; char *p; if (argc > 1) { agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { dbprintf(_("bad allocation group number %s\n"), argv[1]); return 0; } cur_agno = agno; } else if (cur_agno == NULLAGNUMBER) cur_agno = 0; ASSERT(typtab[TYP_AGF].typnm == TYP_AGF); set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, cur_agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL); return 0; } void agf_init(void) { add_command(&agf_cmd); } int agf_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_sectsize); } xfsprogs-5.3.0/db/agf.h0000644000175000017500000000043313435336036014545 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field agf_flds[]; extern const struct field agf_hfld[]; extern void agf_init(void); extern int agf_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/agfl.c0000644000175000017500000000504413435336036014717 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "io.h" #include "bit.h" #include "output.h" #include "init.h" #include "agfl.h" static int agfl_bno_size(void *obj, int startoff); static int agfl_f(int argc, char **argv); static void agfl_help(void); static const cmdinfo_t agfl_cmd = { "agfl", NULL, agfl_f, 0, 1, 1, N_("[agno]"), N_("set address to agfl block"), agfl_help }; const field_t agfl_hfld[] = { { "", FLDT_AGFL, OI(0), C1, 0, TYP_NONE, }, { NULL } }; const field_t agfl_crc_hfld[] = { { "", FLDT_AGFL_CRC, OI(0), C1, 0, TYP_NONE, }, { NULL } }; #define OFF(f) bitize(offsetof(xfs_agfl_t, agfl_ ## f)) const field_t agfl_flds[] = { { "bno", FLDT_AGBLOCKNZ, OI(OFF(magicnum)), agfl_bno_size, FLD_ARRAY|FLD_COUNT, TYP_DATA }, { NULL } }; const field_t agfl_crc_flds[] = { { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, { "seqno", FLDT_AGNUMBER, OI(OFF(seqno)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, { "bno", FLDT_AGBLOCKNZ, OI(OFF(bno)), agfl_bno_size, FLD_ARRAY|FLD_COUNT, TYP_DATA }, { NULL } }; static int agfl_bno_size( void *obj, int startoff) { return libxfs_agfl_size(mp); } static void agfl_help(void) { dbprintf(_( "\n" " set allocation group freelist\n" "\n" " Example:\n" "\n" " agfl 5" "\n" " Located in the fourth sector of each allocation group,\n" " the agfl freelist for internal btree space allocation is maintained\n" " for each allocation group. This acts as a reserved pool of space\n" " separate from the general filesystem freespace (not used for user data).\n" "\n" )); } static int agfl_f( int argc, char **argv) { xfs_agnumber_t agno; char *p; if (argc > 1) { agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { dbprintf(_("bad allocation group number %s\n"), argv[1]); return 0; } cur_agno = agno; } else if (cur_agno == NULLAGNUMBER) cur_agno = 0; ASSERT(typtab[TYP_AGFL].typnm == TYP_AGFL); set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, cur_agno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL); return 0; } void agfl_init(void) { add_command(&agfl_cmd); } /*ARGSUSED*/ int agfl_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_sectsize); } xfsprogs-5.3.0/db/agfl.h0000644000175000017500000000056513435336036014727 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field agfl_flds[]; extern const struct field agfl_hfld[]; extern const struct field agfl_crc_flds[]; extern const struct field agfl_crc_hfld[]; extern void agfl_init(void); extern int agfl_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/agi.c0000644000175000017500000000557013435336036014552 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "io.h" #include "bit.h" #include "output.h" #include "init.h" #include "agi.h" static int agi_f(int argc, char **argv); static void agi_help(void); static const cmdinfo_t agi_cmd = { "agi", NULL, agi_f, 0, 1, 1, N_("[agno]"), N_("set address to agi header"), agi_help }; const field_t agi_hfld[] = { { "", FLDT_AGI, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(xfs_agi_t, agi_ ## f)) const field_t agi_flds[] = { { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, { "versionnum", FLDT_UINT32D, OI(OFF(versionnum)), C1, 0, TYP_NONE }, { "seqno", FLDT_AGNUMBER, OI(OFF(seqno)), C1, 0, TYP_NONE }, { "length", FLDT_AGBLOCK, OI(OFF(length)), C1, 0, TYP_NONE }, { "count", FLDT_AGINO, OI(OFF(count)), C1, 0, TYP_NONE }, { "root", FLDT_AGBLOCK, OI(OFF(root)), C1, 0, TYP_INOBT }, { "level", FLDT_UINT32D, OI(OFF(level)), C1, 0, TYP_NONE }, { "freecount", FLDT_AGINO, OI(OFF(freecount)), C1, 0, TYP_NONE }, { "newino", FLDT_AGINO, OI(OFF(newino)), C1, 0, TYP_INODE }, { "dirino", FLDT_AGINO, OI(OFF(dirino)), C1, 0, TYP_INODE }, { "unlinked", FLDT_AGINONN, OI(OFF(unlinked)), CI(XFS_AGI_UNLINKED_BUCKETS), FLD_ARRAY, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, { "pad32", FLDT_UINT32X, OI(OFF(pad32)), C1, FLD_SKIPALL, TYP_NONE }, { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, { "free_root", FLDT_AGBLOCK, OI(OFF(free_root)), C1, 0, TYP_FINOBT }, { "free_level", FLDT_UINT32D, OI(OFF(free_level)), C1, 0, TYP_NONE }, { NULL } }; static void agi_help(void) { dbprintf(_( "\n" " set allocation group inode btree\n" "\n" " Example:\n" "\n" " agi 3 (set location to 3rd allocation group inode btree and type to 'agi')\n" "\n" " Located in the 3rd 512 byte block of each allocation group,\n" " the agi inode btree tracks all used/free inodes in the allocation group.\n" " Inodes are allocated in 16k 'chunks', each btree entry tracks a 'chunk'.\n" "\n" )); } static int agi_f( int argc, char **argv) { xfs_agnumber_t agno; char *p; if (argc > 1) { agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { dbprintf(_("bad allocation group number %s\n"), argv[1]); return 0; } cur_agno = agno; } else if (cur_agno == NULLAGNUMBER) cur_agno = 0; ASSERT(typtab[TYP_AGI].typnm == TYP_AGI); set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, cur_agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL); return 0; } void agi_init(void) { add_command(&agi_cmd); } /*ARGSUSED*/ int agi_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_sectsize); } xfsprogs-5.3.0/db/agi.h0000644000175000017500000000043313435336036014550 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field agi_flds[]; extern const struct field agi_hfld[]; extern void agi_init(void); extern int agi_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/attr.c0000644000175000017500000004364413435336036014770 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "bit.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "attr.h" #include "io.h" #include "init.h" #include "output.h" static int attr_leaf_entries_count(void *obj, int startoff); static int attr_leaf_hdr_count(void *obj, int startoff); static int attr_leaf_name_local_count(void *obj, int startoff); static int attr_leaf_name_local_name_count(void *obj, int startoff); static int attr_leaf_name_local_value_count(void *obj, int startoff); static int attr_leaf_name_local_value_offset(void *obj, int startoff, int idx); static int attr_leaf_name_remote_count(void *obj, int startoff); static int attr_leaf_name_remote_name_count(void *obj, int startoff); static int attr_leaf_nvlist_count(void *obj, int startoff); static int attr_leaf_nvlist_offset(void *obj, int startoff, int idx); static int attr_node_btree_count(void *obj, int startoff); static int attr_node_hdr_count(void *obj, int startoff); static int attr_remote_data_count(void *obj, int startoff); static int attr3_remote_hdr_count(void *obj, int startoff); static int attr3_remote_data_count(void *obj, int startoff); const field_t attr_hfld[] = { { "", FLDT_ATTR, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define LOFF(f) bitize(offsetof(xfs_attr_leafblock_t, f)) #define NOFF(f) bitize(offsetof(xfs_da_intnode_t, f)) const field_t attr_flds[] = { { "hdr", FLDT_ATTR_LEAF_HDR, OI(LOFF(hdr)), attr_leaf_hdr_count, FLD_COUNT, TYP_NONE }, { "hdr", FLDT_ATTR_NODE_HDR, OI(NOFF(hdr)), attr_node_hdr_count, FLD_COUNT, TYP_NONE }, { "data", FLDT_CHARNS, OI(0), attr_remote_data_count, FLD_COUNT, TYP_NONE }, { "entries", FLDT_ATTR_LEAF_ENTRY, OI(LOFF(entries)), attr_leaf_entries_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "btree", FLDT_ATTR_NODE_ENTRY, OI(NOFF(__btree)), attr_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "nvlist", FLDT_ATTR_LEAF_NAME, attr_leaf_nvlist_offset, attr_leaf_nvlist_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { NULL } }; #define BOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f)) const field_t attr_blkinfo_flds[] = { { "forw", FLDT_ATTRBLOCK, OI(BOFF(forw)), C1, 0, TYP_ATTR }, { "back", FLDT_ATTRBLOCK, OI(BOFF(back)), C1, 0, TYP_ATTR }, { "magic", FLDT_UINT16X, OI(BOFF(magic)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT16X, OI(BOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define LEOFF(f) bitize(offsetof(xfs_attr_leaf_entry_t, f)) const field_t attr_leaf_entry_flds[] = { { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE }, { "nameidx", FLDT_UINT16D, OI(LEOFF(nameidx)), C1, 0, TYP_NONE }, { "flags", FLDT_UINT8X, OI(LEOFF(flags)), C1, FLD_SKIPALL, TYP_NONE }, { "incomplete", FLDT_UINT1, OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_INCOMPLETE_BIT - 1), C1, 0, TYP_NONE }, { "root", FLDT_UINT1, OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_ROOT_BIT - 1), C1, 0, TYP_NONE }, { "secure", FLDT_UINT1, OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_SECURE_BIT - 1), C1, 0, TYP_NONE }, { "local", FLDT_UINT1, OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_LOCAL_BIT - 1), C1, 0, TYP_NONE }, { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define LHOFF(f) bitize(offsetof(xfs_attr_leaf_hdr_t, f)) const field_t attr_leaf_hdr_flds[] = { { "info", FLDT_ATTR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, { "usedbytes", FLDT_UINT16D, OI(LHOFF(usedbytes)), C1, 0, TYP_NONE }, { "firstused", FLDT_UINT16D, OI(LHOFF(firstused)), C1, 0, TYP_NONE }, { "holes", FLDT_UINT8D, OI(LHOFF(holes)), C1, 0, TYP_NONE }, { "pad1", FLDT_UINT8X, OI(LHOFF(pad1)), C1, FLD_SKIPALL, TYP_NONE }, { "freemap", FLDT_ATTR_LEAF_MAP, OI(LHOFF(freemap)), CI(XFS_ATTR_LEAF_MAPSIZE), FLD_ARRAY, TYP_NONE }, { NULL } }; #define LMOFF(f) bitize(offsetof(xfs_attr_leaf_map_t, f)) const field_t attr_leaf_map_flds[] = { { "base", FLDT_UINT16D, OI(LMOFF(base)), C1, 0, TYP_NONE }, { "size", FLDT_UINT16D, OI(LMOFF(size)), C1, 0, TYP_NONE }, { NULL } }; #define LNOFF(f) bitize(offsetof(xfs_attr_leaf_name_local_t, f)) #define LVOFF(f) bitize(offsetof(xfs_attr_leaf_name_remote_t, f)) const field_t attr_leaf_name_flds[] = { { "valuelen", FLDT_UINT16D, OI(LNOFF(valuelen)), attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, { "namelen", FLDT_UINT8D, OI(LNOFF(namelen)), attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, { "name", FLDT_CHARNS, OI(LNOFF(nameval)), attr_leaf_name_local_name_count, FLD_COUNT, TYP_NONE }, { "value", FLDT_CHARNS, attr_leaf_name_local_value_offset, attr_leaf_name_local_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "valueblk", FLDT_UINT32X, OI(LVOFF(valueblk)), attr_leaf_name_remote_count, FLD_COUNT, TYP_NONE }, { "valuelen", FLDT_UINT32D, OI(LVOFF(valuelen)), attr_leaf_name_remote_count, FLD_COUNT, TYP_NONE }, { "namelen", FLDT_UINT8D, OI(LVOFF(namelen)), attr_leaf_name_remote_count, FLD_COUNT, TYP_NONE }, { "name", FLDT_CHARNS, OI(LVOFF(name)), attr_leaf_name_remote_name_count, FLD_COUNT, TYP_NONE }, { NULL } }; #define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f)) const field_t attr_node_entry_flds[] = { { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE }, { "before", FLDT_ATTRBLOCK, OI(EOFF(before)), C1, 0, TYP_ATTR }, { NULL } }; #define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f)) const field_t attr_node_hdr_flds[] = { { "info", FLDT_ATTR_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(HOFF(__count)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(HOFF(__level)), C1, 0, TYP_NONE }, { NULL } }; static int attr_leaf_entries_count( void *obj, int startoff) { struct xfs_attr_leafblock *leaf = obj; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) return 0; return be16_to_cpu(leaf->hdr.count); } static int attr3_leaf_entries_count( void *obj, int startoff) { struct xfs_attr3_leafblock *leaf = obj; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_ATTR3_LEAF_MAGIC) return 0; return be16_to_cpu(leaf->hdr.count); } static int attr_leaf_hdr_count( void *obj, int startoff) { struct xfs_attr_leafblock *leaf = obj; ASSERT(startoff == 0); return be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC; } static int attr3_leaf_hdr_count( void *obj, int startoff) { struct xfs_attr3_leafblock *leaf = obj; ASSERT(startoff == 0); return be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_ATTR3_LEAF_MAGIC; } static int attr_remote_data_count( void *obj, int startoff) { if (attr_leaf_hdr_count(obj, startoff) == 0 && attr_node_hdr_count(obj, startoff) == 0) return mp->m_sb.sb_blocksize; return 0; } static int attr3_remote_data_count( void *obj, int startoff) { struct xfs_attr3_rmt_hdr *hdr = obj; size_t buf_space; ASSERT(startoff == 0); if (hdr->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC)) return 0; buf_space = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); if (be32_to_cpu(hdr->rm_bytes) > buf_space) return buf_space; return be32_to_cpu(hdr->rm_bytes); } typedef int (*attr_leaf_entry_walk_f)(struct xfs_attr_leafblock *, struct xfs_attr_leaf_entry *, int); static int attr_leaf_entry_walk( void *obj, int startoff, attr_leaf_entry_walk_f func) { struct xfs_attr_leafblock *leaf = obj; struct xfs_attr3_icleaf_hdr leafhdr; struct xfs_attr_leaf_entry *entries; struct xfs_attr_leaf_entry *e; int i; int off; ASSERT(bitoffs(startoff) == 0); if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC && be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR3_LEAF_MAGIC) return 0; off = byteize(startoff); xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); entries = xfs_attr3_leaf_entryp(leaf); for (i = 0; i < leafhdr.count; i++) { e = &entries[i]; if (be16_to_cpu(e->nameidx) == off) return func(leaf, e, i); } return 0; } static int __attr_leaf_name_local_count( struct xfs_attr_leafblock *leaf, struct xfs_attr_leaf_entry *e, int i) { return (e->flags & XFS_ATTR_LOCAL) != 0; } static int attr_leaf_name_local_count( void *obj, int startoff) { return attr_leaf_entry_walk(obj, startoff, __attr_leaf_name_local_count); } static int __attr_leaf_name_local_name_count( struct xfs_attr_leafblock *leaf, struct xfs_attr_leaf_entry *e, int i) { struct xfs_attr_leaf_name_local *l; if (!(e->flags & XFS_ATTR_LOCAL)) return 0; l = xfs_attr3_leaf_name_local(leaf, i); return l->namelen; } static int attr_leaf_name_local_name_count( void *obj, int startoff) { return attr_leaf_entry_walk(obj, startoff, __attr_leaf_name_local_name_count); } static int __attr_leaf_name_local_value_count( struct xfs_attr_leafblock *leaf, struct xfs_attr_leaf_entry *e, int i) { struct xfs_attr_leaf_name_local *l; if (!(e->flags & XFS_ATTR_LOCAL)) return 0; l = xfs_attr3_leaf_name_local(leaf, i); return be16_to_cpu(l->valuelen); } static int attr_leaf_name_local_value_count( void *obj, int startoff) { return attr_leaf_entry_walk(obj, startoff, __attr_leaf_name_local_value_count); } static int __attr_leaf_name_local_value_offset( struct xfs_attr_leafblock *leaf, struct xfs_attr_leaf_entry *e, int i) { struct xfs_attr_leaf_name_local *l; char *vp; l = xfs_attr3_leaf_name_local(leaf, i); vp = (char *)&l->nameval[l->namelen]; return (int)bitize(vp - (char *)l); } static int attr_leaf_name_local_value_offset( void *obj, int startoff, int idx) { return attr_leaf_entry_walk(obj, startoff, __attr_leaf_name_local_value_offset); } static int __attr_leaf_name_remote_count( struct xfs_attr_leafblock *leaf, struct xfs_attr_leaf_entry *e, int i) { return (e->flags & XFS_ATTR_LOCAL) == 0; } static int attr_leaf_name_remote_count( void *obj, int startoff) { return attr_leaf_entry_walk(obj, startoff, __attr_leaf_name_remote_count); } static int __attr_leaf_name_remote_name_count( struct xfs_attr_leafblock *leaf, struct xfs_attr_leaf_entry *e, int i) { struct xfs_attr_leaf_name_remote *r; if (e->flags & XFS_ATTR_LOCAL) return 0; r = xfs_attr3_leaf_name_remote(leaf, i); return r->namelen; } static int attr_leaf_name_remote_name_count( void *obj, int startoff) { return attr_leaf_entry_walk(obj, startoff, __attr_leaf_name_remote_name_count); } int attr_leaf_name_size( void *obj, int startoff, int idx) { struct xfs_attr_leafblock *leaf = obj; struct xfs_attr_leaf_entry *e; struct xfs_attr_leaf_name_local *l; struct xfs_attr_leaf_name_remote *r; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC && be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR3_LEAF_MAGIC) return 0; e = &xfs_attr3_leaf_entryp(leaf)[idx]; if (e->flags & XFS_ATTR_LOCAL) { l = xfs_attr3_leaf_name_local(leaf, idx); return (int)bitize(xfs_attr_leaf_entsize_local(l->namelen, be16_to_cpu(l->valuelen))); } else { r = xfs_attr3_leaf_name_remote(leaf, idx); return (int)bitize(xfs_attr_leaf_entsize_remote(r->namelen)); } } static int attr_leaf_nvlist_count( void *obj, int startoff) { struct xfs_attr_leafblock *leaf = obj; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) return 0; return be16_to_cpu(leaf->hdr.count); } static int attr3_leaf_nvlist_count( void *obj, int startoff) { struct xfs_attr3_leafblock *leaf = obj; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_ATTR3_LEAF_MAGIC) return 0; return be16_to_cpu(leaf->hdr.count); } static int attr_leaf_nvlist_offset( void *obj, int startoff, int idx) { struct xfs_attr_leafblock *leaf = obj; struct xfs_attr_leaf_entry *e; ASSERT(startoff == 0); e = &xfs_attr3_leaf_entryp(leaf)[idx]; return bitize(be16_to_cpu(e->nameidx)); } static int attr_node_btree_count( void *obj, int startoff) { struct xfs_da_intnode *node = obj; ASSERT(startoff == 0); /* this is a base structure */ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) return 0; return be16_to_cpu(node->hdr.__count); } static int attr3_node_btree_count( void *obj, int startoff) { struct xfs_da3_intnode *node = obj; ASSERT(startoff == 0); if (be16_to_cpu(node->hdr.info.hdr.magic) != XFS_DA3_NODE_MAGIC) return 0; return be16_to_cpu(node->hdr.__count); } static int attr_node_hdr_count( void *obj, int startoff) { struct xfs_da_intnode *node = obj; ASSERT(startoff == 0); return be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC; } static int attr3_node_hdr_count( void *obj, int startoff) { struct xfs_da3_intnode *node = obj; ASSERT(startoff == 0); return be16_to_cpu(node->hdr.info.hdr.magic) == XFS_DA3_NODE_MAGIC; } static int attr3_remote_hdr_count( void *obj, int startoff) { struct xfs_attr3_rmt_hdr *node = obj; ASSERT(startoff == 0); return be32_to_cpu(node->rm_magic) == XFS_ATTR3_RMT_MAGIC; } int attr_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_blocksize); } /* * CRC enabled attribute block field definitions */ const field_t attr3_hfld[] = { { "", FLDT_ATTR3, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define L3OFF(f) bitize(offsetof(struct xfs_attr3_leafblock, f)) #define N3OFF(f) bitize(offsetof(struct xfs_da3_intnode, f)) const field_t attr3_flds[] = { { "hdr", FLDT_ATTR3_LEAF_HDR, OI(L3OFF(hdr)), attr3_leaf_hdr_count, FLD_COUNT, TYP_NONE }, { "hdr", FLDT_ATTR3_NODE_HDR, OI(N3OFF(hdr)), attr3_node_hdr_count, FLD_COUNT, TYP_NONE }, { "hdr", FLDT_ATTR3_REMOTE_HDR, OI(0), attr3_remote_hdr_count, FLD_COUNT, TYP_NONE }, { "data", FLDT_CHARNS, OI(bitize(sizeof(struct xfs_attr3_rmt_hdr))), attr3_remote_data_count, FLD_COUNT, TYP_NONE }, { "entries", FLDT_ATTR_LEAF_ENTRY, OI(L3OFF(entries)), attr3_leaf_entries_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "btree", FLDT_ATTR_NODE_ENTRY, OI(N3OFF(__btree)), attr3_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "nvlist", FLDT_ATTR_LEAF_NAME, attr_leaf_nvlist_offset, attr3_leaf_nvlist_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { NULL } }; #define LH3OFF(f) bitize(offsetof(struct xfs_attr3_leaf_hdr, f)) const field_t attr3_leaf_hdr_flds[] = { { "info", FLDT_ATTR3_BLKINFO, OI(LH3OFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(LH3OFF(count)), C1, 0, TYP_NONE }, { "usedbytes", FLDT_UINT16D, OI(LH3OFF(usedbytes)), C1, 0, TYP_NONE }, { "firstused", FLDT_UINT16D, OI(LH3OFF(firstused)), C1, 0, TYP_NONE }, { "holes", FLDT_UINT8D, OI(LH3OFF(holes)), C1, 0, TYP_NONE }, { "pad1", FLDT_UINT8X, OI(LH3OFF(pad1)), C1, FLD_SKIPALL, TYP_NONE }, { "freemap", FLDT_ATTR_LEAF_MAP, OI(LH3OFF(freemap)), CI(XFS_ATTR_LEAF_MAPSIZE), FLD_ARRAY, TYP_NONE }, { NULL } }; #define B3OFF(f) bitize(offsetof(struct xfs_da3_blkinfo, f)) const field_t attr3_blkinfo_flds[] = { { "hdr", FLDT_ATTR_BLKINFO, OI(B3OFF(hdr)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(B3OFF(crc)), C1, 0, TYP_NONE }, { "bno", FLDT_DFSBNO, OI(B3OFF(blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(B3OFF(lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(B3OFF(uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(B3OFF(owner)), C1, 0, TYP_NONE }, { NULL } }; #define H3OFF(f) bitize(offsetof(struct xfs_da3_node_hdr, f)) const field_t attr3_node_hdr_flds[] = { { "info", FLDT_ATTR3_BLKINFO, OI(H3OFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(H3OFF(__count)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(H3OFF(__level)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT32X, OI(H3OFF(__pad32)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define RM3OFF(f) bitize(offsetof(struct xfs_attr3_rmt_hdr, rm_ ## f)) const struct field attr3_remote_crc_flds[] = { { "magic", FLDT_UINT32X, OI(RM3OFF(magic)), C1, 0, TYP_NONE }, { "offset", FLDT_UINT32D, OI(RM3OFF(offset)), C1, 0, TYP_NONE }, { "bytes", FLDT_UINT32D, OI(RM3OFF(bytes)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(RM3OFF(crc)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(RM3OFF(uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(RM3OFF(owner)), C1, 0, TYP_NONE }, { "bno", FLDT_DFSBNO, OI(RM3OFF(blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(RM3OFF(lsn)), C1, 0, TYP_NONE }, { NULL } }; /* Set the CRC. */ void xfs_attr3_set_crc( struct xfs_buf *bp) { __be32 magic32; __be16 magic16; magic32 = *(__be32 *)bp->b_addr; magic16 = ((struct xfs_da_blkinfo *)bp->b_addr)->magic; switch (magic16) { case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): xfs_buf_update_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF); return; case cpu_to_be16(XFS_DA3_NODE_MAGIC): xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF); return; default: break; } switch (magic32) { case cpu_to_be32(XFS_ATTR3_RMT_MAGIC): xfs_buf_update_cksum(bp, XFS_ATTR3_RMT_CRC_OFF); return; default: dbprintf(_("Unknown attribute buffer type!\n")); break; } } /* * Special read verifier for attribute buffers. Detect the magic number * appropriately and set the correct verifier and call it. */ static void xfs_attr3_db_read_verify( struct xfs_buf *bp) { __be32 magic32; __be16 magic16; magic32 = *(__be32 *)bp->b_addr; magic16 = ((struct xfs_da_blkinfo *)bp->b_addr)->magic; switch (magic16) { case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): bp->b_ops = &xfs_attr3_leaf_buf_ops; goto verify; case cpu_to_be16(XFS_DA3_NODE_MAGIC): bp->b_ops = &xfs_da3_node_buf_ops; goto verify; default: break; } switch (magic32) { case cpu_to_be32(XFS_ATTR3_RMT_MAGIC): bp->b_ops = &xfs_attr3_rmt_buf_ops; break; default: dbprintf(_("Unknown attribute buffer type!\n")); xfs_buf_ioerror(bp, -EFSCORRUPTED); return; } verify: bp->b_ops->verify_read(bp); } static void xfs_attr3_db_write_verify( struct xfs_buf *bp) { dbprintf(_("Writing unknown attribute buffer type!\n")); xfs_buf_ioerror(bp, -EFSCORRUPTED); } const struct xfs_buf_ops xfs_attr3_db_buf_ops = { .name = "xfs_attr3", .verify_read = xfs_attr3_db_read_verify, .verify_write = xfs_attr3_db_write_verify, }; xfsprogs-5.3.0/db/attr.h0000644000175000017500000000177113435336036014770 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const field_t attr_flds[]; extern const field_t attr_hfld[]; extern const field_t attr_blkinfo_flds[]; extern const field_t attr_leaf_entry_flds[]; extern const field_t attr_leaf_hdr_flds[]; extern const field_t attr_leaf_map_flds[]; extern const field_t attr_leaf_name_flds[]; extern const field_t attr_node_entry_flds[]; extern const field_t attr_node_hdr_flds[]; extern const field_t attr3_flds[]; extern const field_t attr3_hfld[]; extern const field_t attr3_leaf_hdr_flds[]; extern const field_t attr3_node_hdr_flds[]; extern const field_t attr3_blkinfo_flds[]; extern const field_t attr3_node_hdr_flds[]; extern const field_t attr3_remote_crc_flds[]; extern int attr_leaf_name_size(void *obj, int startoff, int idx); extern int attr_size(void *obj, int startoff, int idx); extern void xfs_attr3_set_crc(struct xfs_buf *bp); extern const struct xfs_buf_ops xfs_attr3_db_buf_ops; xfsprogs-5.3.0/db/attrset.c0000644000175000017500000001225113435336036015472 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "attrset.h" #include "io.h" #include "output.h" #include "type.h" #include "init.h" #include "fprint.h" #include "faddr.h" #include "field.h" #include "inode.h" #include "malloc.h" static int attr_set_f(int argc, char **argv); static int attr_remove_f(int argc, char **argv); static void attrset_help(void); static const cmdinfo_t attr_set_cmd = { "attr_set", "aset", attr_set_f, 1, -1, 0, N_("[-r|-s|-p|-u] [-n] [-R|-C] [-v n] name"), N_("set the named attribute on the current inode"), attrset_help }; static const cmdinfo_t attr_remove_cmd = { "attr_remove", "aremove", attr_remove_f, 1, -1, 0, N_("[-r|-s|-p|-u] [-n] name"), N_("remove the named attribute from the current inode"), attrset_help }; static void attrset_help(void) { dbprintf(_( "\n" " The 'attr_set' and 'attr_remove' commands provide interfaces for debugging\n" " the extended attribute allocation and removal code.\n" " Both commands require an attribute name to be specified, and the attr_set\n" " command allows an optional value length (-v) to be provided as well.\n" " There are 4 namespace flags:\n" " -r -- 'root'\n" " -u -- 'user' (default)\n" " -s -- 'secure'\n" "\n" " For attr_set, these options further define the type of set operation:\n" " -C -- 'create' - create attribute, fail if it already exists\n" " -R -- 'replace' - replace attribute, fail if it does not exist\n" " The backward compatibility mode 'noattr2' can be emulated (-n) also.\n" "\n")); } void attrset_init(void) { if (!expert_mode) return; add_command(&attr_set_cmd); add_command(&attr_remove_cmd); } static int attr_set_f( int argc, char **argv) { xfs_inode_t *ip = NULL; char *name, *value, *sp; int c, valuelen = 0, flags = 0; if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } if (cur_typ->typnm != TYP_INODE) { dbprintf(_("current type is not inode\n")); return 0; } while ((c = getopt(argc, argv, "rusCRnv:")) != EOF) { switch (c) { /* namespaces */ case 'r': flags |= LIBXFS_ATTR_ROOT; flags &= ~LIBXFS_ATTR_SECURE; break; case 'u': flags &= ~(LIBXFS_ATTR_ROOT | LIBXFS_ATTR_SECURE); break; case 's': flags |= LIBXFS_ATTR_SECURE; flags &= ~LIBXFS_ATTR_ROOT; break; /* modifiers */ case 'C': flags |= LIBXFS_ATTR_CREATE; break; case 'R': flags |= LIBXFS_ATTR_REPLACE; break; case 'n': mp->m_flags |= LIBXFS_MOUNT_COMPAT_ATTR; break; /* value length */ case 'v': valuelen = (int)strtol(optarg, &sp, 0); if (*sp != '\0' || valuelen < 0 || valuelen > 64*1024) { dbprintf(_("bad attr_set valuelen %s\n"), optarg); return 0; } break; default: dbprintf(_("bad option for attr_set command\n")); return 0; } } if (optind != argc - 1) { dbprintf(_("too few options for attr_set (no name given)\n")); return 0; } name = argv[optind]; if (valuelen) { value = (char *)memalign(getpagesize(), valuelen); if (!value) { dbprintf(_("cannot allocate buffer (%d)\n"), valuelen); goto out; } memset(value, 'v', valuelen); } else { value = NULL; } if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip, &xfs_default_ifork_ops)) { dbprintf(_("failed to iget inode %llu\n"), (unsigned long long)iocur_top->ino); goto out; } if (libxfs_attr_set(ip, (unsigned char *)name, (unsigned char *)value, valuelen, flags)) { dbprintf(_("failed to set attr %s on inode %llu\n"), name, (unsigned long long)iocur_top->ino); goto out; } /* refresh with updated inode contents */ set_cur_inode(iocur_top->ino); out: mp->m_flags &= ~LIBXFS_MOUNT_COMPAT_ATTR; if (ip) libxfs_irele(ip); if (value) free(value); return 0; } static int attr_remove_f( int argc, char **argv) { xfs_inode_t *ip = NULL; char *name; int c, flags = 0; if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } if (cur_typ->typnm != TYP_INODE) { dbprintf(_("current type is not inode\n")); return 0; } while ((c = getopt(argc, argv, "rusn")) != EOF) { switch (c) { /* namespaces */ case 'r': flags |= LIBXFS_ATTR_ROOT; flags &= ~LIBXFS_ATTR_SECURE; break; case 'u': flags &= ~(LIBXFS_ATTR_ROOT | LIBXFS_ATTR_SECURE); break; case 's': flags |= LIBXFS_ATTR_SECURE; flags &= ~LIBXFS_ATTR_ROOT; break; case 'n': mp->m_flags |= LIBXFS_MOUNT_COMPAT_ATTR; break; default: dbprintf(_("bad option for attr_remove command\n")); return 0; } } if (optind != argc - 1) { dbprintf(_("too few options for attr_remove (no name given)\n")); return 0; } name = argv[optind]; if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip, &xfs_default_ifork_ops)) { dbprintf(_("failed to iget inode %llu\n"), (unsigned long long)iocur_top->ino); goto out; } if (libxfs_attr_remove(ip, (unsigned char *)name, flags)) { dbprintf(_("failed to remove attr %s from inode %llu\n"), name, (unsigned long long)iocur_top->ino); goto out; } /* refresh with updated inode contents */ set_cur_inode(iocur_top->ino); out: mp->m_flags &= ~LIBXFS_MOUNT_COMPAT_ATTR; if (ip) libxfs_irele(ip); return 0; } xfsprogs-5.3.0/db/attrset.h0000644000175000017500000000022113435336036015471 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void attrset_init(void); xfsprogs-5.3.0/db/attrshort.c0000644000175000017500000000757713435336036016055 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "bit.h" #include "attrshort.h" static int attr_sf_entry_name_count(void *obj, int startoff); static int attr_sf_entry_value_count(void *obj, int startoff); static int attr_sf_entry_value_offset(void *obj, int startoff, int idx); static int attr_shortform_list_count(void *obj, int startoff); static int attr_shortform_list_offset(void *obj, int startoff, int idx); #define OFF(f) bitize(offsetof(xfs_attr_shortform_t, f)) const field_t attr_shortform_flds[] = { { "hdr", FLDT_ATTR_SF_HDR, OI(OFF(hdr)), C1, 0, TYP_NONE }, { "list", FLDT_ATTR_SF_ENTRY, attr_shortform_list_offset, attr_shortform_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; #define HOFF(f) bitize(offsetof(xfs_attr_sf_hdr_t, f)) const field_t attr_sf_hdr_flds[] = { { "totsize", FLDT_UINT16D, OI(HOFF(totsize)), C1, 0, TYP_NONE }, { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE }, { NULL } }; #define EOFF(f) bitize(offsetof(xfs_attr_sf_entry_t, f)) const field_t attr_sf_entry_flds[] = { { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, { "valuelen", FLDT_UINT8D, OI(EOFF(valuelen)), C1, 0, TYP_NONE }, { "flags", FLDT_UINT8X, OI(EOFF(flags)), C1, FLD_SKIPALL, TYP_NONE }, { "root", FLDT_UINT1, OI(EOFF(flags) + bitsz(uint8_t) - XFS_ATTR_ROOT_BIT - 1), C1, 0, TYP_NONE }, { "secure", FLDT_UINT1, OI(EOFF(flags) + bitsz(uint8_t) - XFS_ATTR_SECURE_BIT - 1), C1, 0, TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(nameval)), attr_sf_entry_name_count, FLD_COUNT, TYP_NONE }, { "value", FLDT_CHARNS, attr_sf_entry_value_offset, attr_sf_entry_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; static int attr_sf_entry_name_count( void *obj, int startoff) { xfs_attr_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); e = (xfs_attr_sf_entry_t *)((char *)obj + byteize(startoff)); return e->namelen; } int attr_sf_entry_size( void *obj, int startoff, int idx) { xfs_attr_sf_entry_t *e; int i; xfs_attr_shortform_t *sf; ASSERT(bitoffs(startoff) == 0); sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); e = &sf->list[0]; for (i = 0; i < idx; i++) e = XFS_ATTR_SF_NEXTENTRY(e); return bitize((int)XFS_ATTR_SF_ENTSIZE(e)); } static int attr_sf_entry_value_count( void *obj, int startoff) { xfs_attr_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); e = (xfs_attr_sf_entry_t *)((char *)obj + byteize(startoff)); return e->valuelen; } /*ARGSUSED*/ static int attr_sf_entry_value_offset( void *obj, int startoff, int idx) { xfs_attr_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); e = (xfs_attr_sf_entry_t *)((char *)obj + byteize(startoff)); return bitize((int)((char *)&e->nameval[e->namelen] - (char *)e)); } static int attr_shortform_list_count( void *obj, int startoff) { xfs_attr_shortform_t *sf; ASSERT(bitoffs(startoff) == 0); sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); return sf->hdr.count; } static int attr_shortform_list_offset( void *obj, int startoff, int idx) { xfs_attr_sf_entry_t *e; int i; xfs_attr_shortform_t *sf; ASSERT(bitoffs(startoff) == 0); sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); e = &sf->list[0]; for (i = 0; i < idx; i++) e = XFS_ATTR_SF_NEXTENTRY(e); return bitize((int)((char *)e - (char *)sf)); } /*ARGSUSED*/ int attrshort_size( void *obj, int startoff, int idx) { xfs_attr_sf_entry_t *e; int i; xfs_attr_shortform_t *sf; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); e = &sf->list[0]; for (i = 0; i < sf->hdr.count; i++) e = XFS_ATTR_SF_NEXTENTRY(e); return bitize((int)((char *)e - (char *)sf)); } xfsprogs-5.3.0/db/attrshort.h0000644000175000017500000000064113435336036016043 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const field_t attr_sf_entry_flds[]; extern const field_t attr_sf_hdr_flds[]; extern const field_t attr_shortform_flds[]; extern const field_t attrshort_hfld[]; extern int attr_sf_entry_size(void *obj, int startoff, int idx); extern int attrshort_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/bit.c0000644000175000017500000000633113435336036014564 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "bit.h" int getbit_l( char *ptr, int bit) { int mask; int shift; ptr += byteize(bit); bit = bitoffs(bit); shift = 7 - bit; mask = 1 << shift; return (*ptr & mask) >> shift; } void setbit_l( char *ptr, int bit, int val) { int mask; int shift; ptr += byteize(bit); bit = bitoffs(bit); shift = 7 - bit; mask = (1 << shift); if (val) { *ptr |= mask; } else { mask = ~mask; *ptr &= mask; } } int64_t getbitval( void *obj, int bitoff, int nbits, int flags) { int bit; int i; char *p; int64_t rval; int signext; int z1, z2, z3, z4; ASSERT(nbits<=64); p = (char *)obj + byteize(bitoff); bit = bitoffs(bitoff); signext = (flags & BVSIGNED) != 0; z4 = ((intptr_t)p & 0xf) == 0 && bit == 0; if (nbits == 64 && z4) return be64_to_cpu(*(__be64 *)p); z3 = ((intptr_t)p & 0x7) == 0 && bit == 0; if (nbits == 32 && z3) { if (signext) return (__s32)be32_to_cpu(*(__be32 *)p); else return (__u32)be32_to_cpu(*(__be32 *)p); } z2 = ((intptr_t)p & 0x3) == 0 && bit == 0; if (nbits == 16 && z2) { if (signext) return (__s16)be16_to_cpu(*(__be16 *)p); else return (__u16)be16_to_cpu(*(__be16 *)p); } z1 = ((intptr_t)p & 0x1) == 0 && bit == 0; if (nbits == 8 && z1) { if (signext) return *(__s8 *)p; else return *(__u8 *)p; } for (i = 0, rval = 0LL; i < nbits; i++) { if (getbit_l(p, bit + i)) { /* If the last bit is on and we care about sign * bits and we don't have a full 64 bit * container, turn all bits on between the * sign bit and the most sig bit. */ /* handle endian swap here */ #if __BYTE_ORDER == LITTLE_ENDIAN if (i == 0 && signext && nbits < 64) rval = (~0ULL) << nbits; rval |= 1ULL << (nbits - i - 1); #else if ((i == (nbits - 1)) && signext && nbits < 64) rval |= ((~0ULL) << nbits); rval |= 1ULL << (nbits - i - 1); #endif } } return rval; } /* * The input data can be 8, 16, 32, and 64 sized numeric values * aligned on a byte boundry, or odd sized numbers stored on odd * aligned offset (for example the bmbt fields). * * The input data sent to this routine has been converted to big endian * and has been adjusted in the array so that the first input bit is to * be written in the first bit in the output. * * If the field length and the output buffer are byte aligned, then use * memcpy from the input to the output, but if either entries are not byte * aligned, then loop over the entire bit range reading the input value * and set/clear the matching bit in the output. * * example when ibuf is not multiple of a byte in length: * * ibuf: | BBBBBBBB | bbbxxxxx | * \\\\\\\\--\\\\ * obuf+bitoff: | xBBBBBBB | Bbbbxxxx | * */ void setbitval( void *obuf, /* start of buffer to write into */ int bitoff, /* bit offset into the output buffer */ int nbits, /* number of bits to write */ void *ibuf) /* source bits */ { char *in = ibuf; char *out = obuf; int bit; if (bitoff % NBBY || nbits % NBBY) { for (bit = 0; bit < nbits; bit++) setbit_l(out, bit + bitoff, getbit_l(in, bit)); } else memcpy(out + byteize(bitoff), in, byteize(nbits)); } xfsprogs-5.3.0/db/bit.h0000644000175000017500000000115313435336036014566 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #define bitize(s) ((s) * NBBY) #define bitsz(t) bitize(sizeof(t)) #define bitszof(x,y) bitize(szof(x,y)) #define byteize(s) ((s) / NBBY) #define bitoffs(s) ((s) % NBBY) #define byteize_up(s) (((s) + NBBY - 1) / NBBY) #define BVUNSIGNED 0 #define BVSIGNED 1 extern int64_t getbitval(void *obj, int bitoff, int nbits, int flags); extern void setbitval(void *obuf, int bitoff, int nbits, void *ibuf); extern int getbit_l(char *ptr, int bit); extern void setbit_l(char *ptr, int bit, int val); xfsprogs-5.3.0/db/block.c0000644000175000017500000001371713435336036015106 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "block.h" #include "bmap.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "inode.h" #include "io.h" #include "output.h" #include "init.h" static int ablock_f(int argc, char **argv); static void ablock_help(void); static int daddr_f(int argc, char **argv); static void daddr_help(void); static int dblock_f(int argc, char **argv); static void dblock_help(void); static int fsblock_f(int argc, char **argv); static void fsblock_help(void); static void print_rawdata(void *data, int len); static const cmdinfo_t ablock_cmd = { "ablock", NULL, ablock_f, 1, 1, 1, N_("filoff"), N_("set address to file offset (attr fork)"), ablock_help }; static const cmdinfo_t daddr_cmd = { "daddr", NULL, daddr_f, 0, 1, 1, N_("[d]"), N_("set address to daddr value"), daddr_help }; static const cmdinfo_t dblock_cmd = { "dblock", NULL, dblock_f, 1, 1, 1, N_("filoff"), N_("set address to file offset (data fork)"), dblock_help }; static const cmdinfo_t fsblock_cmd = { "fsblock", "fsb", fsblock_f, 0, 1, 1, N_("[fsb]"), N_("set address to fsblock value"), fsblock_help }; static void ablock_help(void) { dbprintf(_( "\n Example:\n" "\n" " 'ablock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's attribute fork. The filesystem block size is specified in\n" " the superblock.\n\n" )); } /*ARGSUSED*/ static int ablock_f( int argc, char **argv) { bmap_ext_t bm; xfs_fileoff_t bno; xfs_fsblock_t dfsbno; int haveattr; int nex; char *p; bno = (xfs_fileoff_t)strtoull(argv[1], &p, 0); if (*p != '\0') { dbprintf(_("bad block number %s\n"), argv[1]); return 0; } push_cur(); set_cur_inode(iocur_top->ino); if (!iocur_top->data) { pop_cur(); dbprintf(_("no current inode\n")); return 0; } haveattr = XFS_DFORK_Q((xfs_dinode_t *)iocur_top->data); pop_cur(); if (!haveattr) { dbprintf(_("no attribute data for file\n")); return 0; } nex = 1; bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); if (nex == 0) { dbprintf(_("file attr block is unmapped\n")); return 0; } dfsbno = bm.startblock + (bno - bm.startoff); ASSERT(typtab[TYP_ATTR].typnm == TYP_ATTR); set_cur(&typtab[TYP_ATTR], (int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, DB_RING_ADD, NULL); return 0; } void block_init(void) { add_command(&ablock_cmd); add_command(&daddr_cmd); add_command(&dblock_cmd); add_command(&fsblock_cmd); } static void daddr_help(void) { dbprintf(_( "\n Example:\n" "\n" " 'daddr 102' - sets position to the 102nd absolute disk block\n" " (512 byte block).\n" )); } static int daddr_f( int argc, char **argv) { int64_t d; char *p; if (argc == 1) { dbprintf(_("current daddr is %lld\n"), iocur_top->off >> BBSHIFT); return 0; } d = (int64_t)strtoull(argv[1], &p, 0); if (*p != '\0' || d >= mp->m_sb.sb_dblocks << (mp->m_sb.sb_blocklog - BBSHIFT)) { dbprintf(_("bad daddr %s\n"), argv[1]); return 0; } ASSERT(typtab[TYP_DATA].typnm == TYP_DATA); set_cur(&typtab[TYP_DATA], d, 1, DB_RING_ADD, NULL); return 0; } static void dblock_help(void) { dbprintf(_( "\n Example:\n" "\n" " 'dblock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's data fork. The filesystem block size is specified in the\n" " superblock.\n\n" )); } static int dblock_f( int argc, char **argv) { bbmap_t bbmap; bmap_ext_t *bmp; xfs_fileoff_t bno; xfs_fsblock_t dfsbno; int nb; int nex; char *p; typnm_t type; bno = (xfs_fileoff_t)strtoull(argv[1], &p, 0); if (*p != '\0') { dbprintf(_("bad block number %s\n"), argv[1]); return 0; } push_cur(); set_cur_inode(iocur_top->ino); type = inode_next_type(); pop_cur(); if (type == TYP_NONE) { dbprintf(_("no type for file data\n")); return 0; } nex = nb = type == TYP_DIR2 ? mp->m_dir_geo->fsbcount : 1; bmp = malloc(nb * sizeof(*bmp)); bmap(bno, nb, XFS_DATA_FORK, &nex, bmp); if (nex == 0) { dbprintf(_("file data block is unmapped\n")); free(bmp); return 0; } dfsbno = bmp->startblock + (bno - bmp->startoff); ASSERT(typtab[type].typnm == type); if (nex > 1) make_bbmap(&bbmap, nex, bmp); set_cur(&typtab[type], (int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), nb * blkbb, DB_RING_ADD, nex > 1 ? &bbmap : NULL); free(bmp); return 0; } static void fsblock_help(void) { dbprintf(_( "\n Example:\n" "\n" " 'fsblock 1023' - sets the file position to the 1023rd filesystem block.\n" " The filesystem block size is specified in the superblock and set during\n" " mkfs time. Offset is absolute (not AG relative).\n\n" )); } static int fsblock_f( int argc, char **argv) { xfs_agblock_t agbno; xfs_agnumber_t agno; xfs_fsblock_t d; char *p; if (argc == 1) { dbprintf(_("current fsblock is %lld\n"), XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT)); return 0; } d = strtoull(argv[1], &p, 0); if (*p != '\0') { dbprintf(_("bad fsblock %s\n"), argv[1]); return 0; } agno = XFS_FSB_TO_AGNO(mp, d); agbno = XFS_FSB_TO_AGBNO(mp, d); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks) { dbprintf(_("bad fsblock %s\n"), argv[1]); return 0; } ASSERT(typtab[TYP_DATA].typnm == TYP_DATA); set_cur(&typtab[TYP_DATA], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_ADD, NULL); return 0; } void print_block( const field_t *fields, int argc, char **argv) { print_rawdata(iocur_top->data, iocur_top->len); } static void print_rawdata( void *data, int len) { int i; int j; int lastaddr; int offchars; unsigned char *p; lastaddr = (len - 1) & ~(32 - 1); if (lastaddr < 0x10) offchars = 1; else if (lastaddr < 0x100) offchars = 2; else if (lastaddr < 0x1000) offchars = 3; else offchars = 4; for (i = 0, p = data; i < len; i += 32) { dbprintf("%-0*.*x:", offchars, offchars, i); for (j = 0; j < 32 && i + j < len; j++, p++) { if ((j & 3) == 0) dbprintf(" "); dbprintf("%02x", *p); } dbprintf("\n"); } } xfsprogs-5.3.0/db/block.h0000644000175000017500000000036413435336036015105 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct field; extern void block_init(void); extern void print_block(const struct field *fields, int argc, char **argv); xfsprogs-5.3.0/db/bmap.c0000644000175000017500000001533113435336036014725 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "fprint.h" #include "faddr.h" #include "field.h" #include "bmap.h" #include "io.h" #include "inode.h" #include "output.h" #include "init.h" static int bmap_f(int argc, char **argv); static int bmap_one_extent(xfs_bmbt_rec_t *ep, xfs_fileoff_t *offp, xfs_fileoff_t eoff, int *idxp, bmap_ext_t *bep); static xfs_fsblock_t select_child(xfs_fileoff_t off, xfs_bmbt_key_t *kp, xfs_bmbt_ptr_t *pp, int nrecs); static const cmdinfo_t bmap_cmd = { "bmap", NULL, bmap_f, 0, 3, 0, N_("[-ad] [block [len]]"), N_("show block map for current file"), NULL }; void bmap( xfs_fileoff_t offset, xfs_filblks_t len, int whichfork, int *nexp, bmap_ext_t *bep) { struct xfs_btree_block *block; xfs_fsblock_t bno; xfs_fileoff_t curoffset; xfs_dinode_t *dip; xfs_fileoff_t eoffset; xfs_bmbt_rec_t *ep; xfs_dinode_fmt_t fmt; int fsize; xfs_bmbt_key_t *kp; int n; int nex; xfs_fsblock_t nextbno; int nextents; xfs_bmbt_ptr_t *pp; xfs_bmdr_block_t *rblock; typnm_t typ; xfs_bmbt_rec_t *xp; push_cur(); set_cur_inode(iocur_top->ino); nex = *nexp; *nexp = 0; ASSERT(nex > 0); dip = iocur_top->data; n = 0; eoffset = offset + len - 1; curoffset = offset; fmt = (xfs_dinode_fmt_t)XFS_DFORK_FORMAT(dip, whichfork); typ = whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA; ASSERT(typtab[typ].typnm == typ); ASSERT(fmt == XFS_DINODE_FMT_LOCAL || fmt == XFS_DINODE_FMT_EXTENTS || fmt == XFS_DINODE_FMT_BTREE); if (fmt == XFS_DINODE_FMT_EXTENTS) { nextents = XFS_DFORK_NEXTENTS(dip, whichfork); xp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork); for (ep = xp; ep < &xp[nextents] && n < nex; ep++) { if (!bmap_one_extent(ep, &curoffset, eoffset, &n, bep)) break; } } else if (fmt == XFS_DINODE_FMT_BTREE) { push_cur(); rblock = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); fsize = XFS_DFORK_SIZE(dip, mp, whichfork); pp = XFS_BMDR_PTR_ADDR(rblock, 1, libxfs_bmdr_maxrecs(fsize, 0)); kp = XFS_BMDR_KEY_ADDR(rblock, 1); bno = select_child(curoffset, kp, pp, be16_to_cpu(rblock->bb_numrecs)); for (;;) { set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, NULL); block = (struct xfs_btree_block *)iocur_top->data; if (be16_to_cpu(block->bb_level) == 0) break; pp = XFS_BMBT_PTR_ADDR(mp, block, 1, libxfs_bmbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0)); kp = XFS_BMBT_KEY_ADDR(mp, block, 1); bno = select_child(curoffset, kp, pp, be16_to_cpu(block->bb_numrecs)); } for (;;) { nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); nextents = be16_to_cpu(block->bb_numrecs); xp = (xfs_bmbt_rec_t *) XFS_BMBT_REC_ADDR(mp, block, 1); for (ep = xp; ep < &xp[nextents] && n < nex; ep++) { if (!bmap_one_extent(ep, &curoffset, eoffset, &n, bep)) { nextbno = NULLFSBLOCK; break; } } bno = nextbno; if (bno == NULLFSBLOCK) break; set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, NULL); block = (struct xfs_btree_block *)iocur_top->data; } pop_cur(); } pop_cur(); *nexp = n; } static int bmap_f( int argc, char **argv) { int afork = 0; bmap_ext_t be; int c; xfs_fileoff_t co, cosave; int dfork = 0; xfs_dinode_t *dip; xfs_fileoff_t eo; xfs_filblks_t len; int nex; char *p; int whichfork; if (iocur_top->ino == NULLFSINO) { dbprintf(_("no current inode\n")); return 0; } optind = 0; if (argc) while ((c = getopt(argc, argv, "ad")) != EOF) { switch (c) { case 'a': afork = 1; break; case 'd': dfork = 1; break; default: dbprintf(_("bad option for bmap command\n")); return 0; } } if (afork + dfork == 0) { push_cur(); set_cur_inode(iocur_top->ino); dip = iocur_top->data; if (be32_to_cpu(dip->di_nextents)) dfork = 1; if (be16_to_cpu(dip->di_anextents)) afork = 1; pop_cur(); } if (optind < argc) { co = (xfs_fileoff_t)strtoull(argv[optind], &p, 0); if (*p != '\0') { dbprintf(_("bad block number for bmap %s\n"), argv[optind]); return 0; } optind++; if (optind < argc) { len = (xfs_filblks_t)strtoull(argv[optind], &p, 0); if (*p != '\0') { dbprintf(_("bad len for bmap %s\n"), argv[optind]); return 0; } eo = co + len - 1; } else eo = co; } else { co = 0; eo = -1; } cosave = co; for (whichfork = XFS_DATA_FORK; whichfork <= XFS_ATTR_FORK; whichfork++) { if (whichfork == XFS_DATA_FORK && !dfork) continue; if (whichfork == XFS_ATTR_FORK && !afork) continue; for (;;) { nex = 1; bmap(co, eo - co + 1, whichfork, &nex, &be); if (nex == 0) break; dbprintf(_("%s offset %lld startblock %llu (%u/%u) count " "%llu flag %u\n"), whichfork == XFS_DATA_FORK ? _("data") : _("attr"), be.startoff, be.startblock, XFS_FSB_TO_AGNO(mp, be.startblock), XFS_FSB_TO_AGBNO(mp, be.startblock), be.blockcount, be.flag); co = be.startoff + be.blockcount; } co = cosave; } return 0; } void bmap_init(void) { add_command(&bmap_cmd); } static int bmap_one_extent( xfs_bmbt_rec_t *ep, xfs_fileoff_t *offp, xfs_fileoff_t eoff, int *idxp, bmap_ext_t *bep) { xfs_filblks_t c; xfs_fileoff_t curoffset; int f; int idx; xfs_fileoff_t o; xfs_fsblock_t s; convert_extent(ep, &o, &s, &c, &f); curoffset = *offp; idx = *idxp; if (o + c <= curoffset) return 1; if (o > eoff) return 0; if (o < curoffset) { c -= curoffset - o; s += curoffset - o; o = curoffset; } if (o + c - 1 > eoff) c -= (o + c - 1) - eoff; bep[idx].startoff = o; bep[idx].startblock = s; bep[idx].blockcount = c; bep[idx].flag = f; *idxp = idx + 1; *offp = o + c; return 1; } void convert_extent( xfs_bmbt_rec_t *rp, xfs_fileoff_t *op, xfs_fsblock_t *sp, xfs_filblks_t *cp, int *fp) { struct xfs_bmbt_irec irec; libxfs_bmbt_disk_get_all(rp, &irec); *fp = irec.br_state == XFS_EXT_UNWRITTEN; *op = irec.br_startoff; *sp = irec.br_startblock; *cp = irec.br_blockcount; } void make_bbmap( bbmap_t *bbmap, int nex, bmap_ext_t *bmp) { int i; for (i = 0; i < nex; i++) { bbmap->b[i].bm_bn = XFS_FSB_TO_DADDR(mp, bmp[i].startblock); bbmap->b[i].bm_len = XFS_FSB_TO_BB(mp, bmp[i].blockcount); } bbmap->nmaps = nex; } static xfs_fsblock_t select_child( xfs_fileoff_t off, xfs_bmbt_key_t *kp, xfs_bmbt_ptr_t *pp, int nrecs) { int i; for (i = 0; i < nrecs; i++) { if (be64_to_cpu(kp[i].br_startoff) == off) return be64_to_cpu(pp[i]); if (be64_to_cpu(kp[i].br_startoff) > off) { if (i == 0) return be64_to_cpu(pp[i]); else return be64_to_cpu(pp[i - 1]); } } return be64_to_cpu(pp[nrecs - 1]); } xfsprogs-5.3.0/db/bmap.h0000644000175000017500000000116513435336036014732 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct bbmap; struct xfs_bmbt_rec; typedef struct bmap_ext { xfs_fileoff_t startoff; xfs_fsblock_t startblock; xfs_filblks_t blockcount; int flag; } bmap_ext_t; extern void bmap(xfs_fileoff_t offset, xfs_filblks_t len, int whichfork, int *nexp, bmap_ext_t *bep); extern void bmap_init(void); extern void convert_extent(struct xfs_bmbt_rec *rp, xfs_fileoff_t *op, xfs_fsblock_t *sp, xfs_filblks_t *cp, int *fp); extern void make_bbmap(struct bbmap *bbmap, int nex, bmap_ext_t *bmp); xfsprogs-5.3.0/db/bmroot.c0000644000175000017500000001407713435336036015316 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "bmroot.h" #include "io.h" #include "print.h" #include "bit.h" #include "init.h" static int bmroota_key_count(void *obj, int startoff); static int bmroota_key_offset(void *obj, int startoff, int idx); static int bmroota_ptr_count(void *obj, int startoff); static int bmroota_ptr_offset(void *obj, int startoff, int idx); static int bmrootd_key_count(void *obj, int startoff); static int bmrootd_key_offset(void *obj, int startoff, int idx); static int bmrootd_ptr_count(void *obj, int startoff); static int bmrootd_ptr_offset(void *obj, int startoff, int idx); #define OFF(f) bitize(offsetof(xfs_bmdr_block_t, bb_ ## f)) const field_t bmroota_flds[] = { { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "keys", FLDT_BMROOTAKEY, bmroota_key_offset, bmroota_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BMROOTAPTR, bmroota_ptr_offset, bmroota_ptr_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTA }, { NULL } }; const field_t bmrootd_flds[] = { { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "keys", FLDT_BMROOTDKEY, bmrootd_key_offset, bmrootd_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BMROOTDPTR, bmrootd_ptr_offset, bmrootd_ptr_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTD }, { NULL } }; #define KOFF(f) bitize(offsetof(xfs_bmdr_key_t, br_ ## f)) const field_t bmroota_key_flds[] = { { "startoff", FLDT_DFILOFFA, OI(KOFF(startoff)), C1, 0, TYP_NONE }, { NULL } }; const field_t bmrootd_key_flds[] = { { "startoff", FLDT_DFILOFFD, OI(KOFF(startoff)), C1, 0, TYP_NONE }, { NULL } }; static int bmroota_key_count( void *obj, int startoff) { xfs_bmdr_block_t *block; #ifdef DEBUG xfs_dinode_t *dip = obj; #endif ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); ASSERT(be16_to_cpu(block->bb_level) > 0); return be16_to_cpu(block->bb_numrecs); } static int bmroota_key_offset( void *obj, int startoff, int idx) { xfs_bmdr_block_t *block; #ifdef DEBUG xfs_dinode_t *dip = obj; #endif xfs_bmdr_key_t *kp; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); ASSERT(be16_to_cpu(block->bb_level) > 0); kp = XFS_BMDR_KEY_ADDR(block, idx); return bitize((int)((char *)kp - (char *)block)); } static int bmroota_ptr_count( void *obj, int startoff) { xfs_bmdr_block_t *block; #ifdef DEBUG xfs_dinode_t *dip = obj; #endif ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); ASSERT(be16_to_cpu(block->bb_level) > 0); return be16_to_cpu(block->bb_numrecs); } static int bmroota_ptr_offset( void *obj, int startoff, int idx) { xfs_bmdr_block_t *block; xfs_dinode_t *dip; xfs_bmdr_ptr_t *pp; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); ASSERT(be16_to_cpu(block->bb_level) > 0); pp = XFS_BMDR_PTR_ADDR(block, idx, libxfs_bmdr_maxrecs(XFS_DFORK_ASIZE(dip, mp), 0)); return bitize((int)((char *)pp - (char *)block)); } int bmroota_size( void *obj, int startoff, int idx) { xfs_dinode_t *dip; #ifdef DEBUG xfs_bmdr_block_t *block; #endif ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); ASSERT(idx == 0); dip = obj; #ifdef DEBUG block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); #endif return bitize((int)XFS_DFORK_ASIZE(dip, mp)); } static int bmrootd_key_count( void *obj, int startoff) { xfs_bmdr_block_t *block; #ifdef DEBUG xfs_dinode_t *dip = obj; #endif ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT((char *)block == XFS_DFORK_DPTR(dip)); ASSERT(be16_to_cpu(block->bb_level) > 0); return be16_to_cpu(block->bb_numrecs); } static int bmrootd_key_offset( void *obj, int startoff, int idx) { xfs_bmdr_block_t *block; xfs_bmdr_key_t *kp; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(be16_to_cpu(block->bb_level) > 0); kp = XFS_BMDR_KEY_ADDR(block, idx); return bitize((int)((char *)kp - (char *)block)); } static int bmrootd_ptr_count( void *obj, int startoff) { xfs_bmdr_block_t *block; #ifdef DEBUG xfs_dinode_t *dip = obj; #endif ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT((char *)block == XFS_DFORK_DPTR(dip)); ASSERT(be16_to_cpu(block->bb_level) > 0); return be16_to_cpu(block->bb_numrecs); } static int bmrootd_ptr_offset( void *obj, int startoff, int idx) { xfs_bmdr_block_t *block; xfs_bmdr_ptr_t *pp; xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); ASSERT(be16_to_cpu(block->bb_level) > 0); pp = XFS_BMDR_PTR_ADDR(block, idx, libxfs_bmdr_maxrecs(XFS_DFORK_DSIZE(dip, mp), 0)); return bitize((int)((char *)pp - (char *)block)); } int bmrootd_size( void *obj, int startoff, int idx) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); ASSERT(idx == 0); dip = obj; return bitize((int)XFS_DFORK_DSIZE(dip, mp)); } xfsprogs-5.3.0/db/bmroot.h0000644000175000017500000000064213435336036015314 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field bmroota_flds[]; extern const struct field bmroota_key_flds[]; extern const struct field bmrootd_flds[]; extern const struct field bmrootd_key_flds[]; extern int bmroota_size(void *obj, int startoff, int idx); extern int bmrootd_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/btblock.c0000644000175000017500000006527213435336036015437 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "btblock.h" #include "print.h" #include "bit.h" #include "init.h" #include "io.h" #include "output.h" /* * Definition of the possible btree block layouts. */ static struct xfs_db_btree { uint32_t magic; size_t block_len; size_t key_len; size_t rec_len; size_t ptr_len; } btrees[] = { { XFS_BMAP_MAGIC, XFS_BTREE_LBLOCK_LEN, sizeof(xfs_bmbt_key_t), sizeof(xfs_bmbt_rec_t), sizeof(__be64), }, { XFS_ABTB_MAGIC, XFS_BTREE_SBLOCK_LEN, sizeof(xfs_alloc_key_t), sizeof(xfs_alloc_rec_t), sizeof(__be32), }, { XFS_ABTC_MAGIC, XFS_BTREE_SBLOCK_LEN, sizeof(xfs_alloc_key_t), sizeof(xfs_alloc_rec_t), sizeof(__be32), }, { XFS_IBT_MAGIC, XFS_BTREE_SBLOCK_LEN, sizeof(xfs_inobt_key_t), sizeof(xfs_inobt_rec_t), sizeof(__be32), }, { XFS_FIBT_MAGIC, XFS_BTREE_SBLOCK_LEN, sizeof(xfs_inobt_key_t), sizeof(xfs_inobt_rec_t), sizeof(__be32), }, { XFS_BMAP_CRC_MAGIC, XFS_BTREE_LBLOCK_CRC_LEN, sizeof(xfs_bmbt_key_t), sizeof(xfs_bmbt_rec_t), sizeof(__be64), }, { XFS_ABTB_CRC_MAGIC, XFS_BTREE_SBLOCK_CRC_LEN, sizeof(xfs_alloc_key_t), sizeof(xfs_alloc_rec_t), sizeof(__be32), }, { XFS_ABTC_CRC_MAGIC, XFS_BTREE_SBLOCK_CRC_LEN, sizeof(xfs_alloc_key_t), sizeof(xfs_alloc_rec_t), sizeof(__be32), }, { XFS_IBT_CRC_MAGIC, XFS_BTREE_SBLOCK_CRC_LEN, sizeof(xfs_inobt_key_t), sizeof(xfs_inobt_rec_t), sizeof(__be32), }, { XFS_FIBT_CRC_MAGIC, XFS_BTREE_SBLOCK_CRC_LEN, sizeof(xfs_inobt_key_t), sizeof(xfs_inobt_rec_t), sizeof(__be32), }, { XFS_RMAP_CRC_MAGIC, XFS_BTREE_SBLOCK_CRC_LEN, 2 * sizeof(struct xfs_rmap_key), sizeof(struct xfs_rmap_rec), sizeof(__be32), }, { XFS_REFC_CRC_MAGIC, XFS_BTREE_SBLOCK_CRC_LEN, sizeof(struct xfs_refcount_key), sizeof(struct xfs_refcount_rec), sizeof(__be32), }, { 0, }, }; /* * Find the right block definition for a given ondisk block. */ static struct xfs_db_btree * block_to_bt( struct xfs_btree_block *bb) { struct xfs_db_btree *btp; uint32_t magic; bool crc; magic = be32_to_cpu((bb)->bb_magic); for (btp = &btrees[0]; btp->magic != 0; btp++) { if (magic == btp->magic) return btp; } /* Magic is invalid/unknown. Guess based on iocur type */ crc = xfs_sb_version_hascrc(&mp->m_sb); switch (iocur_top->typ->typnm) { case TYP_BMAPBTA: case TYP_BMAPBTD: magic = crc ? XFS_BMAP_CRC_MAGIC : XFS_BMAP_MAGIC; break; case TYP_BNOBT: magic = crc ? XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC; break; case TYP_CNTBT: magic = crc ? XFS_ABTC_CRC_MAGIC : XFS_ABTC_MAGIC; break; case TYP_INOBT: magic = crc ? XFS_IBT_CRC_MAGIC : XFS_IBT_MAGIC; break; case TYP_FINOBT: magic = crc ? XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC; break; case TYP_RMAPBT: magic = crc ? XFS_RMAP_CRC_MAGIC : 0; break; case TYP_REFCBT: magic = crc ? XFS_REFC_CRC_MAGIC : 0; break; default: ASSERT(0); } ASSERT(magic); dbprintf(_("Bad btree magic 0x%x; coercing to %s.\n"), be32_to_cpu((bb)->bb_magic), iocur_top->typ->name); for (btp = &btrees[0]; btp->magic != 0; btp++) { if (magic == btp->magic) return btp; } return NULL; } /* calculate max records. Only for non-leaves. */ static int btblock_maxrecs(struct xfs_db_btree *bt, int blocksize) { blocksize -= bt->block_len; return blocksize / (bt->key_len + bt->ptr_len); } /* * Get the number of keys in a btree block. * * Note: can also be used to get the number of ptrs because there are * always the same number of keys and ptrs in a block. */ static int btblock_key_count( void *obj, int startoff) { struct xfs_btree_block *block = obj; ASSERT(startoff == 0); if (block->bb_level == 0) return 0; return be16_to_cpu(block->bb_numrecs); } /* * Get the number of keys in a btree block. */ static int btblock_rec_count( void *obj, int startoff) { struct xfs_btree_block *block = obj; ASSERT(startoff == 0); if (block->bb_level != 0) return 0; return be16_to_cpu(block->bb_numrecs); } /* * Get the offset of the key at idx in a btree block. */ static int btblock_key_offset( void *obj, int startoff, int idx) { struct xfs_btree_block *block = obj; struct xfs_db_btree *bt = block_to_bt(block); int offset; ASSERT(startoff == 0); ASSERT(block->bb_level != 0); offset = bt->block_len + (idx - 1) * bt->key_len; return bitize(offset); } /* * Get the offset of the ptr at idx in a btree block. */ static int btblock_ptr_offset( void *obj, int startoff, int idx) { struct xfs_btree_block *block = obj; struct xfs_db_btree *bt = block_to_bt(block); int offset; int maxrecs; ASSERT(startoff == 0); ASSERT(block->bb_level != 0); maxrecs = btblock_maxrecs(bt, mp->m_sb.sb_blocksize); offset = bt->block_len + maxrecs * bt->key_len + (idx - 1) * bt->ptr_len; return bitize(offset); } /* * Get the offset of the record at idx in a btree block. */ static int btblock_rec_offset( void *obj, int startoff, int idx) { struct xfs_btree_block *block = obj; struct xfs_db_btree *bt = block_to_bt(block); int offset; ASSERT(startoff == 0); ASSERT(block->bb_level == 0); offset = bt->block_len + (idx - 1) * bt->rec_len; return bitize(offset); } /* * Get the size of a btree block. */ int btblock_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_blocksize); } /* * Bmap btree. */ const field_t bmapbta_hfld[] = { { "", FLDT_BMAPBTA, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t bmapbtd_hfld[] = { { "", FLDT_BMAPBTD, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t bmapbta_crc_hfld[] = { { "", FLDT_BMAPBTA_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t bmapbtd_crc_hfld[] = { { "", FLDT_BMAPBTD_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f)) const field_t bmapbta_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_DFSBNO, OI(OFF(u.l.bb_leftsib)), C1, 0, TYP_BMAPBTA }, { "rightsib", FLDT_DFSBNO, OI(OFF(u.l.bb_rightsib)), C1, 0, TYP_BMAPBTA }, { "recs", FLDT_BMAPBTAREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_BMAPBTAKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BMAPBTAPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTA }, { NULL } }; const field_t bmapbtd_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_DFSBNO, OI(OFF(u.l.bb_leftsib)), C1, 0, TYP_BMAPBTD }, { "rightsib", FLDT_DFSBNO, OI(OFF(u.l.bb_rightsib)), C1, 0, TYP_BMAPBTD }, { "recs", FLDT_BMAPBTDREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_BMAPBTDKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BMAPBTDPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTD }, { NULL } }; /* crc enabled versions */ const field_t bmapbta_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_DFSBNO, OI(OFF(u.l.bb_leftsib)), C1, 0, TYP_BMAPBTA }, { "rightsib", FLDT_DFSBNO, OI(OFF(u.l.bb_rightsib)), C1, 0, TYP_BMAPBTA }, { "bno", FLDT_DFSBNO, OI(OFF(u.l.bb_blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(OFF(u.l.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.l.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(OFF(u.l.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.l.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_BMAPBTAREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_BMAPBTAKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BMAPBTAPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTA }, { NULL } }; const field_t bmapbtd_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_DFSBNO, OI(OFF(u.l.bb_leftsib)), C1, 0, TYP_BMAPBTD }, { "rightsib", FLDT_DFSBNO, OI(OFF(u.l.bb_rightsib)), C1, 0, TYP_BMAPBTD }, { "bno", FLDT_DFSBNO, OI(OFF(u.l.bb_blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(OFF(u.l.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.l.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(OFF(u.l.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.l.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_BMAPBTDREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_BMAPBTDKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BMAPBTDPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTD }, { NULL } }; #undef OFF #define KOFF(f) bitize(offsetof(xfs_bmbt_key_t, br_ ## f)) const field_t bmapbta_key_flds[] = { { "startoff", FLDT_DFILOFFA, OI(KOFF(startoff)), C1, 0, TYP_ATTR }, { NULL } }; const field_t bmapbtd_key_flds[] = { { "startoff", FLDT_DFILOFFD, OI(KOFF(startoff)), C1, 0, TYP_INODATA }, { NULL } }; #undef KOFF #define BMBT_EXNTFLAG_BITOFF 0 #define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF + BMBT_EXNTFLAG_BITLEN) #define BMBT_STARTBLOCK_BITOFF (BMBT_STARTOFF_BITOFF + BMBT_STARTOFF_BITLEN) #define BMBT_BLOCKCOUNT_BITOFF \ (BMBT_STARTBLOCK_BITOFF + BMBT_STARTBLOCK_BITLEN) const field_t bmapbta_rec_flds[] = { { "startoff", FLDT_CFILEOFFA, OI(BMBT_STARTOFF_BITOFF), C1, 0, TYP_ATTR }, { "startblock", FLDT_CFSBLOCK, OI(BMBT_STARTBLOCK_BITOFF), C1, 0, TYP_ATTR }, { "blockcount", FLDT_CEXTLEN, OI(BMBT_BLOCKCOUNT_BITOFF), C1, 0, TYP_NONE }, { "extentflag", FLDT_CEXTFLG, OI(BMBT_EXNTFLAG_BITOFF), C1, 0, TYP_NONE }, { NULL } }; const field_t bmapbtd_rec_flds[] = { { "startoff", FLDT_CFILEOFFD, OI(BMBT_STARTOFF_BITOFF), C1, 0, TYP_INODATA }, { "startblock", FLDT_CFSBLOCK, OI(BMBT_STARTBLOCK_BITOFF), C1, 0, TYP_INODATA }, { "blockcount", FLDT_CEXTLEN, OI(BMBT_BLOCKCOUNT_BITOFF), C1, 0, TYP_NONE }, { "extentflag", FLDT_CEXTFLG, OI(BMBT_EXNTFLAG_BITOFF), C1, 0, TYP_NONE }, { NULL } }; /* * Inode allocation btree. */ const field_t inobt_hfld[] = { { "", FLDT_INOBT, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t inobt_crc_hfld[] = { { "", FLDT_INOBT_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t inobt_spcrc_hfld[] = { { "", FLDT_INOBT_SPCRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f)) const field_t inobt_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_INOBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_INOBT }, { "recs", FLDT_INOBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_INOBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_INOBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_INOBT }, { NULL } }; const field_t inobt_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_INOBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_INOBT }, { "bno", FLDT_DFSBNO, OI(OFF(u.s.bb_blkno)), C1, 0, TYP_INOBT }, { "lsn", FLDT_UINT64X, OI(OFF(u.s.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.s.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_AGNUMBER, OI(OFF(u.s.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.s.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_INOBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_INOBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_INOBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_INOBT }, { NULL } }; const field_t inobt_spcrc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_INOBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_INOBT }, { "bno", FLDT_DFSBNO, OI(OFF(u.s.bb_blkno)), C1, 0, TYP_INOBT }, { "lsn", FLDT_UINT64X, OI(OFF(u.s.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.s.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_AGNUMBER, OI(OFF(u.s.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.s.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_INOBTSPREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_INOBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_INOBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_INOBT }, { NULL } }; #undef OFF #define KOFF(f) bitize(offsetof(xfs_inobt_key_t, ir_ ## f)) const field_t inobt_key_flds[] = { { "startino", FLDT_AGINO, OI(KOFF(startino)), C1, 0, TYP_INODE }, { NULL } }; #undef KOFF #define ROFF(f) bitize(offsetof(xfs_inobt_rec_t, f)) const field_t inobt_rec_flds[] = { { "startino", FLDT_AGINO, OI(ROFF(ir_startino)), C1, 0, TYP_INODE }, { "freecount", FLDT_INT32D, OI(ROFF(ir_u.f.ir_freecount)), C1, 0, TYP_NONE }, { "free", FLDT_INOFREE, OI(ROFF(ir_free)), C1, 0, TYP_NONE }, { NULL } }; /* sparse inode on-disk format */ const field_t inobt_sprec_flds[] = { { "startino", FLDT_AGINO, OI(ROFF(ir_startino)), C1, 0, TYP_INODE }, { "holemask", FLDT_UINT16X, OI(ROFF(ir_u.sp.ir_holemask)), C1, 0, TYP_NONE }, { "count", FLDT_UINT8D, OI(ROFF(ir_u.sp.ir_count)), C1, 0, TYP_NONE }, { "freecount", FLDT_UINT8D, OI(ROFF(ir_u.sp.ir_freecount)), C1, 0, TYP_NONE }, { "free", FLDT_INOFREE, OI(ROFF(ir_free)), C1, 0, TYP_NONE }, { NULL } }; #undef ROFF /* * Allocation btrees. */ const field_t bnobt_hfld[] = { { "", FLDT_BNOBT, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t bnobt_crc_hfld[] = { { "", FLDT_BNOBT_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f)) const field_t bnobt_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_BNOBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_BNOBT }, { "recs", FLDT_BNOBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_BNOBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BNOBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BNOBT }, { NULL } }; const field_t bnobt_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_BNOBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_BNOBT }, { "bno", FLDT_DFSBNO, OI(OFF(u.s.bb_blkno)), C1, 0, TYP_BNOBT }, { "lsn", FLDT_UINT64X, OI(OFF(u.s.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.s.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_AGNUMBER, OI(OFF(u.s.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.s.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_BNOBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_BNOBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_BNOBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BNOBT }, { NULL } }; #undef OFF #define KOFF(f) bitize(offsetof(xfs_alloc_key_t, ar_ ## f)) const field_t bnobt_key_flds[] = { { "startblock", FLDT_AGBLOCK, OI(KOFF(startblock)), C1, 0, TYP_DATA }, { "blockcount", FLDT_EXTLEN, OI(KOFF(blockcount)), C1, 0, TYP_NONE }, { NULL } }; #undef KOFF #define ROFF(f) bitize(offsetof(xfs_alloc_rec_t, ar_ ## f)) const field_t bnobt_rec_flds[] = { { "startblock", FLDT_AGBLOCK, OI(ROFF(startblock)), C1, 0, TYP_DATA }, { "blockcount", FLDT_EXTLEN, OI(ROFF(blockcount)), C1, 0, TYP_NONE }, { NULL } }; #undef ROFF const field_t cntbt_hfld[] = { { "", FLDT_CNTBT, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t cntbt_crc_hfld[] = { { "", FLDT_CNTBT_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f)) const field_t cntbt_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_CNTBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_CNTBT }, { "recs", FLDT_CNTBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_CNTBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_CNTBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_CNTBT }, { NULL } }; const field_t cntbt_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_CNTBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_CNTBT }, { "bno", FLDT_DFSBNO, OI(OFF(u.s.bb_blkno)), C1, 0, TYP_CNTBT }, { "lsn", FLDT_UINT64X, OI(OFF(u.s.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.s.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_AGNUMBER, OI(OFF(u.s.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.s.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_CNTBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_CNTBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_CNTBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_CNTBT }, { NULL } }; #undef OFF #define KOFF(f) bitize(offsetof(xfs_alloc_key_t, ar_ ## f)) const field_t cntbt_key_flds[] = { { "blockcount", FLDT_EXTLEN, OI(KOFF(blockcount)), C1, 0, TYP_NONE }, { "startblock", FLDT_AGBLOCK, OI(KOFF(startblock)), C1, 0, TYP_DATA }, { NULL } }; #undef KOFF #define ROFF(f) bitize(offsetof(xfs_alloc_rec_t, ar_ ## f)) const field_t cntbt_rec_flds[] = { { "startblock", FLDT_AGBLOCK, OI(ROFF(startblock)), C1, 0, TYP_DATA }, { "blockcount", FLDT_EXTLEN, OI(ROFF(blockcount)), C1, 0, TYP_NONE }, { NULL } }; #undef ROFF /* RMAP btree blocks */ const field_t rmapbt_crc_hfld[] = { { "", FLDT_RMAPBT_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f)) const field_t rmapbt_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_RMAPBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_RMAPBT }, { "bno", FLDT_DFSBNO, OI(OFF(u.s.bb_blkno)), C1, 0, TYP_RMAPBT }, { "lsn", FLDT_UINT64X, OI(OFF(u.s.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.s.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_AGNUMBER, OI(OFF(u.s.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.s.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_RMAPBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_RMAPBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_RMAPBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_RMAPBT }, { NULL } }; #undef OFF #define KOFF(f) bitize(offsetof(struct xfs_rmap_key, rm_ ## f)) #define RMAPBK_STARTBLOCK_BITOFF 0 #define RMAPBK_OWNER_BITOFF (RMAPBK_STARTBLOCK_BITOFF + RMAPBT_STARTBLOCK_BITLEN) #define RMAPBK_ATTRFLAG_BITOFF (RMAPBK_OWNER_BITOFF + RMAPBT_OWNER_BITLEN) #define RMAPBK_BMBTFLAG_BITOFF (RMAPBK_ATTRFLAG_BITOFF + RMAPBT_ATTRFLAG_BITLEN) #define RMAPBK_EXNTFLAG_BITOFF (RMAPBK_BMBTFLAG_BITOFF + RMAPBT_BMBTFLAG_BITLEN) #define RMAPBK_UNUSED_OFFSET_BITOFF (RMAPBK_EXNTFLAG_BITOFF + RMAPBT_EXNTFLAG_BITLEN) #define RMAPBK_OFFSET_BITOFF (RMAPBK_UNUSED_OFFSET_BITOFF + RMAPBT_UNUSED_OFFSET_BITLEN) #define HI_KOFF(f) bitize(sizeof(struct xfs_rmap_key) + offsetof(struct xfs_rmap_key, rm_ ## f)) #define RMAPBK_STARTBLOCKHI_BITOFF (bitize(sizeof(struct xfs_rmap_key))) #define RMAPBK_OWNERHI_BITOFF (RMAPBK_STARTBLOCKHI_BITOFF + RMAPBT_STARTBLOCK_BITLEN) #define RMAPBK_ATTRFLAGHI_BITOFF (RMAPBK_OWNERHI_BITOFF + RMAPBT_OWNER_BITLEN) #define RMAPBK_BMBTFLAGHI_BITOFF (RMAPBK_ATTRFLAGHI_BITOFF + RMAPBT_ATTRFLAG_BITLEN) #define RMAPBK_EXNTFLAGHI_BITOFF (RMAPBK_BMBTFLAGHI_BITOFF + RMAPBT_BMBTFLAG_BITLEN) #define RMAPBK_UNUSED_OFFSETHI_BITOFF (RMAPBK_EXNTFLAGHI_BITOFF + RMAPBT_EXNTFLAG_BITLEN) #define RMAPBK_OFFSETHI_BITOFF (RMAPBK_UNUSED_OFFSETHI_BITOFF + RMAPBT_UNUSED_OFFSET_BITLEN) const field_t rmapbt_key_flds[] = { { "startblock", FLDT_AGBLOCK, OI(KOFF(startblock)), C1, 0, TYP_DATA }, { "owner", FLDT_INT64D, OI(KOFF(owner)), C1, 0, TYP_NONE }, { "offset", FLDT_RFILEOFFD, OI(RMAPBK_OFFSET_BITOFF), C1, 0, TYP_NONE }, { "attrfork", FLDT_RATTRFORKFLG, OI(RMAPBK_ATTRFLAG_BITOFF), C1, 0, TYP_NONE }, { "bmbtblock", FLDT_RBMBTFLG, OI(RMAPBK_BMBTFLAG_BITOFF), C1, 0, TYP_NONE }, { "startblock_hi", FLDT_AGBLOCK, OI(HI_KOFF(startblock)), C1, 0, TYP_DATA }, { "owner_hi", FLDT_INT64D, OI(HI_KOFF(owner)), C1, 0, TYP_NONE }, { "offset_hi", FLDT_RFILEOFFD, OI(RMAPBK_OFFSETHI_BITOFF), C1, 0, TYP_NONE }, { "attrfork_hi", FLDT_RATTRFORKFLG, OI(RMAPBK_ATTRFLAGHI_BITOFF), C1, 0, TYP_NONE }, { "bmbtblock_hi", FLDT_RBMBTFLG, OI(RMAPBK_BMBTFLAGHI_BITOFF), C1, 0, TYP_NONE }, { NULL } }; #undef HI_KOFF #undef KOFF #define RMAPBT_STARTBLOCK_BITOFF 0 #define RMAPBT_BLOCKCOUNT_BITOFF (RMAPBT_STARTBLOCK_BITOFF + RMAPBT_STARTBLOCK_BITLEN) #define RMAPBT_OWNER_BITOFF (RMAPBT_BLOCKCOUNT_BITOFF + RMAPBT_BLOCKCOUNT_BITLEN) #define RMAPBT_ATTRFLAG_BITOFF (RMAPBT_OWNER_BITOFF + RMAPBT_OWNER_BITLEN) #define RMAPBT_BMBTFLAG_BITOFF (RMAPBT_ATTRFLAG_BITOFF + RMAPBT_ATTRFLAG_BITLEN) #define RMAPBT_EXNTFLAG_BITOFF (RMAPBT_BMBTFLAG_BITOFF + RMAPBT_BMBTFLAG_BITLEN) #define RMAPBT_UNUSED_OFFSET_BITOFF (RMAPBT_EXNTFLAG_BITOFF + RMAPBT_EXNTFLAG_BITLEN) #define RMAPBT_OFFSET_BITOFF (RMAPBT_UNUSED_OFFSET_BITOFF + RMAPBT_UNUSED_OFFSET_BITLEN) const field_t rmapbt_rec_flds[] = { { "startblock", FLDT_AGBLOCK, OI(RMAPBT_STARTBLOCK_BITOFF), C1, 0, TYP_DATA }, { "blockcount", FLDT_REXTLEN, OI(RMAPBT_BLOCKCOUNT_BITOFF), C1, 0, TYP_NONE }, { "owner", FLDT_INT64D, OI(RMAPBT_OWNER_BITOFF), C1, 0, TYP_NONE }, { "offset", FLDT_RFILEOFFD, OI(RMAPBT_OFFSET_BITOFF), C1, 0, TYP_NONE }, { "extentflag", FLDT_REXTFLG, OI(RMAPBT_EXNTFLAG_BITOFF), C1, 0, TYP_NONE }, { "attrfork", FLDT_RATTRFORKFLG, OI(RMAPBT_ATTRFLAG_BITOFF), C1, 0, TYP_NONE }, { "bmbtblock", FLDT_RBMBTFLG, OI(RMAPBT_BMBTFLAG_BITOFF), C1, 0, TYP_NONE }, { NULL } }; /* refcount btree blocks */ const field_t refcbt_crc_hfld[] = { { "", FLDT_REFCBT_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f)) const field_t refcbt_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, { "leftsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_leftsib)), C1, 0, TYP_REFCBT }, { "rightsib", FLDT_AGBLOCK, OI(OFF(u.s.bb_rightsib)), C1, 0, TYP_REFCBT }, { "bno", FLDT_DFSBNO, OI(OFF(u.s.bb_blkno)), C1, 0, TYP_REFCBT }, { "lsn", FLDT_UINT64X, OI(OFF(u.s.bb_lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(u.s.bb_uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_AGNUMBER, OI(OFF(u.s.bb_owner)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(u.s.bb_crc)), C1, 0, TYP_NONE }, { "recs", FLDT_REFCBTREC, btblock_rec_offset, btblock_rec_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "keys", FLDT_REFCBTKEY, btblock_key_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "ptrs", FLDT_REFCBTPTR, btblock_ptr_offset, btblock_key_count, FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_REFCBT }, { NULL } }; #undef OFF #define REFCNTBT_COWFLAG_BITOFF 0 #define REFCNTBT_STARTBLOCK_BITOFF (REFCNTBT_COWFLAG_BITOFF + REFCNTBT_COWFLAG_BITLEN) const field_t refcbt_key_flds[] = { { "startblock", FLDT_CAGBLOCK, OI(REFCNTBT_STARTBLOCK_BITOFF), C1, 0, TYP_DATA }, { "cowflag", FLDT_CCOWFLG, OI(REFCNTBT_COWFLAG_BITOFF), C1, 0, TYP_DATA }, { NULL } }; #define ROFF(f) bitize(offsetof(struct xfs_refcount_rec, rc_ ## f)) const field_t refcbt_rec_flds[] = { { "startblock", FLDT_CAGBLOCK, OI(REFCNTBT_STARTBLOCK_BITOFF), C1, 0, TYP_DATA }, { "blockcount", FLDT_EXTLEN, OI(ROFF(blockcount)), C1, 0, TYP_NONE }, { "refcount", FLDT_UINT32D, OI(ROFF(refcount)), C1, 0, TYP_DATA }, { "cowflag", FLDT_CCOWFLG, OI(REFCNTBT_COWFLAG_BITOFF), C1, 0, TYP_DATA }, { NULL } }; #undef ROFF xfsprogs-5.3.0/db/btblock.h0000644000175000017500000000370713435336036015437 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field bmapbta_flds[]; extern const struct field bmapbta_hfld[]; extern const struct field bmapbta_crc_flds[]; extern const struct field bmapbta_crc_hfld[]; extern const struct field bmapbta_key_flds[]; extern const struct field bmapbta_rec_flds[]; extern const struct field bmapbtd_flds[]; extern const struct field bmapbtd_hfld[]; extern const struct field bmapbtd_crc_flds[]; extern const struct field bmapbtd_crc_hfld[]; extern const struct field bmapbtd_key_flds[]; extern const struct field bmapbtd_rec_flds[]; extern const struct field inobt_flds[]; extern const struct field inobt_hfld[]; extern const struct field inobt_crc_flds[]; extern const struct field inobt_spcrc_flds[]; extern const struct field inobt_crc_hfld[]; extern const struct field inobt_spcrc_hfld[]; extern const struct field inobt_key_flds[]; extern const struct field inobt_rec_flds[]; extern const struct field inobt_sprec_flds[]; extern const struct field bnobt_flds[]; extern const struct field bnobt_hfld[]; extern const struct field bnobt_crc_flds[]; extern const struct field bnobt_crc_hfld[]; extern const struct field bnobt_key_flds[]; extern const struct field bnobt_rec_flds[]; extern const struct field cntbt_flds[]; extern const struct field cntbt_hfld[]; extern const struct field cntbt_crc_flds[]; extern const struct field cntbt_crc_hfld[]; extern const struct field cntbt_key_flds[]; extern const struct field cntbt_rec_flds[]; extern const struct field rmapbt_crc_flds[]; extern const struct field rmapbt_crc_hfld[]; extern const struct field rmapbt_key_flds[]; extern const struct field rmapbt_rec_flds[]; extern const struct field refcbt_crc_flds[]; extern const struct field refcbt_crc_hfld[]; extern const struct field refcbt_key_flds[]; extern const struct field refcbt_rec_flds[]; extern int btblock_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/btdump.c0000644000175000017500000002463713435336036015312 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs.h" #include "command.h" #include "output.h" #include "init.h" #include "io.h" #include "type.h" #include "input.h" static void btdump_help(void) { dbprintf(_( "\n" " If the cursor points to a btree block, 'btdump' dumps the btree\n" " downward from that block. If the cursor points to an inode,\n" " the data fork btree root is selected by default. If the cursor\n" " points to a directory or extended attribute btree node, the tree\n" " will be printed downward from that block.\n" "\n" " Options:\n" " -a -- Display an inode's extended attribute fork btree.\n" " -i -- Print internal btree nodes.\n" "\n" )); } static int eval( const char *fmt, ...) { va_list ap; char buf[PATH_MAX]; char **v; int c; int ret; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); v = breakline(buf, &c); ret = command(c, v); free(v); return ret; } static bool btblock_has_rightsib( struct xfs_btree_block *block, bool long_format) { if (long_format) return block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK); return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK); } static int dump_btlevel( int level, bool long_format) { xfs_daddr_t orig_daddr = iocur_top->bb; xfs_daddr_t last_daddr; unsigned int nr; int ret = 0; push_cur_and_set_type(); nr = 1; do { last_daddr = iocur_top->bb; dbprintf(_("%s level %u block %u daddr %llu\n"), iocur_top->typ->name, level, nr, last_daddr); if (level > 0) { ret = eval("print keys"); if (ret) goto err; ret = eval("print ptrs"); } else { ret = eval("print recs"); } if (ret) goto err; if (btblock_has_rightsib(iocur_top->data, long_format)) { ret = eval("addr rightsib"); if (ret) goto err; } nr++; } while (iocur_top->bb != orig_daddr && iocur_top->bb != last_daddr); err: pop_cur(); return ret; } static int dump_btree( bool dump_node_blocks, bool long_format) { xfs_daddr_t orig_daddr = iocur_top->bb; xfs_daddr_t last_daddr; int level; int ret = 0; push_cur_and_set_type(); cur_agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb)); level = xfs_btree_get_level(iocur_top->data); do { last_daddr = iocur_top->bb; if (level > 0) { if (dump_node_blocks) { ret = dump_btlevel(level, long_format); if (ret) goto err; } ret = eval("addr ptrs[1]"); } else { ret = dump_btlevel(level, long_format); } if (ret) goto err; level--; } while (level >= 0 && iocur_top->bb != orig_daddr && iocur_top->bb != last_daddr); err: pop_cur(); return ret; } static inline int dump_btree_short(bool dump_node_blocks) { return dump_btree(dump_node_blocks, false); } static inline int dump_btree_long(bool dump_node_blocks) { return dump_btree(dump_node_blocks, true); } static int dump_inode( bool dump_node_blocks, bool attrfork) { char *prefix; struct xfs_dinode *dip; int ret = 0; if (attrfork) prefix = "a.bmbt"; else if (xfs_sb_version_hascrc(&mp->m_sb)) prefix = "u3.bmbt"; else prefix = "u.bmbt"; dip = iocur_top->data; if (attrfork) { if (!dip->di_anextents || dip->di_aformat != XFS_DINODE_FMT_BTREE) { dbprintf(_("attr fork not in btree format\n")); return 0; } } else { if (!dip->di_nextents || dip->di_format != XFS_DINODE_FMT_BTREE) { dbprintf(_("data fork not in btree format\n")); return 0; } } push_cur_and_set_type(); if (dump_node_blocks) { ret = eval("print %s.keys", prefix); if (ret) goto err; ret = eval("print %s.ptrs", prefix); if (ret) goto err; } ret = eval("addr %s.ptrs[1]", prefix); if (ret) goto err; ret = dump_btree_long(dump_node_blocks); if (ret) goto err; err: pop_cur(); return ret; } static bool dir_has_rightsib( void *block, int level) { struct xfs_dir3_icleaf_hdr lhdr; struct xfs_da3_icnode_hdr nhdr; if (level > 0) { M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block); return nhdr.forw != 0; } M_DIROPS(mp)->leaf_hdr_from_disk(&lhdr, block); return lhdr.forw != 0; } static int dir_level( void *block) { struct xfs_dir3_icleaf_hdr lhdr; struct xfs_da3_icnode_hdr nhdr; switch (((struct xfs_da_intnode *)block)->hdr.info.magic) { case cpu_to_be16(XFS_DIR2_LEAF1_MAGIC): case cpu_to_be16(XFS_DIR2_LEAFN_MAGIC): M_DIROPS(mp)->leaf_hdr_from_disk(&lhdr, block); return 0; case cpu_to_be16(XFS_DA_NODE_MAGIC): M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block); return nhdr.level; default: return -1; } } static int dir3_level( void *block) { struct xfs_dir3_icleaf_hdr lhdr; struct xfs_da3_icnode_hdr nhdr; switch (((struct xfs_da_intnode *)block)->hdr.info.magic) { case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC): case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC): M_DIROPS(mp)->leaf_hdr_from_disk(&lhdr, block); return 0; case cpu_to_be16(XFS_DA3_NODE_MAGIC): M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block); return nhdr.level; default: return -1; } } static bool attr_has_rightsib( void *block, int level) { struct xfs_attr_leafblock lhdr; struct xfs_da3_icnode_hdr nhdr; if (level > 0) { M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block); return nhdr.forw != 0; } xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, &lhdr, block); return lhdr.hdr.info.forw != 0; } static int attr_level( void *block) { struct xfs_attr_leafblock lhdr; struct xfs_da3_icnode_hdr nhdr; switch (((struct xfs_da_intnode *)block)->hdr.info.magic) { case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, &lhdr, block); return 0; case cpu_to_be16(XFS_DA_NODE_MAGIC): M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block); return nhdr.level; default: return -1; } } static int attr3_level( void *block) { struct xfs_attr_leafblock lhdr; struct xfs_da3_icnode_hdr nhdr; switch (((struct xfs_da_intnode *)block)->hdr.info.magic) { case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, &lhdr, block); return 0; case cpu_to_be16(XFS_DA3_NODE_MAGIC): M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block); return nhdr.level; default: return -1; } } struct dabprinter_ops { const char *print_node_entries; const char *print_leaf_entries; const char *go_node_forward; const char *go_leaf_forward; const char *go_down; bool (*has_rightsib)(void *, int); int (*level)(void *); }; static struct dabprinter_ops attr_print = { .print_node_entries = "btree", .print_leaf_entries = "entries nvlist", .go_node_forward = "hdr.info.forw", .go_leaf_forward = "hdr.info.forw", .go_down = "btree[0].before", .has_rightsib = attr_has_rightsib, .level = attr_level, }; static struct dabprinter_ops attr3_print = { .print_node_entries = "btree", .print_leaf_entries = "entries nvlist", .go_node_forward = "hdr.info.hdr.forw", .go_leaf_forward = "hdr.info.hdr.forw", .go_down = "btree[0].before", .has_rightsib = attr_has_rightsib, .level = attr3_level, }; static struct dabprinter_ops dir_print = { .print_node_entries = "nbtree", .print_leaf_entries = "lents", .go_node_forward = "nhdr.info.hdr.forw", .go_leaf_forward = "lhdr.info.hdr.forw", .go_down = "nbtree[0].before", .has_rightsib = dir_has_rightsib, .level = dir_level, }; static struct dabprinter_ops dir3_print = { .print_node_entries = "nbtree", .print_leaf_entries = "lents", .go_node_forward = "nhdr.info.forw", .go_leaf_forward = "lhdr.info.forw", .go_down = "nbtree[0].before", .has_rightsib = dir_has_rightsib, .level = dir3_level, }; static int dump_dablevel( int level, struct dabprinter_ops *dbp) { xfs_daddr_t orig_daddr = iocur_top->bb; xfs_daddr_t last_daddr; unsigned int nr; int ret = 0; push_cur_and_set_type(); nr = 1; do { last_daddr = iocur_top->bb; dbprintf(_("%s level %u block %u daddr %llu\n"), iocur_top->typ->name, level, nr, last_daddr); ret = eval("print %s", level > 0 ? dbp->print_node_entries : dbp->print_leaf_entries); if (ret) goto err; if (dbp->has_rightsib(iocur_top->data, level)) { ret = eval("addr %s", level > 0 ? dbp->go_node_forward : dbp->go_leaf_forward); if (ret) goto err; } nr++; } while (iocur_top->bb != orig_daddr && iocur_top->bb != last_daddr); err: pop_cur(); return ret; } static int dump_dabtree( bool dump_node_blocks, struct dabprinter_ops *dbp) { xfs_daddr_t orig_daddr = iocur_top->bb; xfs_daddr_t last_daddr; int level; int ret = 0; push_cur_and_set_type(); cur_agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb)); level = dbp->level(iocur_top->data); if (level < 0) { printf(_("Current location is not part of a dir/attr btree.\n")); goto err; } do { last_daddr = iocur_top->bb; if (level > 0) { if (dump_node_blocks) { ret = dump_dablevel(level, dbp); if (ret) goto err; } ret = eval("addr %s", dbp->go_down); } else { ret = dump_dablevel(level, dbp); } if (ret) goto err; level--; } while (level >= 0 && iocur_top->bb != orig_daddr && iocur_top->bb != last_daddr); err: pop_cur(); return ret; } static int btdump_f( int argc, char **argv) { bool aflag = false; bool iflag = false; bool crc = xfs_sb_version_hascrc(&mp->m_sb); int c; if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } while ((c = getopt(argc, argv, "ai")) != EOF) { switch (c) { case 'a': aflag = true; break; case 'i': iflag = true; break; default: dbprintf(_("bad option for btdump command\n")); return 0; } } if (optind != argc) { dbprintf(_("bad options for btdump command\n")); return 0; } if (aflag && cur_typ->typnm != TYP_INODE) { dbprintf(_("attrfork flag doesn't apply here\n")); return 0; } switch (cur_typ->typnm) { case TYP_BNOBT: case TYP_CNTBT: case TYP_INOBT: case TYP_FINOBT: case TYP_RMAPBT: case TYP_REFCBT: return dump_btree_short(iflag); case TYP_BMAPBTA: case TYP_BMAPBTD: return dump_btree_long(iflag); case TYP_INODE: return dump_inode(iflag, aflag); case TYP_ATTR: return dump_dabtree(iflag, crc ? &attr3_print : &attr_print); case TYP_DIR2: return dump_dabtree(iflag, crc ? &dir3_print : &dir_print); default: dbprintf(_("type \"%s\" is not a btree type or inode\n"), cur_typ->name); return 0; } } static const cmdinfo_t btdump_cmd = { "btdump", "b", btdump_f, 0, 2, 0, "[-a] [-i]", N_("dump btree"), btdump_help }; void btdump_init(void) { add_command(&btdump_cmd); } xfsprogs-5.3.0/db/btheight.c0000644000175000017500000002021413570057155015602 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs.h" #include "command.h" #include "output.h" #include "init.h" #include "io.h" #include "type.h" #include "input.h" #include "libfrog/convert.h" static int refc_maxrecs(struct xfs_mount *mp, int blocklen, int leaf) { return libxfs_refcountbt_maxrecs(blocklen, leaf != 0); } static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf) { return libxfs_rmapbt_maxrecs(blocklen, leaf); } struct btmap { const char *tag; int (*maxrecs)(struct xfs_mount *mp, int blocklen, int leaf); } maps[] = { {"bnobt", libxfs_allocbt_maxrecs}, {"cntbt", libxfs_allocbt_maxrecs}, {"inobt", libxfs_inobt_maxrecs}, {"finobt", libxfs_inobt_maxrecs}, {"bmapbt", libxfs_bmbt_maxrecs}, {"refcountbt", refc_maxrecs}, {"rmapbt", rmap_maxrecs}, }; static void btheight_help(void) { struct btmap *m; int i; dbprintf(_( "\n" " For a given number of btree records and a btree type, report the number of\n" " records and blocks for each level of the btree, and the total btree size.\n" " The btree type must be given after the options. A raw btree geometry can\n" " be provided in the format \"record_bytes:key_bytes:ptr_bytes:header_type\"\n" " where header_type is one of \"short\", \"long\", \"shortcrc\", or \"longcrc\".\n" "\n" " Options:\n" " -b -- Override the btree block size.\n" " -n -- Number of records we want to store.\n" " -w max -- Show only the best case scenario.\n" " -w min -- Show only the worst case scenario.\n" "\n" " Supported btree types:\n" " " )); for (i = 0, m = maps; i < ARRAY_SIZE(maps); i++, m++) printf("%s ", m->tag); printf("\n"); } static void calc_height( unsigned long long nr_records, uint *records_per_block) { unsigned int level = 0; unsigned long long total_blocks = 0; unsigned long long blocks; char *levels_suffix = "s"; char *totblocks_suffix = "s"; while (nr_records) { unsigned int level_rpb = records_per_block[level != 0]; char *recs_suffix = "s"; char *blocks_suffix = "s"; blocks = (nr_records + level_rpb - 1) / level_rpb; if (nr_records == 1) recs_suffix = ""; if (blocks == 1) blocks_suffix = ""; printf(_("level %u: %llu record%s, %llu block%s\n"), level, nr_records, recs_suffix, blocks, blocks_suffix); total_blocks += blocks; nr_records = blocks == 1 ? 0 : blocks; level++; } if (level == 1) levels_suffix = ""; if (total_blocks == 1) totblocks_suffix = ""; printf(_("%u level%s, %llu block%s total\n"), level, levels_suffix, total_blocks, totblocks_suffix); } static int construct_records_per_block( char *tag, int blocksize, unsigned int *records_per_block) { char *toktag; struct btmap *m; unsigned int record_size, key_size, ptr_size; char *p; int i, ret; for (i = 0, m = maps; i < ARRAY_SIZE(maps); i++, m++) { if (!strcmp(m->tag, tag)) { records_per_block[0] = m->maxrecs(mp, blocksize, 1); records_per_block[1] = m->maxrecs(mp, blocksize, 0); return 0; } } toktag = strdup(tag); ret = -1; p = strtok(toktag, ":"); if (!p) { fprintf(stderr, _("%s: record size not found.\n"), tag); goto out; } record_size = cvt_u16(p, 0); if (errno) { perror(p); goto out; } if (record_size == 0) { fprintf(stderr, _("%s: record size cannot be zero.\n"), tag); goto out; } p = strtok(NULL, ":"); if (!p) { fprintf(stderr, _("%s: key size not found.\n"), tag); goto out; } key_size = cvt_u16(p, 0); if (errno) { perror(p); goto out; } if (key_size == 0) { fprintf(stderr, _("%s: key size cannot be zero.\n"), tag); goto out; } p = strtok(NULL, ":"); if (!p) { fprintf(stderr, _("%s: pointer size not found.\n"), tag); goto out; } ptr_size = cvt_u16(p, 0); if (errno) { perror(p); goto out; } if (ptr_size == 0) { fprintf(stderr, _("%s: pointer size cannot be zero.\n"), tag); goto out; } p = strtok(NULL, ":"); if (!p) { fprintf(stderr, _("%s: header type not found.\n"), tag); goto out; } if (!strcmp(p, "short")) blocksize -= XFS_BTREE_SBLOCK_LEN; else if (!strcmp(p, "shortcrc")) blocksize -= XFS_BTREE_SBLOCK_CRC_LEN; else if (!strcmp(p, "long")) blocksize -= XFS_BTREE_LBLOCK_LEN; else if (!strcmp(p, "longcrc")) blocksize -= XFS_BTREE_LBLOCK_CRC_LEN; else { fprintf(stderr, _("%s: unrecognized btree header type."), p); goto out; } if (record_size > blocksize) { fprintf(stderr, _("%s: record size must be less than selected block size (%u bytes).\n"), tag, blocksize); goto out; } if (key_size > blocksize) { fprintf(stderr, _("%s: key size must be less than selected block size (%u bytes).\n"), tag, blocksize); goto out; } if (ptr_size > blocksize) { fprintf(stderr, _("%s: pointer size must be less than selected block size (%u bytes).\n"), tag, blocksize); goto out; } p = strtok(NULL, ":"); if (p) { fprintf(stderr, _("%s: unrecognized raw btree geometry."), tag); goto out; } records_per_block[0] = blocksize / record_size; records_per_block[1] = blocksize / (key_size + ptr_size); ret = 0; out: free(toktag); return ret; } #define REPORT_DEFAULT (-1U) #define REPORT_MAX (1 << 0) #define REPORT_MIN (1 << 1) static void report( char *tag, unsigned int report_what, unsigned long long nr_records, unsigned int blocksize) { unsigned int records_per_block[2]; int ret; ret = construct_records_per_block(tag, blocksize, records_per_block); if (ret) return; if (report_what & REPORT_MAX) { if (records_per_block[0] < 2) { fprintf(stderr, _("%s: cannot calculate best case scenario due to leaf geometry underflow.\n"), tag); return; } if (records_per_block[1] < 4) { fprintf(stderr, _("%s: cannot calculate best case scenario due to node geometry underflow.\n"), tag); return; } printf( _("%s: best case per %u-byte block: %u records (leaf) / %u keyptrs (node)\n"), tag, blocksize, records_per_block[0], records_per_block[1]); calc_height(nr_records, records_per_block); } if (report_what & REPORT_MIN) { records_per_block[0] /= 2; records_per_block[1] /= 2; if (records_per_block[0] < 1) { fprintf(stderr, _("%s: cannot calculate worst case scenario due to leaf geometry underflow.\n"), tag); return; } if (records_per_block[1] < 2) { fprintf(stderr, _("%s: cannot calculate worst case scenario due to node geometry underflow.\n"), tag); return; } printf( _("%s: worst case per %u-byte block: %u records (leaf) / %u keyptrs (node)\n"), tag, blocksize, records_per_block[0], records_per_block[1]); calc_height(nr_records, records_per_block); } } static int btheight_f( int argc, char **argv) { long long blocksize = mp->m_sb.sb_blocksize; uint64_t nr_records = 0; int report_what = REPORT_DEFAULT; int i, c; while ((c = getopt(argc, argv, "b:n:w:")) != -1) { switch (c) { case 'b': errno = 0; blocksize = cvtnum(mp->m_sb.sb_blocksize, mp->m_sb.sb_sectsize, optarg); if (errno) { perror(optarg); return 0; } break; case 'n': nr_records = cvt_u64(optarg, 0); if (errno) { perror(optarg); return 0; } break; case 'w': if (!strcmp(optarg, "min")) report_what = REPORT_MIN; else if (!strcmp(optarg, "max")) report_what = REPORT_MAX; else { btheight_help(); return 0; } break; default: btheight_help(); return 0; } } if (nr_records == 0) { fprintf(stderr, _("Number of records must be greater than zero.\n")); return 0; } if (blocksize > INT_MAX) { fprintf(stderr, _("The largest block size this command will consider is %u bytes.\n"), INT_MAX); return 0; } if (blocksize < 128) { fprintf(stderr, _("The smallest block size this command will consider is 128 bytes.\n")); return 0; } if (argc == optind) { btheight_help(); return 0; } for (i = optind; i < argc; i++) report(argv[i], report_what, nr_records, blocksize); return 0; } static const cmdinfo_t btheight_cmd = { "btheight", "b", btheight_f, 1, -1, 0, "[-b blksz] [-n recs] [-w max|-w min] btree types...", N_("compute btree heights"), btheight_help }; void btheight_init(void) { add_command(&btheight_cmd); } xfsprogs-5.3.0/db/check.c0000644000175000017500000035763713570057155015107 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include #include "bmap.h" #include "check.h" #include "command.h" #include "io.h" #include "type.h" #include "fprint.h" #include "faddr.h" #include "field.h" #include "sb.h" #include "output.h" #include "init.h" #include "malloc.h" #include "dir2.h" typedef enum { IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA, } qtype_t; typedef enum { DBM_UNKNOWN, DBM_AGF, DBM_AGFL, DBM_AGI, DBM_ATTR, DBM_BTBMAPA, DBM_BTBMAPD, DBM_BTBNO, DBM_BTCNT, DBM_BTINO, DBM_DATA, DBM_DIR, DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE, DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP, DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB, DBM_SYMLINK, DBM_BTFINO, DBM_BTRMAP, DBM_BTREFC, DBM_RLDATA, DBM_COWDATA, DBM_NDBM } dbm_t; typedef struct inodata { struct inodata *next; nlink_t link_set; nlink_t link_add; bool isdir; bool isreflink; char security; char ilist; xfs_ino_t ino; struct inodata *parent; char *name; } inodata_t; #define MIN_INODATA_HASH_SIZE 256 #define MAX_INODATA_HASH_SIZE 65536 #define INODATA_AVG_HASH_LENGTH 8 typedef struct qinfo { xfs_qcnt_t bc; xfs_qcnt_t ic; xfs_qcnt_t rc; } qinfo_t; #define QDATA_HASH_SIZE 256 typedef struct qdata { struct qdata *next; xfs_dqid_t id; qinfo_t count; qinfo_t dq; } qdata_t; typedef struct blkent { xfs_fileoff_t startoff; int nblks; xfs_fsblock_t blks[1]; } blkent_t; #define BLKENT_SIZE(n) \ (offsetof(blkent_t, blks) + (sizeof(xfs_fsblock_t) * (n))) typedef struct blkmap { int naents; int nents; blkent_t *ents[1]; } blkmap_t; #define BLKMAP_SIZE(n) \ (offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n))) typedef struct freetab { int naents; int nents; xfs_dir2_data_off_t ents[1]; } freetab_t; #define FREETAB_SIZE(n) \ (offsetof(freetab_t, ents) + (sizeof(xfs_dir2_data_off_t) * (n))) typedef struct dirhash { struct dirhash *next; __u32 hashval; __u32 address; int seen; } dirhash_t; #define DIR_HASH_SIZE 1024 #define DIR_HASH_FUNC(h,a) (((h) ^ (a)) % DIR_HASH_SIZE) static xfs_extlen_t agffreeblks; static xfs_extlen_t agflongest; static uint64_t agf_aggr_freeblks; /* aggregate count over all */ static uint32_t agfbtreeblks; static int lazycount; static xfs_agino_t agicount; static xfs_agino_t agifreecount; static xfs_fsblock_t *blist; static int blist_size; static char **dbmap; /* really dbm_t:8 */ static dirhash_t **dirhash; static int error; static uint64_t fdblocks; static uint64_t frextents; static uint64_t icount; static uint64_t ifree; static inodata_t ***inodata; static int inodata_hash_size; static inodata_t ***inomap; static int nflag; static int pflag; static int tflag; static qdata_t **qpdata; static int qpdo; static qdata_t **qudata; static int qudo; static qdata_t **qgdata; static int qgdo; static unsigned sbversion; static int sbver_err; static int serious_error; static int sflag; static xfs_suminfo_t *sumcompute; static xfs_suminfo_t *sumfile; static const char *typename[] = { "unknown", "agf", "agfl", "agi", "attr", "btbmapa", "btbmapd", "btbno", "btcnt", "btino", "data", "dir", "free1", "free2", "freelist", "inode", "log", "missing", "quota", "rtbitmap", "rtdata", "rtfree", "rtsum", "sb", "symlink", "btfino", "btrmap", "btrefcnt", "rldata", "cowdata", NULL }; /* * Make sure typename has the same number of elements as there are DBM types. * This function isn't called anywhere; we just use it to trip up the compiler. */ static inline void check_typename(void) { BUILD_BUG_ON(ARRAY_SIZE(typename) != DBM_NDBM + 1); } static int verbose; #define CHECK_BLIST(b) (blist_size && check_blist(b)) #define CHECK_BLISTA(a,b) \ (blist_size && check_blist(XFS_AGB_TO_FSB(mp, a, b))) typedef void (*scan_lbtree_f_t)(struct xfs_btree_block *block, int level, dbm_t type, xfs_fsblock_t bno, inodata_t *id, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int isroot, typnm_t btype); typedef void (*scan_sbtree_f_t)(struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot); static void add_blist(xfs_fsblock_t bno); static void add_ilist(xfs_ino_t ino); static void addlink_inode(inodata_t *id); static void addname_inode(inodata_t *id, char *name, int namelen); static void addparent_inode(inodata_t *id, xfs_ino_t parent); static void blkent_append(blkent_t **entp, xfs_fsblock_t b, xfs_extlen_t c); static blkent_t *blkent_new(xfs_fileoff_t o, xfs_fsblock_t b, xfs_extlen_t c); static void blkent_prepend(blkent_t **entp, xfs_fsblock_t b, xfs_extlen_t c); static blkmap_t *blkmap_alloc(xfs_extnum_t); static void blkmap_free(blkmap_t *blkmap); static xfs_fsblock_t blkmap_get(blkmap_t *blkmap, xfs_fileoff_t o); static int blkmap_getn(blkmap_t *blkmap, xfs_fileoff_t o, int nb, bmap_ext_t **bmpp); static void blkmap_grow(blkmap_t **blkmapp, blkent_t **entp, blkent_t *newent); static xfs_fileoff_t blkmap_next_off(blkmap_t *blkmap, xfs_fileoff_t o, int *t); static void blkmap_set_blk(blkmap_t **blkmapp, xfs_fileoff_t o, xfs_fsblock_t b); static void blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o, xfs_fsblock_t b, xfs_extlen_t c); static void blkmap_shrink(blkmap_t *blkmap, blkent_t **entp); static int blockfree_f(int argc, char **argv); static int blockget_f(int argc, char **argv); static int blocktrash_f(int argc, char **argv); static int blockuse_f(int argc, char **argv); static int check_blist(xfs_fsblock_t bno); static void check_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type, int ignore_reflink); static int check_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, xfs_ino_t c_ino); static void check_linkcounts(xfs_agnumber_t agno); static int check_range(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len); static void check_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, dbm_t type); static int check_rinomap(xfs_rfsblock_t bno, xfs_extlen_t len, xfs_ino_t c_ino); static void check_rootdir(void); static int check_rrange(xfs_rfsblock_t bno, xfs_extlen_t len); static void check_set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type1, dbm_t type2, xfs_agnumber_t c_agno, xfs_agblock_t c_agbno); static void check_set_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, dbm_t type1, dbm_t type2); static void check_summary(void); static void checknot_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, int typemask); static void checknot_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, int typemask); static void dir_hash_add(xfs_dahash_t hash, xfs_dir2_dataptr_t addr); static void dir_hash_check(inodata_t *id, int v); static void dir_hash_done(void); static void dir_hash_init(void); static int dir_hash_see(xfs_dahash_t hash, xfs_dir2_dataptr_t addr); static inodata_t *find_inode(xfs_ino_t ino, int add); static void free_inodata(xfs_agnumber_t agno); static int init(int argc, char **argv); static char *inode_name(xfs_ino_t ino, inodata_t **ipp); static int ncheck_f(int argc, char **argv); static char *prepend_path(char *oldpath, char *parent); static xfs_ino_t process_block_dir_v2(blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id); static void process_bmbt_reclist(xfs_bmbt_rec_t *rp, int numrecs, dbm_t type, inodata_t *id, xfs_rfsblock_t *tot, blkmap_t **blkmapp); static void process_btinode(inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork); static xfs_ino_t process_data_dir_v2(int *dot, int *dotdot, inodata_t *id, int v, xfs_dablk_t dabno, freetab_t **freetabp); static xfs_dir2_data_free_t *process_data_dir_v2_freefind( struct xfs_dir2_data_hdr *data, struct xfs_dir2_data_unused *dup); static void process_dir(xfs_dinode_t *dip, blkmap_t *blkmap, inodata_t *id); static int process_dir_v2(xfs_dinode_t *dip, blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id, xfs_ino_t *parent); static void process_exinode(inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork); static void process_inode(xfs_agf_t *agf, xfs_agino_t agino, xfs_dinode_t *dip, int isfree); static void process_lclinode(inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork); static xfs_ino_t process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id, xfs_fsize_t dirsize); static void process_leaf_node_dir_v2_free(inodata_t *id, int v, xfs_dablk_t dbno, freetab_t *freetab); static void process_leaf_node_dir_v2_int(inodata_t *id, int v, xfs_dablk_t dbno, freetab_t *freetab); static void process_quota(qtype_t qtype, inodata_t *id, blkmap_t *blkmap); static void process_rtbitmap(blkmap_t *blkmap); static void process_rtsummary(blkmap_t *blkmap); static xfs_ino_t process_sf_dir_v2(xfs_dinode_t *dip, int *dot, int *dotdot, inodata_t *id); static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u, int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, xfs_qcnt_t rc); static void quota_add1(qdata_t **qt, xfs_dqid_t id, int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, xfs_qcnt_t rc); static void quota_check(char *s, qdata_t **qt); static void quota_init(void); static void scan_ag(xfs_agnumber_t agno); static void scan_freelist(xfs_agf_t *agf); static void scan_lbtree(xfs_fsblock_t root, int nlevels, scan_lbtree_f_t func, dbm_t type, inodata_t *id, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int isroot, typnm_t btype); static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, int nlevels, int isroot, scan_sbtree_f_t func, typnm_t btype); static void scanfunc_bmap(struct xfs_btree_block *block, int level, dbm_t type, xfs_fsblock_t bno, inodata_t *id, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int isroot, typnm_t btype); static void scanfunc_bno(struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot); static void scanfunc_cnt(struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot); static void scanfunc_ino(struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot); static void scanfunc_fino(struct xfs_btree_block *block, int level, struct xfs_agf *agf, xfs_agblock_t bno, int isroot); static void scanfunc_rmap(struct xfs_btree_block *block, int level, struct xfs_agf *agf, xfs_agblock_t bno, int isroot); static void scanfunc_refcnt(struct xfs_btree_block *block, int level, struct xfs_agf *agf, xfs_agblock_t bno, int isroot); static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type, xfs_agnumber_t c_agno, xfs_agblock_t c_agbno); static void set_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, inodata_t *id); static void set_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, dbm_t type); static void set_rinomap(xfs_rfsblock_t bno, xfs_extlen_t len, inodata_t *id); static void setlink_inode(inodata_t *id, nlink_t nlink, int isdir, int security); static const cmdinfo_t blockfree_cmd = { "blockfree", NULL, blockfree_f, 0, 0, 0, NULL, N_("free block usage information"), NULL }; static const cmdinfo_t blockget_cmd = { "blockget", "check", blockget_f, 0, -1, 0, N_("[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..."), N_("get block usage and check consistency"), NULL }; static const cmdinfo_t blocktrash_cmd = { "blocktrash", NULL, blocktrash_f, 0, -1, 0, N_("[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..."), N_("trash randomly selected block(s)"), NULL }; static const cmdinfo_t blockuse_cmd = { "blockuse", NULL, blockuse_f, 0, 3, 0, N_("[-n] [-c blockcount]"), N_("print usage for current block(s)"), NULL }; static const cmdinfo_t ncheck_cmd = { "ncheck", NULL, ncheck_f, 0, -1, 0, N_("[-s] [-i ino] ..."), N_("print inode-name pairs"), NULL }; static void add_blist( xfs_fsblock_t bno) { blist_size++; blist = xrealloc(blist, blist_size * sizeof(bno)); blist[blist_size - 1] = bno; } static void add_ilist( xfs_ino_t ino) { inodata_t *id; id = find_inode(ino, 1); if (id == NULL) { dbprintf(_("-i %lld bad inode number\n"), ino); return; } id->ilist = 1; } static void addlink_inode( inodata_t *id) { id->link_add++; if (verbose || id->ilist) dbprintf(_("inode %lld add link, now %u\n"), id->ino, id->link_add); } static void addname_inode( inodata_t *id, char *name, int namelen) { if (!nflag || id->name) return; id->name = xmalloc(namelen + 1); memcpy(id->name, name, namelen); id->name[namelen] = '\0'; } static void addparent_inode( inodata_t *id, xfs_ino_t parent) { inodata_t *pid; pid = find_inode(parent, 1); id->parent = pid; if (verbose || id->ilist || (pid && pid->ilist)) dbprintf(_("inode %lld parent %lld\n"), id->ino, parent); } static void blkent_append( blkent_t **entp, xfs_fsblock_t b, xfs_extlen_t c) { blkent_t *ent; int i; ent = *entp; *entp = ent = xrealloc(ent, BLKENT_SIZE(c + ent->nblks)); for (i = 0; i < c; i++) ent->blks[ent->nblks + i] = b + i; ent->nblks += c; } static blkent_t * blkent_new( xfs_fileoff_t o, xfs_fsblock_t b, xfs_extlen_t c) { blkent_t *ent; int i; ent = xmalloc(BLKENT_SIZE(c)); ent->nblks = c; ent->startoff = o; for (i = 0; i < c; i++) ent->blks[i] = b + i; return ent; } static void blkent_prepend( blkent_t **entp, xfs_fsblock_t b, xfs_extlen_t c) { int i; blkent_t *newent; blkent_t *oldent; oldent = *entp; newent = xmalloc(BLKENT_SIZE(oldent->nblks + c)); newent->nblks = oldent->nblks + c; newent->startoff = oldent->startoff - c; for (i = 0; i < c; i++) newent->blks[i] = b + c; for (; i < oldent->nblks + c; i++) newent->blks[i] = oldent->blks[i - c]; xfree(oldent); *entp = newent; } static blkmap_t * blkmap_alloc( xfs_extnum_t nex) { blkmap_t *blkmap; if (nex < 1) nex = 1; blkmap = xmalloc(BLKMAP_SIZE(nex)); blkmap->naents = nex; blkmap->nents = 0; return blkmap; } static void blkmap_free( blkmap_t *blkmap) { blkent_t **entp; xfs_extnum_t i; for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) xfree(*entp); xfree(blkmap); } static xfs_fsblock_t blkmap_get( blkmap_t *blkmap, xfs_fileoff_t o) { blkent_t *ent; blkent_t **entp; int i; for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) { ent = *entp; if (o >= ent->startoff && o < ent->startoff + ent->nblks) return ent->blks[o - ent->startoff]; } return NULLFSBLOCK; } static int blkmap_getn( blkmap_t *blkmap, xfs_fileoff_t o, int nb, bmap_ext_t **bmpp) { bmap_ext_t *bmp; blkent_t *ent; xfs_fileoff_t ento; blkent_t **entp; int i; int nex; for (i = nex = 0, bmp = NULL, entp = blkmap->ents; i < blkmap->nents; i++, entp++) { ent = *entp; if (ent->startoff >= o + nb) break; if (ent->startoff + ent->nblks <= o) continue; for (ento = ent->startoff; ento < ent->startoff + ent->nblks && ento < o + nb; ento++) { if (ento < o) continue; if (bmp && bmp[nex - 1].startoff + bmp[nex - 1].blockcount == ento && bmp[nex - 1].startblock + bmp[nex - 1].blockcount == ent->blks[ento - ent->startoff]) bmp[nex - 1].blockcount++; else { bmp = realloc(bmp, ++nex * sizeof(*bmp)); bmp[nex - 1].startoff = ento; bmp[nex - 1].startblock = ent->blks[ento - ent->startoff]; bmp[nex - 1].blockcount = 1; bmp[nex - 1].flag = 0; } } } *bmpp = bmp; return nex; } static void blkmap_grow( blkmap_t **blkmapp, blkent_t **entp, blkent_t *newent) { blkmap_t *blkmap; int i; int idx; blkmap = *blkmapp; idx = (int)(entp - blkmap->ents); if (blkmap->naents == blkmap->nents) { blkmap = xrealloc(blkmap, BLKMAP_SIZE(blkmap->nents + 1)); *blkmapp = blkmap; blkmap->naents++; } for (i = blkmap->nents; i > idx; i--) blkmap->ents[i] = blkmap->ents[i - 1]; blkmap->ents[idx] = newent; blkmap->nents++; } static xfs_fileoff_t blkmap_last_off( blkmap_t *blkmap) { blkent_t *ent; if (!blkmap->nents) return NULLFILEOFF; ent = blkmap->ents[blkmap->nents - 1]; return ent->startoff + ent->nblks; } static xfs_fileoff_t blkmap_next_off( blkmap_t *blkmap, xfs_fileoff_t o, int *t) { blkent_t *ent; blkent_t **entp; if (!blkmap->nents) return NULLFILEOFF; if (o == NULLFILEOFF) { *t = 0; ent = blkmap->ents[0]; return ent->startoff; } entp = &blkmap->ents[*t]; ent = *entp; if (o < ent->startoff + ent->nblks - 1) return o + 1; entp++; if (entp >= &blkmap->ents[blkmap->nents]) return NULLFILEOFF; (*t)++; ent = *entp; return ent->startoff; } static void blkmap_set_blk( blkmap_t **blkmapp, xfs_fileoff_t o, xfs_fsblock_t b) { blkmap_t *blkmap; blkent_t *ent; blkent_t **entp; blkent_t *nextent; blkmap = *blkmapp; for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) { ent = *entp; if (o < ent->startoff - 1) { ent = blkent_new(o, b, 1); blkmap_grow(blkmapp, entp, ent); return; } if (o == ent->startoff - 1) { blkent_prepend(entp, b, 1); return; } if (o >= ent->startoff && o < ent->startoff + ent->nblks) { ent->blks[o - ent->startoff] = b; return; } if (o > ent->startoff + ent->nblks) continue; blkent_append(entp, b, 1); if (entp == &blkmap->ents[blkmap->nents - 1]) return; ent = *entp; nextent = entp[1]; if (ent->startoff + ent->nblks < nextent->startoff) return; blkent_append(entp, nextent->blks[0], nextent->nblks); blkmap_shrink(blkmap, &entp[1]); return; } ent = blkent_new(o, b, 1); blkmap_grow(blkmapp, entp, ent); } static void blkmap_set_ext( blkmap_t **blkmapp, xfs_fileoff_t o, xfs_fsblock_t b, xfs_extlen_t c) { blkmap_t *blkmap; blkent_t *ent; blkent_t **entp; xfs_extnum_t i; blkmap = *blkmapp; if (!blkmap->nents) { blkmap->ents[0] = blkent_new(o, b, c); blkmap->nents = 1; return; } entp = &blkmap->ents[blkmap->nents - 1]; ent = *entp; if (ent->startoff + ent->nblks == o) { blkent_append(entp, b, c); return; } if (ent->startoff + ent->nblks < o) { ent = blkent_new(o, b, c); blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent); return; } for (i = 0; i < c; i++) blkmap_set_blk(blkmapp, o + i, b + i); } static void blkmap_shrink( blkmap_t *blkmap, blkent_t **entp) { int i; int idx; xfree(*entp); idx = (int)(entp - blkmap->ents); for (i = idx + 1; i < blkmap->nents; i++) blkmap->ents[i] = blkmap->ents[i - 1]; blkmap->nents--; } /* ARGSUSED */ static int blockfree_f( int argc, char **argv) { xfs_agnumber_t c; int rt; if (!dbmap) { dbprintf(_("block usage information not allocated\n")); return 0; } rt = mp->m_sb.sb_rextents != 0; for (c = 0; c < mp->m_sb.sb_agcount; c++) { xfree(dbmap[c]); xfree(inomap[c]); free_inodata(c); } if (rt) { xfree(dbmap[c]); xfree(inomap[c]); xfree(sumcompute); xfree(sumfile); sumcompute = sumfile = NULL; } xfree(dbmap); xfree(inomap); xfree(inodata); dbmap = NULL; inomap = NULL; inodata = NULL; return 0; } /* * Check consistency of xfs filesystem contents. */ static int blockget_f( int argc, char **argv) { xfs_agnumber_t agno; int oldprefix; int sbyell; if (dbmap) { dbprintf(_("already have block usage information\n")); return 0; } if (!init(argc, argv)) { if (serious_error) exitcode = 3; else exitcode = 1; return 0; } oldprefix = dbprefix; dbprefix |= pflag; for (agno = 0, sbyell = 0; agno < mp->m_sb.sb_agcount; agno++) { scan_ag(agno); if (sbver_err > 4 && !sbyell && sbver_err >= agno) { sbyell = 1; dbprintf(_("WARNING: this may be a newer XFS " "filesystem.\n")); } } if (blist_size) { xfree(blist); blist = NULL; blist_size = 0; } if (serious_error) { exitcode = 2; dbprefix = oldprefix; return 0; } check_rootdir(); /* * Check that there are no blocks either * a) unaccounted for or * b) bno-free but not cnt-free */ if (!tflag) { /* are we in test mode, faking out freespace? */ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) checknot_dbmap(agno, 0, mp->m_sb.sb_agblocks, (1 << DBM_UNKNOWN) | (1 << DBM_FREE1)); } for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) check_linkcounts(agno); if (mp->m_sb.sb_rblocks) { checknot_rdbmap(0, (xfs_extlen_t)(mp->m_sb.sb_rextents * mp->m_sb.sb_rextsize), 1 << DBM_UNKNOWN); check_summary(); } if (mp->m_sb.sb_icount != icount) { if (!sflag) dbprintf(_("sb_icount %lld, counted %lld\n"), mp->m_sb.sb_icount, icount); error++; } if (mp->m_sb.sb_ifree != ifree) { if (!sflag) dbprintf(_("sb_ifree %lld, counted %lld\n"), mp->m_sb.sb_ifree, ifree); error++; } if (mp->m_sb.sb_fdblocks != fdblocks) { if (!sflag) dbprintf(_("sb_fdblocks %lld, counted %lld\n"), mp->m_sb.sb_fdblocks, fdblocks); error++; } if (lazycount && mp->m_sb.sb_fdblocks != agf_aggr_freeblks) { if (!sflag) dbprintf(_("sb_fdblocks %lld, aggregate AGF count %lld\n"), mp->m_sb.sb_fdblocks, agf_aggr_freeblks); error++; } if (mp->m_sb.sb_frextents != frextents) { if (!sflag) dbprintf(_("sb_frextents %lld, counted %lld\n"), mp->m_sb.sb_frextents, frextents); error++; } if (mp->m_sb.sb_bad_features2 != 0 && mp->m_sb.sb_bad_features2 != mp->m_sb.sb_features2) { if (!sflag) dbprintf(_("sb_features2 (0x%x) not same as " "sb_bad_features2 (0x%x)\n"), mp->m_sb.sb_features2, mp->m_sb.sb_bad_features2); error++; } if ((sbversion & XFS_SB_VERSION_ATTRBIT) && !xfs_sb_version_hasattr(&mp->m_sb)) { if (!sflag) dbprintf(_("sb versionnum missing attr bit %x\n"), XFS_SB_VERSION_ATTRBIT); error++; } if ((sbversion & XFS_SB_VERSION_QUOTABIT) && !xfs_sb_version_hasquota(&mp->m_sb)) { if (!sflag) dbprintf(_("sb versionnum missing quota bit %x\n"), XFS_SB_VERSION_QUOTABIT); error++; } if (!(sbversion & XFS_SB_VERSION_ALIGNBIT) && xfs_sb_version_hasalign(&mp->m_sb)) { if (!sflag) dbprintf(_("sb versionnum extra align bit %x\n"), XFS_SB_VERSION_ALIGNBIT); error++; } if (qudo) quota_check("user", qudata); if (qpdo) quota_check("project", qpdata); if (qgdo) quota_check("group", qgdata); if (sbver_err > mp->m_sb.sb_agcount / 2) dbprintf(_("WARNING: this may be a newer XFS filesystem.\n")); if (error) exitcode = 3; dbprefix = oldprefix; return 0; } typedef struct ltab { int min; int max; } ltab_t; static void blocktrash_b( int bit_offset, dbm_t type, ltab_t *ltabp, int mode) { int bit; int bitno; char *buf; int byte; int len; int mask; int newbit; const struct xfs_buf_ops *stashed_ops; static char *modestr[] = { N_("zeroed"), N_("set"), N_("flipped"), N_("randomized") }; xfs_agnumber_t agno; xfs_agblock_t agbno; agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb)); agbno = XFS_FSB_TO_AGBNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb)); if (iocur_top->len == 0) { dbprintf(_("zero-length block %u/%u buffer to trash??\n"), agno, agbno); return; } len = (int)((random() % (ltabp->max - ltabp->min + 1)) + ltabp->min); /* * bit_offset >= 0: start fuzzing at this exact bit_offset. * bit_offset < 0: pick an offset at least as high at -(bit_offset + 1). */ if (bit_offset < 0) { bit_offset = -(bit_offset + 1); bit_offset += (int)(random() % (int)((iocur_top->len - bit_offset) * NBBY)); } if (bit_offset + len >= iocur_top->len * NBBY) len = (iocur_top->len * NBBY) - bit_offset; newbit = 0; stashed_ops = iocur_top->bp->b_ops; iocur_top->bp->b_ops = NULL; if ((buf = iocur_top->data) == NULL) { dbprintf(_("can't read block %u/%u for trashing\n"), agno, agbno); return; } for (bitno = 0; bitno < len; bitno++) { bit = (bit_offset + bitno) % (mp->m_sb.sb_blocksize * NBBY); byte = bit / NBBY; bit %= NBBY; mask = 1 << bit; switch (mode) { case 0: newbit = 0; break; case 1: newbit = 1; break; case 2: newbit = (buf[byte] & mask) == 0; break; case 3: newbit = (int)random() & 1; break; } if (newbit) buf[byte] |= mask; else buf[byte] &= ~mask; } write_cur(); iocur_top->bp->b_ops = stashed_ops; printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"), agno, agbno, typename[type], len, len == 1 ? "" : "s", bit_offset / NBBY, bit_offset % NBBY, modestr[mode]); } static int blocktrash_f( int argc, char **argv) { xfs_agblock_t agbno; xfs_agnumber_t agno; xfs_rfsblock_t bi; xfs_rfsblock_t blocks; int c; int count; int done; int goodmask; int i; ltab_t *lentab; int lentablen; int max; int min; int mode; struct timeval now; char *p; xfs_rfsblock_t randb; uint seed; int sopt; int tmask; bool this_block = false; int bit_offset = -1; optind = 0; count = 1; min = 1; max = 128 * NBBY; mode = 2; gettimeofday(&now, NULL); seed = (unsigned int)(now.tv_sec ^ now.tv_usec); sopt = 0; tmask = 0; goodmask = (1 << DBM_AGF) | (1 << DBM_AGFL) | (1 << DBM_AGI) | (1 << DBM_ATTR) | (1 << DBM_BTBMAPA) | (1 << DBM_BTBMAPD) | (1 << DBM_BTBNO) | (1 << DBM_BTCNT) | (1 << DBM_BTINO) | (1 << DBM_DIR) | (1 << DBM_INODE) | (1 << DBM_LOG) | (1 << DBM_QUOTA) | (1 << DBM_RTBITMAP) | (1 << DBM_RTSUM) | (1 << DBM_SYMLINK) | (1 << DBM_BTFINO) | (1 << DBM_BTRMAP) | (1 << DBM_BTREFC) | (1 << DBM_SB); while ((c = getopt(argc, argv, "0123n:o:s:t:x:y:z")) != EOF) { switch (c) { case '0': mode = 0; break; case '1': mode = 1; break; case '2': mode = 2; break; case '3': mode = 3; break; case 'n': count = (int)strtol(optarg, &p, 0); if (*p != '\0' || count <= 0) { dbprintf(_("bad blocktrash count %s\n"), optarg); return 0; } break; case 'o': { int relative = 0; if (optarg[0] == '+') { optarg++; relative = 1; } bit_offset = (int)strtol(optarg, &p, 0); if (*p != '\0' || bit_offset < 0) { dbprintf(_("bad blocktrash offset %s\n"), optarg); return 0; } if (relative) bit_offset = -bit_offset - 1; break; } case 's': seed = (uint)strtoul(optarg, &p, 0); sopt = 1; break; case 't': for (i = 0; typename[i]; i++) { if (strcmp(typename[i], optarg) == 0) break; } if (!typename[i] || (((1 << i) & goodmask) == 0)) { dbprintf(_("bad blocktrash type %s\n"), optarg); return 0; } tmask |= 1 << i; break; case 'x': min = (int)strtol(optarg, &p, 0); if (*p != '\0' || min <= 0 || min > mp->m_sb.sb_blocksize * NBBY) { dbprintf(_("bad blocktrash min %s\n"), optarg); return 0; } break; case 'y': max = (int)strtol(optarg, &p, 0); if (*p != '\0' || max <= 0 || max > mp->m_sb.sb_blocksize * NBBY) { dbprintf(_("bad blocktrash max %s\n"), optarg); return 0; } break; case 'z': this_block = true; break; default: dbprintf(_("bad option for blocktrash command\n")); return 0; } } if (!this_block && !dbmap) { dbprintf(_("must run blockget first\n")); return 0; } if (this_block && iocur_sp == 0) { dbprintf(_("nothing on stack\n")); return 0; } if (min > max) { dbprintf(_("bad min/max for blocktrash command\n")); return 0; } if (tmask == 0) tmask = goodmask & ~((1 << DBM_LOG) | (1 << DBM_SB)); lentab = xmalloc(sizeof(ltab_t)); lentab->min = lentab->max = min; lentablen = 1; for (i = min + 1; i <= max; i++) { if ((i & (i - 1)) == 0) { lentab = xrealloc(lentab, sizeof(ltab_t) * (lentablen + 1)); lentab[lentablen].min = lentab[lentablen].max = i; lentablen++; } else lentab[lentablen - 1].max = i; } if (!sopt) dbprintf(_("blocktrash: seed %u\n"), seed); srandom(seed); if (this_block) { blocktrash_b(bit_offset, DBM_UNKNOWN, &lentab[random() % lentablen], mode); goto out; } for (blocks = 0, agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for (agbno = 0, p = dbmap[agno]; agbno < mp->m_sb.sb_agblocks; agbno++, p++) { if ((1 << *p) & tmask) blocks++; } } if (blocks == 0) { dbprintf(_("blocktrash: no matching blocks\n")); goto out; } for (i = 0; i < count; i++) { randb = (xfs_rfsblock_t)((((int64_t)random() << 32) | random()) % blocks); for (bi = 0, agno = 0, done = 0; !done && agno < mp->m_sb.sb_agcount; agno++) { for (agbno = 0, p = dbmap[agno]; agbno < mp->m_sb.sb_agblocks; agbno++, p++) { if (!((1 << *p) & tmask)) continue; if (bi++ < randb) continue; push_cur(); set_cur(NULL, XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL); blocktrash_b(bit_offset, (dbm_t)*p, &lentab[random() % lentablen], mode); pop_cur(); done = 1; break; } } } out: xfree(lentab); return 0; } static int blockuse_f( int argc, char **argv) { xfs_agblock_t agbno; xfs_agnumber_t agno; int c; int count; xfs_agblock_t end; xfs_fsblock_t fsb; inodata_t *i; char *p; int shownames; if (!dbmap) { dbprintf(_("must run blockget first\n")); return 0; } optind = 0; shownames = 0; fsb = XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT); agno = XFS_FSB_TO_AGNO(mp, fsb); end = agbno = XFS_FSB_TO_AGBNO(mp, fsb); while ((c = getopt(argc, argv, "c:n")) != EOF) { switch (c) { case 'c': count = (int)strtol(optarg, &p, 0); end = agbno + count - 1; if (*p != '\0' || count <= 0 || end >= mp->m_sb.sb_agblocks) { dbprintf(_("bad blockuse count %s\n"), optarg); return 0; } break; case 'n': if (!nflag) { dbprintf(_("must run blockget -n first\n")); return 0; } shownames = 1; break; default: dbprintf(_("bad option for blockuse command\n")); return 0; } } while (agbno <= end) { p = &dbmap[agno][agbno]; i = inomap[agno][agbno]; dbprintf(_("block %llu (%u/%u) type %s"), (xfs_fsblock_t)XFS_AGB_TO_FSB(mp, agno, agbno), agno, agbno, typename[(dbm_t)*p]); if (i) { dbprintf(_(" inode %lld"), i->ino); if (shownames && (p = inode_name(i->ino, NULL))) { dbprintf(" %s", p); xfree(p); } } dbprintf("\n"); agbno++; } return 0; } static int check_blist( xfs_fsblock_t bno) { int i; for (i = 0; i < blist_size; i++) { if (blist[i] == bno) return 1; } return 0; } static void check_dbmap( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type, int ignore_reflink) { xfs_extlen_t i; char *p; dbm_t d; for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { d = (dbm_t)*p; if (ignore_reflink && (d == DBM_UNKNOWN || d == DBM_DATA || d == DBM_RLDATA)) continue; if ((dbm_t)*p != type) { if (!sflag || CHECK_BLISTA(agno, agbno + i)) { dbprintf(_("block %u/%u expected type %s got " "%s\n"), agno, agbno + i, typename[type], typename[(dbm_t)*p]); } error++; } } } void check_init(void) { add_command(&blockfree_cmd); add_command(&blockget_cmd); if (expert_mode) add_command(&blocktrash_cmd); add_command(&blockuse_cmd); add_command(&ncheck_cmd); } static int check_inomap( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, xfs_ino_t c_ino) { xfs_extlen_t i; inodata_t **idp; int rval; if (!check_range(agno, agbno, len)) { dbprintf(_("blocks %u/%u..%u claimed by inode %lld\n"), agno, agbno, agbno + len - 1, c_ino); return 0; } for (i = 0, rval = 1, idp = &inomap[agno][agbno]; i < len; i++, idp++) { if (*idp && !(*idp)->isreflink) { if (!sflag || (*idp)->ilist || CHECK_BLISTA(agno, agbno + i)) dbprintf(_("block %u/%u claimed by inode %lld, " "previous inum %lld\n"), agno, agbno + i, c_ino, (*idp)->ino); error++; rval = 0; } } return rval; } static void check_linkcounts( xfs_agnumber_t agno) { inodata_t *ep; inodata_t **ht; int idx; char *path; ht = inodata[agno]; for (idx = 0; idx < inodata_hash_size; ht++, idx++) { ep = *ht; while (ep) { if (ep->link_set != ep->link_add || ep->link_set == 0) { path = inode_name(ep->ino, NULL); if (!path && ep->link_add) path = xstrdup("?"); if (!sflag || ep->ilist) { if (ep->link_add) dbprintf(_("link count mismatch " "for inode %lld (name " "%s), nlink %d, " "counted %d\n"), ep->ino, path, ep->link_set, ep->link_add); else if (ep->link_set) dbprintf(_("disconnected inode " "%lld, nlink %d\n"), ep->ino, ep->link_set); else dbprintf(_("allocated inode %lld " "has 0 link count\n"), ep->ino); } if (path) xfree(path); error++; } else if (verbose || ep->ilist) { path = inode_name(ep->ino, NULL); if (path) { dbprintf(_("inode %lld name %s\n"), ep->ino, path); xfree(path); } } ep = ep->next; } } } static int check_range( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len) { xfs_extlen_t i; xfs_agblock_t low = 0; xfs_agblock_t high = 0; int valid_range = 0; int cur, prev = 0; if (agno >= mp->m_sb.sb_agcount || agbno + len - 1 >= mp->m_sb.sb_agblocks) { for (i = 0; i < len; i++) { cur = !sflag || CHECK_BLISTA(agno, agbno + i) ? 1 : 0; if (cur == 1 && prev == 0) { low = high = agbno + i; valid_range = 1; } else if (cur == 0 && prev == 0) { /* Do nothing */ } else if (cur == 0 && prev == 1) { if (low == high) { dbprintf(_("block %u/%u out of range\n"), agno, low); } else { dbprintf(_("blocks %u/%u..%u " "out of range\n"), agno, low, high); } valid_range = 0; } else if (cur == 1 && prev == 1) { high = agbno + i; } prev = cur; } if (valid_range) { if (low == high) { dbprintf(_("block %u/%u out of range\n"), agno, low); } else { dbprintf(_("blocks %u/%u..%u " "out of range\n"), agno, low, high); } } error++; return 0; } return 1; } static void check_rdbmap( xfs_rfsblock_t bno, xfs_extlen_t len, dbm_t type) { xfs_extlen_t i; char *p; for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { if ((dbm_t)*p != type) { if (!sflag || CHECK_BLIST(bno + i)) dbprintf(_("rtblock %llu expected type %s got " "%s\n"), bno + i, typename[type], typename[(dbm_t)*p]); error++; } } } static int check_rinomap( xfs_rfsblock_t bno, xfs_extlen_t len, xfs_ino_t c_ino) { xfs_extlen_t i; inodata_t **idp; int rval; if (!check_rrange(bno, len)) { dbprintf(_("rtblocks %llu..%llu claimed by inode %lld\n"), bno, bno + len - 1, c_ino); return 0; } for (i = 0, rval = 1, idp = &inomap[mp->m_sb.sb_agcount][bno]; i < len; i++, idp++) { if (*idp) { if (!sflag || (*idp)->ilist || CHECK_BLIST(bno + i)) dbprintf(_("rtblock %llu claimed by inode %lld, " "previous inum %lld\n"), bno + i, c_ino, (*idp)->ino); error++; rval = 0; } } return rval; } static void check_rootdir(void) { inodata_t *id; id = find_inode(mp->m_sb.sb_rootino, 0); if (id == NULL) { if (!sflag) dbprintf(_("root inode %lld is missing\n"), mp->m_sb.sb_rootino); error++; } else if (!id->isdir) { if (!sflag || id->ilist) dbprintf(_("root inode %lld is not a directory\n"), mp->m_sb.sb_rootino); error++; } } static int check_rrange( xfs_rfsblock_t bno, xfs_extlen_t len) { xfs_extlen_t i; if (bno + len - 1 >= mp->m_sb.sb_rblocks) { for (i = 0; i < len; i++) { if (!sflag || CHECK_BLIST(bno + i)) dbprintf(_("rtblock %llu out of range\n"), bno + i); } error++; return 0; } return 1; } /* * We don't check the accuracy of reference counts -- all we do is ensure * that a data block never crosses with non-data blocks. repair can check * those kinds of things. * * So with that in mind, if we're setting a block to be data or rldata, * don't complain so long as the block is currently unknown, data, or rldata. * Don't let blocks downgrade from rldata -> data. */ static bool is_reflink( dbm_t type2) { if (!xfs_sb_version_hasreflink(&mp->m_sb)) return false; if (type2 == DBM_DATA || type2 == DBM_RLDATA) return true; return false; } static void check_set_dbmap( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type1, dbm_t type2, xfs_agnumber_t c_agno, xfs_agblock_t c_agbno) { xfs_extlen_t i; int mayprint; char *p; if (!check_range(agno, agbno, len)) { dbprintf(_("blocks %u/%u..%u claimed by block %u/%u\n"), agno, agbno, agbno + len - 1, c_agno, c_agbno); return; } check_dbmap(agno, agbno, len, type1, is_reflink(type2)); mayprint = verbose | blist_size; for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { if (*p == DBM_RLDATA && type2 == DBM_DATA) ; /* do nothing */ else if (*p == DBM_DATA && type2 == DBM_DATA) *p = (char)DBM_RLDATA; else *p = (char)type2; if (mayprint && (verbose || CHECK_BLISTA(agno, agbno + i))) dbprintf(_("setting block %u/%u to %s\n"), agno, agbno + i, typename[type2]); } } static void check_set_rdbmap( xfs_rfsblock_t bno, xfs_extlen_t len, dbm_t type1, dbm_t type2) { xfs_extlen_t i; int mayprint; char *p; if (!check_rrange(bno, len)) return; check_rdbmap(bno, len, type1); mayprint = verbose | blist_size; for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { *p = (char)type2; if (mayprint && (verbose || CHECK_BLIST(bno + i))) dbprintf(_("setting rtblock %llu to %s\n"), bno + i, typename[type2]); } } static void check_summary(void) { xfs_rfsblock_t bno; xfs_suminfo_t *csp; xfs_suminfo_t *fsp; int log; csp = sumcompute; fsp = sumfile; for (log = 0; log < mp->m_rsumlevels; log++) { for (bno = 0; bno < mp->m_sb.sb_rbmblocks; bno++, csp++, fsp++) { if (*csp != *fsp) { if (!sflag) dbprintf(_("rt summary mismatch, size %d " "block %llu, file: %d, " "computed: %d\n"), log, bno, *fsp, *csp); error++; } } } } static void checknot_dbmap( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, int typemask) { xfs_extlen_t i; char *p; if (!check_range(agno, agbno, len)) return; for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { if ((1 << *p) & typemask) { if (!sflag || CHECK_BLISTA(agno, agbno + i)) dbprintf(_("block %u/%u type %s not expected\n"), agno, agbno + i, typename[(dbm_t)*p]); error++; } } } static void checknot_rdbmap( xfs_rfsblock_t bno, xfs_extlen_t len, int typemask) { xfs_extlen_t i; char *p; if (!check_rrange(bno, len)) return; for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { if ((1 << *p) & typemask) { if (!sflag || CHECK_BLIST(bno + i)) dbprintf(_("rtblock %llu type %s not expected\n"), bno + i, typename[(dbm_t)*p]); error++; } } } static void dir_hash_add( xfs_dahash_t hash, xfs_dir2_dataptr_t addr) { int i; dirhash_t *p; i = DIR_HASH_FUNC(hash, addr); p = malloc(sizeof(*p)); p->next = dirhash[i]; dirhash[i] = p; p->hashval = hash; p->address = addr; p->seen = 0; } static void dir_hash_check( inodata_t *id, int v) { int i; dirhash_t *p; for (i = 0; i < DIR_HASH_SIZE; i++) { for (p = dirhash[i]; p; p = p->next) { if (p->seen) continue; if (!sflag || id->ilist || v) dbprintf(_("dir ino %lld missing leaf entry for " "%x/%x\n"), id->ino, p->hashval, p->address); error++; } } } static void dir_hash_done(void) { int i; dirhash_t *n; dirhash_t *p; for (i = 0; i < DIR_HASH_SIZE; i++) { for (p = dirhash[i]; p; p = n) { n = p->next; free(p); } dirhash[i] = NULL; } } static void dir_hash_init(void) { if (!dirhash) dirhash = calloc(DIR_HASH_SIZE, sizeof(*dirhash)); } static int dir_hash_see( xfs_dahash_t hash, xfs_dir2_dataptr_t addr) { int i; dirhash_t *p; i = DIR_HASH_FUNC(hash, addr); for (p = dirhash[i]; p; p = p->next) { if (p->hashval == hash && p->address == addr) { if (p->seen) return 1; p->seen = 1; return 0; } } return -1; } static inodata_t * find_inode( xfs_ino_t ino, int add) { xfs_agino_t agino; xfs_agnumber_t agno; inodata_t *ent; inodata_t **htab; xfs_agino_t ih; agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); if (agno >= mp->m_sb.sb_agcount || XFS_AGINO_TO_INO(mp, agno, agino) != ino) return NULL; htab = inodata[agno]; ih = agino % inodata_hash_size; ent = htab[ih]; while (ent) { if (ent->ino == ino) return ent; ent = ent->next; } if (!add) return NULL; ent = xcalloc(1, sizeof(*ent)); ent->ino = ino; ent->next = htab[ih]; htab[ih] = ent; return ent; } static void free_inodata( xfs_agnumber_t agno) { inodata_t *hp; inodata_t **ht; int i; inodata_t *next; ht = inodata[agno]; for (i = 0; i < inodata_hash_size; i++) { hp = ht[i]; while (hp) { next = hp->next; if (hp->name) xfree(hp->name); xfree(hp); hp = next; } } xfree(ht); } static int init( int argc, char **argv) { xfs_fsblock_t bno; int c; xfs_ino_t ino; int rt; serious_error = 0; if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) { dbprintf(_("bad superblock magic number %x, giving up\n"), mp->m_sb.sb_magicnum); serious_error = 1; return 0; } if (!sb_logcheck()) return 0; rt = mp->m_sb.sb_rextents != 0; dbmap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*dbmap)); inomap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*inomap)); inodata = xmalloc(mp->m_sb.sb_agcount * sizeof(*inodata)); inodata_hash_size = (int)max(min(mp->m_sb.sb_icount / (INODATA_AVG_HASH_LENGTH * mp->m_sb.sb_agcount), MAX_INODATA_HASH_SIZE), MIN_INODATA_HASH_SIZE); for (c = 0; c < mp->m_sb.sb_agcount; c++) { dbmap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**dbmap)); inomap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**inomap)); inodata[c] = xcalloc(inodata_hash_size, sizeof(**inodata)); } if (rt) { dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap)); inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap)); sumfile = xcalloc(mp->m_rsumsize, 1); sumcompute = xcalloc(mp->m_rsumsize, 1); } nflag = sflag = tflag = verbose = optind = 0; while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) { switch (c) { case 'b': bno = strtoll(optarg, NULL, 10); add_blist(bno); break; case 'i': ino = strtoll(optarg, NULL, 10); add_ilist(ino); break; case 'n': nflag = 1; break; case 'p': pflag = 1; break; case 's': sflag = 1; break; case 't': tflag = 1; break; case 'v': verbose = 1; break; default: dbprintf(_("bad option for blockget command\n")); return 0; } } error = sbver_err = serious_error = 0; fdblocks = frextents = icount = ifree = 0; sbversion = XFS_SB_VERSION_4; /* * Note that inoalignmt == 0 is valid when fsb size is large enough for * at least one full inode record per block. Check this case explicitly. */ if (mp->m_sb.sb_inoalignmt || (xfs_sb_version_hasalign(&mp->m_sb) && mp->m_sb.sb_inopblock >= XFS_INODES_PER_CHUNK)) sbversion |= XFS_SB_VERSION_ALIGNBIT; if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) || (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) || (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO)) sbversion |= XFS_SB_VERSION_QUOTABIT; quota_init(); return 1; } static char * inode_name( xfs_ino_t ino, inodata_t **ipp) { inodata_t *id; char *npath; char *path; id = find_inode(ino, 0); if (ipp) *ipp = id; if (id == NULL) return NULL; if (id->name == NULL) return NULL; path = xstrdup(id->name); while (id->parent) { id = id->parent; if (id->name == NULL) break; npath = prepend_path(path, id->name); xfree(path); path = npath; } return path; } static int ncheck_f( int argc, char **argv) { xfs_agnumber_t agno; int c; inodata_t *hp; inodata_t **ht; int i; inodata_t *id; xfs_ino_t *ilist; int ilist_size; xfs_ino_t *ilp; xfs_ino_t ino; char *p; int security; if (!inodata || !nflag) { dbprintf(_("must run blockget -n first\n")); return 0; } security = optind = ilist_size = 0; ilist = NULL; while ((c = getopt(argc, argv, "i:s")) != EOF) { switch (c) { case 'i': ino = strtoll(optarg, NULL, 10); ilist = xrealloc(ilist, (ilist_size + 1) * sizeof(*ilist)); ilist[ilist_size++] = ino; break; case 's': security = 1; break; default: dbprintf(_("bad option -%c for ncheck command\n"), c); xfree(ilist); return 0; } } if (ilist) { for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) { ino = *ilp; if ((p = inode_name(ino, &hp))) { dbprintf("%11llu %s", ino, p); if (hp->isdir) dbprintf("/."); dbprintf("\n"); xfree(p); } } xfree(ilist); return 0; } for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { ht = inodata[agno]; for (i = 0; i < inodata_hash_size; i++) { hp = ht[i]; for (hp = ht[i]; hp; hp = hp->next) { ino = XFS_AGINO_TO_INO(mp, agno, hp->ino); p = inode_name(ino, &id); if (!p || !id) continue; if (!security || id->security) { dbprintf("%11llu %s", ino, p); if (hp->isdir) dbprintf("/."); dbprintf("\n"); } xfree(p); } } } return 0; } static char * prepend_path( char *oldpath, char *parent) { int len; char *path; len = (int)(strlen(oldpath) + strlen(parent) + 2); path = xmalloc(len); snprintf(path, len, "%s/%s", parent, oldpath); return path; } static xfs_ino_t process_block_dir_v2( blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id) { xfs_fsblock_t b; bbmap_t bbmap; bmap_ext_t *bmp; int nex; xfs_ino_t parent; int v; int i; nex = blkmap_getn(blkmap, 0, mp->m_dir_geo->fsbcount, &bmp); v = id->ilist || verbose; if (nex == 0) { if (!sflag || v) dbprintf(_("block 0 for directory inode %lld is " "missing\n"), id->ino); error++; return 0; } push_cur(); if (nex > 1) make_bbmap(&bbmap, nex, bmp); set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock), mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL); for (i = 0; !v && i < nex; i++) { for (b = bmp[i].startblock; !v && b < bmp[i].startblock + bmp[i].blockcount; b++) v = CHECK_BLIST(b); } free(bmp); if (iocur_top->data == NULL) { if (!sflag || id->ilist || v) dbprintf(_("can't read block 0 for directory inode " "%lld\n"), id->ino); error++; pop_cur(); return 0; } dir_hash_init(); parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dir_geo->datablk, NULL); dir_hash_check(id, v); dir_hash_done(); pop_cur(); return parent; } static void process_bmbt_reclist( xfs_bmbt_rec_t *rp, int numrecs, dbm_t type, inodata_t *id, xfs_rfsblock_t *tot, blkmap_t **blkmapp) { xfs_agblock_t agbno; xfs_agnumber_t agno; xfs_fsblock_t b; xfs_filblks_t c; xfs_filblks_t cp; int f; int i; xfs_agblock_t iagbno; xfs_agnumber_t iagno; xfs_fileoff_t o; xfs_fileoff_t op; xfs_fsblock_t s; int v; cp = op = 0; v = verbose || id->ilist; iagno = XFS_INO_TO_AGNO(mp, id->ino); iagbno = XFS_INO_TO_AGBNO(mp, id->ino); for (i = 0; i < numrecs; i++, rp++) { convert_extent(rp, &o, &s, &c, &f); if (v) dbprintf(_("inode %lld extent [%lld,%lld,%lld,%d]\n"), id->ino, o, s, c, f); if (!sflag && i > 0 && op + cp > o) dbprintf(_("bmap rec out of order, inode %lld entry %d\n"), id->ino, i); op = o; cp = c; if (type == DBM_RTDATA) { if (!sflag && s >= mp->m_sb.sb_rblocks) { dbprintf(_("inode %lld bad rt block number %lld, " "offset %lld\n"), id->ino, s, o); continue; } } else if (!sflag) { agno = XFS_FSB_TO_AGNO(mp, s); agbno = XFS_FSB_TO_AGBNO(mp, s); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks) { dbprintf(_("inode %lld bad block number %lld " "[%d,%d], offset %lld\n"), id->ino, s, agno, agbno, o); continue; } if (agbno + c - 1 >= mp->m_sb.sb_agblocks) { dbprintf(_("inode %lld bad block number %lld " "[%d,%d], offset %lld\n"), id->ino, s + c - 1, agno, agbno + (xfs_agblock_t)c - 1, o); continue; } } if (blkmapp && *blkmapp) blkmap_set_ext(blkmapp, (xfs_fileoff_t)o, (xfs_fsblock_t)s, (xfs_extlen_t)c); if (type == DBM_RTDATA) { set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c, DBM_RTDATA); set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id); for (b = (xfs_fsblock_t)s; blist_size && b < s + c; b++, o++) { if (CHECK_BLIST(b)) dbprintf(_("inode %lld block %lld at " "offset %lld\n"), id->ino, (xfs_fsblock_t)b, o); } } else { agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s); agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s); set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno, iagbno); set_inomap(agno, agbno, (xfs_extlen_t)c, id); for (b = (xfs_fsblock_t)s; blist_size && b < s + c; b++, o++, agbno++) { if (CHECK_BLIST(b)) dbprintf(_("inode %lld block %lld at " "offset %lld\n"), id->ino, (xfs_fsblock_t)b, o); } } *tot += c; } } static void process_btinode( inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork) { xfs_bmdr_block_t *dib; int i; xfs_bmbt_ptr_t *pp; dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); if (be16_to_cpu(dib->bb_level) >= XFS_BM_MAXLEVELS(mp, whichfork)) { if (!sflag || id->ilist) dbprintf(_("level for ino %lld %s fork bmap root too " "large (%u)\n"), id->ino, whichfork == XFS_DATA_FORK ? _("data") : _("attr"), be16_to_cpu(dib->bb_level)); error++; return; } if (be16_to_cpu(dib->bb_numrecs) > libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), be16_to_cpu(dib->bb_level) == 0)) { if (!sflag || id->ilist) dbprintf(_("numrecs for ino %lld %s fork bmap root too " "large (%u)\n"), id->ino, whichfork == XFS_DATA_FORK ? _("data") : _("attr"), be16_to_cpu(dib->bb_numrecs)); error++; return; } if (be16_to_cpu(dib->bb_level) == 0) { xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1); process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type, id, totd, blkmapp); *nex += be16_to_cpu(dib->bb_numrecs); return; } else { pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs( XFS_DFORK_SIZE(dip, mp, whichfork), 0)); for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++) scan_lbtree(get_unaligned_be64(&pp[i]), be16_to_cpu(dib->bb_level), scanfunc_bmap, type, id, totd, toti, nex, blkmapp, 1, whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA); } if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) { if (!sflag || id->ilist) dbprintf(_("extent count for ino %lld %s fork too low " "(%d) for file format\n"), id->ino, whichfork == XFS_DATA_FORK ? _("data") : _("attr"), *nex); error++; } } static xfs_ino_t process_data_dir_v2( int *dot, int *dotdot, inodata_t *id, int v, xfs_dablk_t dabno, freetab_t **freetabp) { xfs_dir2_dataptr_t addr; xfs_dir2_data_free_t *bf; int bf_err; struct xfs_dir2_data_hdr *block; xfs_dir2_block_tail_t *btp = NULL; inodata_t *cid; int count; struct xfs_dir2_data_hdr *data; xfs_dir2_db_t db; xfs_dir2_data_entry_t *dep; xfs_dir2_data_free_t *dfp; xfs_dir2_data_unused_t *dup; char *endptr; int freeseen; freetab_t *freetab; int i; int lastfree; int lastfree_err; xfs_dir2_leaf_entry_t *lep = NULL; xfs_ino_t lino; xfs_ino_t parent = 0; char *ptr; int stale = 0; int tag_err; __be16 *tagp; struct xfs_name xname; data = iocur_top->data; block = iocur_top->data; if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC && be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC && be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC && be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) { if (!sflag || v) dbprintf(_("bad directory data magic # %#x for dir ino " "%lld block %d\n"), be32_to_cpu(data->magic), id->ino, dabno); error++; return NULLFSINO; } db = xfs_dir2_da_to_db(mp->m_dir_geo, dabno); bf = M_DIROPS(mp)->data_bestfree_p(data); ptr = (char *)M_DIROPS(mp)->data_unused_p(data); if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC) { btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); lep = xfs_dir2_block_leaf_p(btp); endptr = (char *)lep; if (endptr <= ptr || endptr > (char *)btp) { endptr = (char *)data + mp->m_dir_geo->blksize; lep = NULL; if (!sflag || v) dbprintf(_("bad block directory tail for dir ino " "%lld\n"), id->ino); error++; } } else endptr = (char *)data + mp->m_dir_geo->blksize; bf_err = lastfree_err = tag_err = 0; count = lastfree = freeseen = 0; if (be16_to_cpu(bf[0].length) == 0) { bf_err += be16_to_cpu(bf[0].offset) != 0; freeseen |= 1 << 0; } if (be16_to_cpu(bf[1].length) == 0) { bf_err += be16_to_cpu(bf[1].offset) != 0; freeseen |= 1 << 1; } if (be16_to_cpu(bf[2].length) == 0) { bf_err += be16_to_cpu(bf[2].offset) != 0; freeseen |= 1 << 2; } bf_err += be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length); bf_err += be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length); if (freetabp) { freetab = *freetabp; if (freetab->naents <= db) { *freetabp = freetab = realloc(freetab, FREETAB_SIZE(db + 1)); for (i = freetab->naents; i < db; i++) freetab->ents[i] = NULLDATAOFF; freetab->naents = db + 1; } if (freetab->nents < db + 1) freetab->nents = db + 1; freetab->ents[db] = be16_to_cpu(bf[0].length); } while (ptr < endptr) { dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { lastfree_err += lastfree != 0; tagp = xfs_dir2_data_unused_tag_p(dup); if ((be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1)) || be16_to_cpu(dup->length) == 0 || (char *)tagp >= endptr) { if (!sflag || v) dbprintf(_("dir %lld block %d bad free " "entry at %d\n"), id->ino, dabno, (int)((char *)dup - (char *)data)); error++; break; } tag_err += be16_to_cpu(*tagp) != (char *)dup - (char *)data; dfp = process_data_dir_v2_freefind(data, dup); if (dfp) { i = (int)(dfp - bf); bf_err += (freeseen & (1 << i)) != 0; freeseen |= 1 << i; } else bf_err += be16_to_cpu(dup->length) > be16_to_cpu(bf[2].length); ptr += be16_to_cpu(dup->length); lastfree = 1; continue; } dep = (xfs_dir2_data_entry_t *)dup; if (dep->namelen == 0) { if (!sflag || v) dbprintf(_("dir %lld block %d zero length entry " "at %d\n"), id->ino, dabno, (int)((char *)dep - (char *)data)); error++; } tagp = M_DIROPS(mp)->data_entry_tag_p(dep); if ((char *)tagp >= endptr) { if (!sflag || v) dbprintf(_("dir %lld block %d bad entry at %d\n"), id->ino, dabno, (int)((char *)dep - (char *)data)); error++; break; } tag_err += be16_to_cpu(*tagp) != (char *)dep - (char *)data; addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db, (char *)dep - (char *)data); xname.name = dep->name; xname.len = dep->namelen; dir_hash_add(mp->m_dirnameops->hashname(&xname), addr); ptr += M_DIROPS(mp)->data_entsize(dep->namelen); count++; lastfree = 0; lino = be64_to_cpu(dep->inumber); cid = find_inode(lino, 1); if (v) dbprintf(_("dir %lld block %d entry %*.*s %lld\n"), id->ino, dabno, dep->namelen, dep->namelen, dep->name, lino); if (cid) addlink_inode(cid); else { if (!sflag || v) dbprintf(_("dir %lld block %d entry %*.*s bad " "inode number %lld\n"), id->ino, dabno, dep->namelen, dep->namelen, dep->name, lino); error++; } if (dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.') { if (parent) { if (!sflag || v) dbprintf(_("multiple .. entries in dir " "%lld (%lld, %lld)\n"), id->ino, parent, lino); error++; } else parent = cid ? lino : NULLFSINO; (*dotdot)++; } else if (dep->namelen != 1 || dep->name[0] != '.') { if (cid != NULL) { if (!cid->parent) cid->parent = id; addname_inode(cid, (char *)dep->name, dep->namelen); } } else { if (lino != id->ino) { if (!sflag || v) dbprintf(_("dir %lld entry . inode " "number mismatch (%lld)\n"), id->ino, lino); error++; } (*dot)++; } } if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) { endptr = (char *)data + mp->m_dir_geo->blksize; for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) { if ((char *)&lep[i] >= endptr) { if (!sflag || v) dbprintf(_("dir %lld block %d bad count " "%u\n"), id->ino, dabno, be32_to_cpu(btp->count)); error++; break; } if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR) stale++; else if (dir_hash_see(be32_to_cpu(lep[i].hashval), be32_to_cpu(lep[i].address))) { if (!sflag || v) dbprintf(_("dir %lld block %d extra leaf " "entry %x %x\n"), id->ino, dabno, be32_to_cpu(lep[i].hashval), be32_to_cpu(lep[i].address)); error++; } } } bf_err += freeseen != 7; if (bf_err) { if (!sflag || v) dbprintf(_("dir %lld block %d bad bestfree data\n"), id->ino, dabno); error++; } if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) && count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d bad block tail count %d " "(stale %d)\n"), id->ino, dabno, be32_to_cpu(btp->count), be32_to_cpu(btp->stale)); error++; } if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) && stale != be32_to_cpu(btp->stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d bad stale tail count %d\n"), id->ino, dabno, be32_to_cpu(btp->stale)); error++; } if (lastfree_err) { if (!sflag || v) dbprintf(_("dir %lld block %d consecutive free entries\n"), id->ino, dabno); error++; } if (tag_err) { if (!sflag || v) dbprintf(_("dir %lld block %d entry/unused tag " "mismatch\n"), id->ino, dabno); error++; } return parent; } static xfs_dir2_data_free_t * process_data_dir_v2_freefind( struct xfs_dir2_data_hdr *data, xfs_dir2_data_unused_t *dup) { struct xfs_dir2_data_free *bf; struct xfs_dir2_data_free *dfp; xfs_dir2_data_aoff_t off; off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)data); bf = M_DIROPS(mp)->data_bestfree_p(data); if (be16_to_cpu(dup->length) < be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) return NULL; for (dfp = bf; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { if (be16_to_cpu(dfp->offset) == 0) return NULL; if (be16_to_cpu(dfp->offset) == off) return dfp; } return NULL; } static void process_dir( xfs_dinode_t *dip, blkmap_t *blkmap, inodata_t *id) { xfs_fsblock_t bno; int dot; int dotdot; xfs_ino_t parent; dot = dotdot = 0; if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent)) return; bno = XFS_INO_TO_FSB(mp, id->ino); if (dot == 0) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("no . entry for directory %lld\n"), id->ino); error++; } if (dotdot == 0) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("no .. entry for directory %lld\n"), id->ino); error++; } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_(". and .. same for non-root directory %lld\n"), id->ino); error++; } else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("root directory %lld has .. %lld\n"), id->ino, parent); error++; } else if (parent != NULLFSINO && id->ino != parent) addparent_inode(id, parent); } static int process_dir_v2( xfs_dinode_t *dip, blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id, xfs_ino_t *parent) { xfs_fileoff_t last = 0; xfs_fsize_t size = be64_to_cpu(dip->di_size); if (blkmap) last = blkmap_last_off(blkmap); if (size <= XFS_DFORK_DSIZE(dip, mp) && dip->di_format == XFS_DINODE_FMT_LOCAL) *parent = process_sf_dir_v2(dip, dot, dotdot, id); else if (last == mp->m_dir_geo->fsbcount && (dip->di_format == XFS_DINODE_FMT_EXTENTS || dip->di_format == XFS_DINODE_FMT_BTREE)) *parent = process_block_dir_v2(blkmap, dot, dotdot, id); else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount && (dip->di_format == XFS_DINODE_FMT_EXTENTS || dip->di_format == XFS_DINODE_FMT_BTREE)) *parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, size); else { dbprintf(_("bad size (%lld) or format (%d) for directory inode " "%lld\n"), size, dip->di_format, id->ino); error++; return 1; } return 0; } /* ARGSUSED */ static void process_exinode( inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork) { xfs_bmbt_rec_t *rp; rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork); *nex = XFS_DFORK_NEXTENTS(dip, whichfork); if (*nex < 0 || *nex > XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) { if (!sflag || id->ilist) dbprintf(_("bad number of extents %d for inode %lld\n"), *nex, id->ino); error++; return; } process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp); } static void process_inode( xfs_agf_t *agf, xfs_agino_t agino, xfs_dinode_t *dip, int isfree) { blkmap_t *blkmap; xfs_fsblock_t bno = 0; struct xfs_inode xino; inodata_t *id = NULL; xfs_ino_t ino; xfs_extnum_t nextents = 0; int security; xfs_rfsblock_t totblocks; xfs_rfsblock_t totdblocks = 0; xfs_rfsblock_t totiblocks = 0; dbm_t type; xfs_extnum_t anextents = 0; xfs_rfsblock_t atotdblocks = 0; xfs_rfsblock_t atotiblocks = 0; xfs_qcnt_t bc = 0; xfs_qcnt_t ic = 0; xfs_qcnt_t rc = 0; xfs_dqid_t dqprid; int v = 0; mode_t mode; static char okfmts[] = { 0, /* type 0 unused */ 1 << XFS_DINODE_FMT_DEV, /* FIFO */ 1 << XFS_DINODE_FMT_DEV, /* CHR */ 0, /* type 3 unused */ (1 << XFS_DINODE_FMT_LOCAL) | (1 << XFS_DINODE_FMT_EXTENTS) | (1 << XFS_DINODE_FMT_BTREE), /* DIR */ 0, /* type 5 unused */ 1 << XFS_DINODE_FMT_DEV, /* BLK */ 0, /* type 7 unused */ (1 << XFS_DINODE_FMT_EXTENTS) | (1 << XFS_DINODE_FMT_BTREE), /* REG */ 0, /* type 9 unused */ (1 << XFS_DINODE_FMT_LOCAL) | (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */ 0, /* type 11 unused */ 1 << XFS_DINODE_FMT_DEV, /* SOCK */ 0, /* type 13 unused */ 1 << XFS_DINODE_FMT_UUID, /* MNT */ 0 /* type 15 unused */ }; static char *fmtnames[] = { "dev", "local", "extents", "btree", "uuid" }; libxfs_inode_from_disk(&xino, dip); ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino); if (!isfree) { id = find_inode(ino, 1); bno = XFS_INO_TO_FSB(mp, ino); blkmap = NULL; } v = (!sflag || (id && id->ilist) || CHECK_BLIST(bno)); if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) { if (isfree || v) dbprintf(_("bad magic number %#x for inode %lld\n"), be16_to_cpu(dip->di_magic), ino); error++; return; } if (!libxfs_dinode_good_version(mp, xino.i_d.di_version)) { if (isfree || v) dbprintf(_("bad version number %#x for inode %lld\n"), xino.i_d.di_version, ino); error++; return; } if (isfree) { if (xino.i_d.di_nblocks != 0) { if (v) dbprintf(_("bad nblocks %lld for free inode " "%lld\n"), xino.i_d.di_nblocks, ino); error++; } if (dip->di_nlink != 0) { if (v) dbprintf(_("bad nlink %d for free inode %lld\n"), be32_to_cpu(dip->di_nlink), ino); error++; } if (dip->di_mode != 0) { if (v) dbprintf(_("bad mode %#o for free inode %lld\n"), be16_to_cpu(dip->di_mode), ino); error++; } return; } if (be32_to_cpu(dip->di_next_unlinked) != NULLAGINO) { if (v) dbprintf(_("bad next unlinked %#x for inode %lld\n"), be32_to_cpu(dip->di_next_unlinked), ino); error++; } /* * di_mode is a 16-bit uint so no need to check the < 0 case */ mode = be16_to_cpu(dip->di_mode); if ((((mode & S_IFMT) >> 12) > 15) || (!(okfmts[(mode & S_IFMT) >> 12] & (1 << xino.i_d.di_format)))) { if (v) dbprintf(_("bad format %d for inode %lld type %#o\n"), xino.i_d.di_format, id->ino, mode & S_IFMT); error++; return; } if ((unsigned int)XFS_DFORK_ASIZE(dip, mp) >= XFS_LITINO(mp, xino.i_d.di_version)) { if (v) dbprintf(_("bad fork offset %d for inode %lld\n"), xino.i_d.di_forkoff, id->ino); error++; return; } if ((unsigned int)xino.i_d.di_aformat > XFS_DINODE_FMT_BTREE) { if (v) dbprintf(_("bad attribute format %d for inode %lld\n"), xino.i_d.di_aformat, id->ino); error++; return; } if (verbose || (id && id->ilist) || CHECK_BLIST(bno)) dbprintf(_("inode %lld mode %#o fmt %s " "afmt %s " "nex %d anex %d nblk %lld sz %lld%s%s%s%s%s%s%s\n"), id->ino, mode, fmtnames[(int)xino.i_d.di_format], fmtnames[(int)xino.i_d.di_aformat], xino.i_d.di_nextents, xino.i_d.di_anextents, xino.i_d.di_nblocks, xino.i_d.di_size, xino.i_d.di_flags & XFS_DIFLAG_REALTIME ? " rt" : "", xino.i_d.di_flags & XFS_DIFLAG_PREALLOC ? " pre" : "", xino.i_d.di_flags & XFS_DIFLAG_IMMUTABLE? " imm" : "", xino.i_d.di_flags & XFS_DIFLAG_APPEND ? " app" : "", xino.i_d.di_flags & XFS_DIFLAG_SYNC ? " syn" : "", xino.i_d.di_flags & XFS_DIFLAG_NOATIME ? " noa" : "", xino.i_d.di_flags & XFS_DIFLAG_NODUMP ? " nod" : ""); security = 0; switch (mode & S_IFMT) { case S_IFDIR: type = DBM_DIR; if (xino.i_d.di_format == XFS_DINODE_FMT_LOCAL) break; blkmap = blkmap_alloc(xino.i_d.di_nextents); break; case S_IFREG: if (xino.i_d.di_flags & XFS_DIFLAG_REALTIME) type = DBM_RTDATA; else if (id->ino == mp->m_sb.sb_rbmino) { type = DBM_RTBITMAP; blkmap = blkmap_alloc(xino.i_d.di_nextents); addlink_inode(id); } else if (id->ino == mp->m_sb.sb_rsumino) { type = DBM_RTSUM; blkmap = blkmap_alloc(xino.i_d.di_nextents); addlink_inode(id); } else if (id->ino == mp->m_sb.sb_uquotino || id->ino == mp->m_sb.sb_gquotino || id->ino == mp->m_sb.sb_pquotino) { type = DBM_QUOTA; blkmap = blkmap_alloc(xino.i_d.di_nextents); addlink_inode(id); } else type = DBM_DATA; if (mode & (S_ISUID | S_ISGID)) security = 1; break; case S_IFLNK: type = DBM_SYMLINK; break; default: security = 1; type = DBM_UNKNOWN; break; } id->isreflink = !!(xino.i_d.di_flags2 & XFS_DIFLAG2_REFLINK); setlink_inode(id, VFS_I(&xino)->i_nlink, type == DBM_DIR, security); switch (xino.i_d.di_format) { case XFS_DINODE_FMT_LOCAL: process_lclinode(id, dip, type, &totdblocks, &totiblocks, &nextents, &blkmap, XFS_DATA_FORK); break; case XFS_DINODE_FMT_EXTENTS: process_exinode(id, dip, type, &totdblocks, &totiblocks, &nextents, &blkmap, XFS_DATA_FORK); break; case XFS_DINODE_FMT_BTREE: process_btinode(id, dip, type, &totdblocks, &totiblocks, &nextents, &blkmap, XFS_DATA_FORK); break; } if (XFS_DFORK_Q(dip)) { sbversion |= XFS_SB_VERSION_ATTRBIT; switch (xino.i_d.di_aformat) { case XFS_DINODE_FMT_LOCAL: process_lclinode(id, dip, DBM_ATTR, &atotdblocks, &atotiblocks, &anextents, NULL, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_EXTENTS: process_exinode(id, dip, DBM_ATTR, &atotdblocks, &atotiblocks, &anextents, NULL, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_BTREE: process_btinode(id, dip, DBM_ATTR, &atotdblocks, &atotiblocks, &anextents, NULL, XFS_ATTR_FORK); break; } } if (qgdo || qpdo || qudo) { switch (type) { case DBM_DATA: case DBM_DIR: case DBM_RTBITMAP: case DBM_RTSUM: case DBM_SYMLINK: case DBM_UNKNOWN: bc = totdblocks + totiblocks + atotdblocks + atotiblocks; ic = 1; break; case DBM_RTDATA: bc = totiblocks + atotdblocks + atotiblocks; rc = totdblocks; ic = 1; break; default: break; } if (ic) { dqprid = xfs_get_projid(&xino.i_d); /* dquot ID is u32 */ quota_add(&dqprid, &xino.i_d.di_gid, &xino.i_d.di_uid, 0, bc, ic, rc); } } totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks; if (totblocks != xino.i_d.di_nblocks) { if (v) dbprintf(_("bad nblocks %lld for inode %lld, counted " "%lld\n"), xino.i_d.di_nblocks, id->ino, totblocks); error++; } if (nextents != xino.i_d.di_nextents) { if (v) dbprintf(_("bad nextents %d for inode %lld, counted %d\n"), xino.i_d.di_nextents, id->ino, nextents); error++; } if (anextents != xino.i_d.di_anextents) { if (v) dbprintf(_("bad anextents %d for inode %lld, counted " "%d\n"), xino.i_d.di_anextents, id->ino, anextents); error++; } if (type == DBM_DIR) process_dir(dip, blkmap, id); else if (type == DBM_RTBITMAP) process_rtbitmap(blkmap); else if (type == DBM_RTSUM) process_rtsummary(blkmap); /* * If the CHKD flag is not set, this can legitimately contain garbage; * xfs_repair may have cleared that bit. */ else if (type == DBM_QUOTA) { if (id->ino == mp->m_sb.sb_uquotino && (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) && (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD)) process_quota(IS_USER_QUOTA, id, blkmap); else if (id->ino == mp->m_sb.sb_gquotino && (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) && (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD)) process_quota(IS_GROUP_QUOTA, id, blkmap); else if (id->ino == mp->m_sb.sb_pquotino && (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) && (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD)) process_quota(IS_PROJECT_QUOTA, id, blkmap); } if (blkmap) blkmap_free(blkmap); } /* ARGSUSED */ static void process_lclinode( inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork) { xfs_attr_shortform_t *asf; xfs_fsblock_t bno; bno = XFS_INO_TO_FSB(mp, id->ino); if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) > XFS_DFORK_DSIZE(dip, mp)) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("local inode %lld data is too large (size " "%lld)\n"), id->ino, be64_to_cpu(dip->di_size)); error++; } else if (whichfork == XFS_ATTR_FORK) { asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); if (be16_to_cpu(asf->hdr.totsize) > XFS_DFORK_ASIZE(dip, mp)) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("local inode %lld attr is too large " "(size %d)\n"), id->ino, be16_to_cpu(asf->hdr.totsize)); error++; } } } static xfs_ino_t process_leaf_node_dir_v2( blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id, xfs_fsize_t dirsize) { xfs_fsblock_t b; bbmap_t bbmap; bmap_ext_t *bmp; xfs_fileoff_t dbno; freetab_t *freetab; int i; xfs_ino_t lino; int nex; xfs_ino_t parent; int t = 0; int v; int v2; v2 = verbose || id->ilist; v = parent = 0; dbno = NULLFILEOFF; freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dir_geo->blksize)); freetab->naents = (int)(dirsize / mp->m_dir_geo->blksize); freetab->nents = 0; for (i = 0; i < freetab->naents; i++) freetab->ents[i] = NULLDATAOFF; dir_hash_init(); while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) { nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp); ASSERT(nex > 0); for (v = v2, i = 0; !v && i < nex; i++) { for (b = bmp[i].startblock; !v && b < bmp[i].startblock + bmp[i].blockcount; b++) v = CHECK_BLIST(b); } if (v) dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino, (uint32_t)dbno, (xfs_fsblock_t)bmp->startblock); push_cur(); if (nex > 1) make_bbmap(&bbmap, nex, bmp); set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock), mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL); free(bmp); if (iocur_top->data == NULL) { if (!sflag || v) dbprintf(_("can't read block %u for directory " "inode %lld\n"), (uint32_t)dbno, id->ino); error++; pop_cur(); dbno += mp->m_dir_geo->fsbcount - 1; continue; } if (dbno < mp->m_dir_geo->leafblk) { lino = process_data_dir_v2(dot, dotdot, id, v, (xfs_dablk_t)dbno, &freetab); if (lino) { if (parent) { if (!sflag || v) dbprintf(_("multiple .. entries " "in dir %lld\n"), id->ino); error++; } else parent = lino; } } else if (dbno < mp->m_dir_geo->freeblk) { process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno, freetab); } else { process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno, freetab); } pop_cur(); dbno += mp->m_dir_geo->fsbcount - 1; } dir_hash_check(id, v); dir_hash_done(); for (i = 0; i < freetab->nents; i++) { if (freetab->ents[i] != NULLDATAOFF) { if (!sflag || v) dbprintf(_("missing free index for data block %d " "in dir ino %lld\n"), xfs_dir2_db_to_da(mp->m_dir_geo, i), id->ino); error++; } } free(freetab); return parent; } static void process_leaf_node_dir_v3_free( inodata_t *id, int v, xfs_dablk_t dabno, freetab_t *freetab) { xfs_dir2_data_off_t ent; struct xfs_dir3_free *free; int i; int maxent; int used; free = iocur_top->data; maxent = M_DIROPS(mp)->free_max_bests(mp->m_dir_geo); if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo, dabno - mp->m_dir_geo->freeblk) * maxent) { if (!sflag || v) dbprintf(_("bad free block firstdb %d for dir ino %lld " "block %d\n"), be32_to_cpu(free->hdr.firstdb), id->ino, dabno); error++; return; } if (be32_to_cpu(free->hdr.nvalid) > maxent || be32_to_cpu(free->hdr.nused) > maxent || be32_to_cpu(free->hdr.nused) > be32_to_cpu(free->hdr.nvalid)) { if (!sflag || v) dbprintf(_("bad free block nvalid/nused %d/%d for dir " "ino %lld block %d\n"), be32_to_cpu(free->hdr.nvalid), be32_to_cpu(free->hdr.nused), id->ino, dabno); error++; return; } for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) { if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i) ent = NULLDATAOFF; else ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i]; if (ent != be16_to_cpu(free->bests[i])) { if (!sflag || v) dbprintf(_("bad free block ent %d is %d should " "be %d for dir ino %lld block %d\n"), i, be16_to_cpu(free->bests[i]), ent, id->ino, dabno); error++; } if (be16_to_cpu(free->bests[i]) != NULLDATAOFF) used++; if (ent != NULLDATAOFF) freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] = NULLDATAOFF; } if (used != be32_to_cpu(free->hdr.nused)) { if (!sflag || v) dbprintf(_("bad free block nused %d should be %d for dir " "ino %lld block %d\n"), be32_to_cpu(free->hdr.nused), used, id->ino, dabno); error++; } } static void process_leaf_node_dir_v2_free( inodata_t *id, int v, xfs_dablk_t dabno, freetab_t *freetab) { xfs_dir2_data_off_t ent; xfs_dir2_free_t *free; int i; int maxent; int used; free = iocur_top->data; if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC && be32_to_cpu(free->hdr.magic) != XFS_DIR3_FREE_MAGIC) { if (!sflag || v) dbprintf(_("bad free block magic # %#x for dir ino %lld " "block %d\n"), be32_to_cpu(free->hdr.magic), id->ino, dabno); error++; return; } if (be32_to_cpu(free->hdr.magic) == XFS_DIR3_FREE_MAGIC) { process_leaf_node_dir_v3_free(id, v, dabno, freetab); return; } maxent = M_DIROPS(mp)->free_max_bests(mp->m_dir_geo); if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo, dabno - mp->m_dir_geo->freeblk) * maxent) { if (!sflag || v) dbprintf(_("bad free block firstdb %d for dir ino %lld " "block %d\n"), be32_to_cpu(free->hdr.firstdb), id->ino, dabno); error++; return; } if (be32_to_cpu(free->hdr.nvalid) > maxent || be32_to_cpu(free->hdr.nused) > maxent || be32_to_cpu(free->hdr.nused) > be32_to_cpu(free->hdr.nvalid)) { if (!sflag || v) dbprintf(_("bad free block nvalid/nused %d/%d for dir " "ino %lld block %d\n"), be32_to_cpu(free->hdr.nvalid), be32_to_cpu(free->hdr.nused), id->ino, dabno); error++; return; } for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) { if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i) ent = NULLDATAOFF; else ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i]; if (ent != be16_to_cpu(free->bests[i])) { if (!sflag || v) dbprintf(_("bad free block ent %d is %d should " "be %d for dir ino %lld block %d\n"), i, be16_to_cpu(free->bests[i]), ent, id->ino, dabno); error++; } if (be16_to_cpu(free->bests[i]) != NULLDATAOFF) used++; if (ent != NULLDATAOFF) freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] = NULLDATAOFF; } if (used != be32_to_cpu(free->hdr.nused)) { if (!sflag || v) dbprintf(_("bad free block nused %d should be %d for dir " "ino %lld block %d\n"), be32_to_cpu(free->hdr.nused), used, id->ino, dabno); error++; } } /* * Get address of the bestcount field in the single-leaf block. */ static inline int xfs_dir3_leaf_ents_count(struct xfs_dir2_leaf *lp) { if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp; return be16_to_cpu(lp3->hdr.count); } return be16_to_cpu(lp->hdr.count); } static void process_leaf_node_dir_v2_int( inodata_t *id, int v, xfs_dablk_t dabno, freetab_t *freetab) { int i; __be16 *lbp; xfs_dir2_leaf_t *leaf; struct xfs_dir3_leaf *leaf3 = NULL; xfs_dir2_leaf_entry_t *lep; xfs_dir2_leaf_tail_t *ltp; xfs_da_intnode_t *node; int stale; struct xfs_da3_icnode_hdr nodehdr; leaf = iocur_top->data; switch (be16_to_cpu(leaf->hdr.info.magic)) { case XFS_DIR3_LEAF1_MAGIC: case XFS_DIR3_LEAFN_MAGIC: case XFS_DA3_NODE_MAGIC: leaf3 = iocur_top->data; break; } switch (be16_to_cpu(leaf->hdr.info.magic)) { case XFS_DIR2_LEAF1_MAGIC: case XFS_DIR3_LEAF1_MAGIC: if (be32_to_cpu(leaf->hdr.info.forw) || be32_to_cpu(leaf->hdr.info.back)) { if (!sflag || v) dbprintf(_("bad leaf block forw/back pointers " "%d/%d for dir ino %lld block %d\n"), be32_to_cpu(leaf->hdr.info.forw), be32_to_cpu(leaf->hdr.info.back), id->ino, dabno); error++; } if (dabno != mp->m_dir_geo->leafblk) { if (!sflag || v) dbprintf(_("single leaf block for dir ino %lld " "block %d should be at block %d\n"), id->ino, dabno, (xfs_dablk_t)mp->m_dir_geo->leafblk); error++; } ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); lbp = xfs_dir2_leaf_bests_p(ltp); for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) { if (freetab->nents <= i || freetab->ents[i] != be16_to_cpu(lbp[i])) { if (!sflag || v) dbprintf(_("bestfree %d for dir ino %lld " "block %d doesn't match table " "value %d\n"), freetab->nents <= i ? NULLDATAOFF : freetab->ents[i], id->ino, xfs_dir2_db_to_da(mp->m_dir_geo, i), be16_to_cpu(lbp[i])); } if (freetab->nents > i) freetab->ents[i] = NULLDATAOFF; } break; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: /* if it's at the root location then we can check the * pointers are null XXX */ break; case XFS_DA_NODE_MAGIC: case XFS_DA3_NODE_MAGIC: node = iocur_top->data; M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node); if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) { if (!sflag || v) dbprintf(_("bad node block level %d for dir ino " "%lld block %d\n"), nodehdr.level, id->ino, dabno); error++; } return; default: if (!sflag || v) dbprintf(_("bad directory data magic # %#x for dir ino " "%lld block %d\n"), be16_to_cpu(leaf->hdr.info.magic), id->ino, dabno); error++; return; } lep = M_DIROPS(mp)->leaf_ents_p(leaf); for (i = stale = 0; i < xfs_dir3_leaf_ents_count(leaf); i++) { if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR) stale++; else if (dir_hash_see(be32_to_cpu(lep[i].hashval), be32_to_cpu(lep[i].address))) { if (!sflag || v) dbprintf(_("dir %lld block %d extra leaf entry " "%x %x\n"), id->ino, dabno, be32_to_cpu(lep[i].hashval), be32_to_cpu(lep[i].address)); error++; } } if (leaf3 && stale != be16_to_cpu(leaf3->hdr.stale)) { if (!sflag || v) dbprintf(_("dir3 %lld block %d stale mismatch " "%d/%d\n"), id->ino, dabno, stale, be16_to_cpu(leaf3->hdr.stale)); error++; } else if (!leaf && stale != be16_to_cpu(leaf->hdr.stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d stale mismatch " "%d/%d\n"), id->ino, dabno, stale, be16_to_cpu(leaf->hdr.stale)); error++; } } static void process_quota( qtype_t qtype, inodata_t *id, blkmap_t *blkmap) { xfs_fsblock_t bno; int cb; xfs_dqblk_t *dqb; xfs_dqid_t dqid; uint8_t exp_flags = 0; uint i; uint perblock; xfs_fileoff_t qbno; char *s = NULL; int scicb; int t = 0; switch (qtype) { case IS_USER_QUOTA: s = "user"; exp_flags = XFS_DQ_USER; break; case IS_PROJECT_QUOTA: s = "project"; exp_flags = XFS_DQ_PROJ; break; case IS_GROUP_QUOTA: s = "group"; exp_flags = XFS_DQ_GROUP; break; default: ASSERT(0); } perblock = (uint)(mp->m_sb.sb_blocksize / sizeof(*dqb)); dqid = 0; qbno = NULLFILEOFF; while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) { bno = blkmap_get(blkmap, qbno); dqid = (xfs_dqid_t)qbno * perblock; cb = CHECK_BLIST(bno); scicb = !sflag || id->ilist || cb; push_cur(); set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, NULL); if ((dqb = iocur_top->data) == NULL) { if (scicb) dbprintf(_("can't read block %lld for %s quota " "inode (fsblock %lld)\n"), (xfs_fileoff_t)qbno, s, (xfs_fsblock_t)bno); error++; pop_cur(); continue; } for (i = 0; i < perblock; i++, dqid++, dqb++) { if (verbose || id->ilist || cb) dbprintf(_("%s dqblk %lld entry %d id %u bc " "%lld ic %lld rc %lld\n"), s, (xfs_fileoff_t)qbno, i, dqid, be64_to_cpu(dqb->dd_diskdq.d_bcount), be64_to_cpu(dqb->dd_diskdq.d_icount), be64_to_cpu(dqb->dd_diskdq.d_rtbcount)); if (be16_to_cpu(dqb->dd_diskdq.d_magic) != XFS_DQUOT_MAGIC) { if (scicb) dbprintf(_("bad magic number %#x for %s " "dqblk %lld entry %d id %u\n"), be16_to_cpu(dqb->dd_diskdq.d_magic), s, (xfs_fileoff_t)qbno, i, dqid); error++; continue; } if (dqb->dd_diskdq.d_version != XFS_DQUOT_VERSION) { if (scicb) dbprintf(_("bad version number %#x for " "%s dqblk %lld entry %d id " "%u\n"), dqb->dd_diskdq.d_version, s, (xfs_fileoff_t)qbno, i, dqid); error++; continue; } if (dqb->dd_diskdq.d_flags != exp_flags) { if (scicb) dbprintf(_("bad flags %#x for %s dqblk " "%lld entry %d id %u\n"), dqb->dd_diskdq.d_flags, s, (xfs_fileoff_t)qbno, i, dqid); error++; continue; } if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) { if (scicb) dbprintf(_("bad id %u for %s dqblk %lld " "entry %d id %u\n"), be32_to_cpu(dqb->dd_diskdq.d_id), s, (xfs_fileoff_t)qbno, i, dqid); error++; continue; } quota_add((qtype == IS_PROJECT_QUOTA) ? &dqid : NULL, (qtype == IS_GROUP_QUOTA) ? &dqid : NULL, (qtype == IS_USER_QUOTA) ? &dqid : NULL, 1, be64_to_cpu(dqb->dd_diskdq.d_bcount), be64_to_cpu(dqb->dd_diskdq.d_icount), be64_to_cpu(dqb->dd_diskdq.d_rtbcount)); } pop_cur(); } } static void process_rtbitmap( blkmap_t *blkmap) { int bit; int bitsperblock; xfs_fileoff_t bmbno; xfs_fsblock_t bno; xfs_rtblock_t extno; int len; int log; int offs; int prevbit; xfs_rfsblock_t rtbno; int start_bmbno; int start_bit; int t; xfs_rtword_t *words; bitsperblock = mp->m_sb.sb_blocksize * NBBY; bit = extno = prevbit = start_bmbno = start_bit = 0; bmbno = NULLFILEOFF; while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) != NULLFILEOFF) { bno = blkmap_get(blkmap, bmbno); if (bno == NULLFSBLOCK) { if (!sflag) dbprintf(_("block %lld for rtbitmap inode is " "missing\n"), (xfs_fileoff_t)bmbno); error++; continue; } push_cur(); set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, NULL); if ((words = iocur_top->data) == NULL) { if (!sflag) dbprintf(_("can't read block %lld for rtbitmap " "inode\n"), (xfs_fileoff_t)bmbno); error++; pop_cur(); continue; } for (bit = 0; bit < bitsperblock && extno < mp->m_sb.sb_rextents; bit++, extno++) { if (xfs_isset(words, bit)) { rtbno = extno * mp->m_sb.sb_rextsize; set_rdbmap(rtbno, mp->m_sb.sb_rextsize, DBM_RTFREE); frextents++; if (prevbit == 0) { start_bmbno = (int)bmbno; start_bit = bit; prevbit = 1; } } else if (prevbit == 1) { len = ((int)bmbno - start_bmbno) * bitsperblock + (bit - start_bit); log = XFS_RTBLOCKLOG(len); offs = XFS_SUMOFFS(mp, log, start_bmbno); sumcompute[offs]++; prevbit = 0; } } pop_cur(); if (extno == mp->m_sb.sb_rextents) break; } if (prevbit == 1) { len = ((int)bmbno - start_bmbno) * bitsperblock + (bit - start_bit); log = XFS_RTBLOCKLOG(len); offs = XFS_SUMOFFS(mp, log, start_bmbno); sumcompute[offs]++; } } static void process_rtsummary( blkmap_t *blkmap) { xfs_fsblock_t bno; char *bytes; xfs_fileoff_t sumbno; int t; sumbno = NULLFILEOFF; while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) { bno = blkmap_get(blkmap, sumbno); if (bno == NULLFSBLOCK) { if (!sflag) dbprintf(_("block %lld for rtsummary inode is " "missing\n"), (xfs_fileoff_t)sumbno); error++; continue; } push_cur(); set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, NULL); if ((bytes = iocur_top->data) == NULL) { if (!sflag) dbprintf(_("can't read block %lld for rtsummary " "inode\n"), (xfs_fileoff_t)sumbno); error++; pop_cur(); continue; } memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes, mp->m_sb.sb_blocksize); pop_cur(); } } static xfs_ino_t process_sf_dir_v2( xfs_dinode_t *dip, int *dot, int *dotdot, inodata_t *id) { inodata_t *cid; int i; int i8; xfs_ino_t lino; int offset; struct xfs_dir2_sf_hdr *sf; xfs_dir2_sf_entry_t *sfe; int v; sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); addlink_inode(id); v = verbose || id->ilist; if (v) dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino); (*dot)++; sfe = xfs_dir2_sf_firstentry(sf); offset = M_DIROPS(mp)->data_first_offset; for (i = sf->count - 1, i8 = 0; i >= 0; i--) { if ((intptr_t)sfe + M_DIROPS(mp)->sf_entsize(sf, sfe->namelen) - (intptr_t)sf > be64_to_cpu(dip->di_size)) { if (!sflag) dbprintf(_("dir %llu bad size in entry at %d\n"), id->ino, (int)((char *)sfe - (char *)sf)); error++; break; } lino = M_DIROPS(mp)->sf_get_ino(sf, sfe); if (lino > XFS_DIR2_MAX_SHORT_INUM) i8++; cid = find_inode(lino, 1); if (cid == NULL) { if (!sflag) dbprintf(_("dir %lld entry %*.*s bad inode " "number %lld\n"), id->ino, sfe->namelen, sfe->namelen, sfe->name, lino); error++; } else { addlink_inode(cid); if (!cid->parent) cid->parent = id; addname_inode(cid, (char *)sfe->name, sfe->namelen); } if (v) dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"), id->ino, sfe->namelen, sfe->namelen, sfe->name, xfs_dir2_sf_get_offset(sfe), lino); if (xfs_dir2_sf_get_offset(sfe) < offset) { if (!sflag) dbprintf(_("dir %lld entry %*.*s bad offset %d\n"), id->ino, sfe->namelen, sfe->namelen, sfe->name, xfs_dir2_sf_get_offset(sfe)); error++; } offset = xfs_dir2_sf_get_offset(sfe) + M_DIROPS(mp)->sf_entsize(sf, sfe->namelen); sfe = M_DIROPS(mp)->sf_nextentry(sf, sfe); } if (i < 0 && (intptr_t)sfe - (intptr_t)sf != be64_to_cpu(dip->di_size)) { if (!sflag) dbprintf(_("dir %llu size is %lld, should be %u\n"), id->ino, be64_to_cpu(dip->di_size), (uint)((char *)sfe - (char *)sf)); error++; } if (offset + (sf->count + 2) * sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) { if (!sflag) dbprintf(_("dir %llu offsets too high\n"), id->ino); error++; } lino = M_DIROPS(mp)->sf_get_parent_ino(sf); if (lino > XFS_DIR2_MAX_SHORT_INUM) i8++; cid = find_inode(lino, 1); if (cid) addlink_inode(cid); else { if (!sflag) dbprintf(_("dir %lld entry .. bad inode number %lld\n"), id->ino, lino); error++; } if (v) dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino); if (i8 != sf->i8count) { if (!sflag) dbprintf(_("dir %lld i8count mismatch is %d should be " "%d\n"), id->ino, sf->i8count, i8); error++; } (*dotdot)++; return cid ? lino : NULLFSINO; } static void quota_add( xfs_dqid_t *prjid, xfs_dqid_t *grpid, xfs_dqid_t *usrid, int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, xfs_qcnt_t rc) { if (qudo && usrid != NULL) quota_add1(qudata, *usrid, dq, bc, ic, rc); if (qgdo && grpid != NULL) quota_add1(qgdata, *grpid, dq, bc, ic, rc); if (qpdo && prjid != NULL) quota_add1(qpdata, *prjid, dq, bc, ic, rc); } static void quota_add1( qdata_t **qt, xfs_dqid_t id, int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, xfs_qcnt_t rc) { qdata_t *qe; int qh; qinfo_t *qi; qh = (int)(id % QDATA_HASH_SIZE); qe = qt[qh]; while (qe) { if (qe->id == id) { qi = dq ? &qe->dq : &qe->count; qi->bc += bc; qi->ic += ic; qi->rc += rc; return; } qe = qe->next; } qe = xmalloc(sizeof(*qe)); qe->id = id; qi = dq ? &qe->dq : &qe->count; qi->bc = bc; qi->ic = ic; qi->rc = rc; qi = dq ? &qe->count : &qe->dq; qi->bc = qi->ic = qi->rc = 0; qe->next = qt[qh]; qt[qh] = qe; } static void quota_check( char *s, qdata_t **qt) { int i; qdata_t *next; qdata_t *qp; for (i = 0; i < QDATA_HASH_SIZE; i++) { qp = qt[i]; while (qp) { next = qp->next; if (qp->count.bc != qp->dq.bc || qp->count.ic != qp->dq.ic || qp->count.rc != qp->dq.rc) { if (!sflag) { dbprintf(_("%s quota id %u, have/exp"), s, qp->id); if (qp->count.bc != qp->dq.bc) dbprintf(_(" bc %lld/%lld"), qp->dq.bc, qp->count.bc); if (qp->count.ic != qp->dq.ic) dbprintf(_(" ic %lld/%lld"), qp->dq.ic, qp->count.ic); if (qp->count.rc != qp->dq.rc) dbprintf(_(" rc %lld/%lld"), qp->dq.rc, qp->count.rc); dbprintf("\n"); } error++; } xfree(qp); qp = next; } } xfree(qt); } static void quota_init(void) { qudo = mp->m_sb.sb_uquotino != 0 && mp->m_sb.sb_uquotino != NULLFSINO && (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) && (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD); qgdo = mp->m_sb.sb_gquotino != 0 && mp->m_sb.sb_gquotino != NULLFSINO && (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) && (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD); qpdo = mp->m_sb.sb_pquotino != 0 && mp->m_sb.sb_pquotino != NULLFSINO && (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) && (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD); if (qudo) qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); if (qgdo) qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); if (qpdo) qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); } static void scan_ag( xfs_agnumber_t agno) { xfs_agf_t *agf; xfs_agi_t *agi; int i; xfs_sb_t tsb; xfs_sb_t *sb = &tsb; agffreeblks = agflongest = 0; agfbtreeblks = -2; agicount = agifreecount = 0; push_cur(); /* 1 pushed */ set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if (!iocur_top->data) { dbprintf(_("can't read superblock for ag %u\n"), agno); serious_error++; goto pop1_out; } libxfs_sb_from_disk(sb, iocur_top->data); if (sb->sb_magicnum != XFS_SB_MAGIC) { if (!sflag) dbprintf(_("bad sb magic # %#x in ag %u\n"), sb->sb_magicnum, agno); error++; } if (!xfs_sb_good_version(sb)) { if (!sflag) dbprintf(_("bad sb version # %#x in ag %u\n"), sb->sb_versionnum, agno); error++; sbver_err++; } if (!lazycount && xfs_sb_version_haslazysbcount(sb)) { lazycount = 1; } if (agno == 0 && sb->sb_inprogress != 0) { if (!sflag) dbprintf(_("mkfs not completed successfully\n")); error++; } set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp)); if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno) set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart), sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp)); push_cur(); /* 2 pushed */ set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if ((agf = iocur_top->data) == NULL) { dbprintf(_("can't read agf block for ag %u\n"), agno); serious_error++; goto pop2_out; } if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) { if (!sflag) dbprintf(_("bad agf magic # %#x in ag %u\n"), be32_to_cpu(agf->agf_magicnum), agno); error++; } if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) { if (!sflag) dbprintf(_("bad agf version # %#x in ag %u\n"), be32_to_cpu(agf->agf_versionnum), agno); error++; } if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp)) set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno, XFS_SB_BLOCK(mp)); if (sb->sb_agblocks > be32_to_cpu(agf->agf_length)) set_dbmap(agno, be32_to_cpu(agf->agf_length), sb->sb_agblocks - be32_to_cpu(agf->agf_length), DBM_MISSING, agno, XFS_SB_BLOCK(mp)); push_cur(); /* 3 pushed */ set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if ((agi = iocur_top->data) == NULL) { dbprintf(_("can't read agi block for ag %u\n"), agno); serious_error++; goto pop3_out; } if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) { if (!sflag) dbprintf(_("bad agi magic # %#x in ag %u\n"), be32_to_cpu(agi->agi_magicnum), agno); error++; } if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) { if (!sflag) dbprintf(_("bad agi version # %#x in ag %u\n"), be32_to_cpu(agi->agi_versionnum), agno); error++; } if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) && XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp)) set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno, XFS_SB_BLOCK(mp)); scan_freelist(agf); fdblocks--; scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]), 1, scanfunc_bno, TYP_BNOBT); fdblocks--; scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]), be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]), 1, scanfunc_cnt, TYP_CNTBT); if (agf->agf_roots[XFS_BTNUM_RMAP]) { scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]), be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]), 1, scanfunc_rmap, TYP_RMAPBT); } if (agf->agf_refcount_root) { scan_sbtree(agf, be32_to_cpu(agf->agf_refcount_root), be32_to_cpu(agf->agf_refcount_level), 1, scanfunc_refcnt, TYP_REFCBT); } scan_sbtree(agf, be32_to_cpu(agi->agi_root), be32_to_cpu(agi->agi_level), 1, scanfunc_ino, TYP_INOBT); if (agi->agi_free_root) { scan_sbtree(agf, be32_to_cpu(agi->agi_free_root), be32_to_cpu(agi->agi_free_level), 1, scanfunc_fino, TYP_FINOBT); } if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) { if (!sflag) dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"), be32_to_cpu(agf->agf_freeblks), agffreeblks, agno); error++; } if (be32_to_cpu(agf->agf_longest) != agflongest) { if (!sflag) dbprintf(_("agf_longest %u, counted %u in ag %u\n"), be32_to_cpu(agf->agf_longest), agflongest, agno); error++; } if (lazycount && be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) { if (!sflag) dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"), be32_to_cpu(agf->agf_btreeblks), agfbtreeblks, agno); error++; } agf_aggr_freeblks += agffreeblks + agfbtreeblks; if (be32_to_cpu(agi->agi_count) != agicount) { if (!sflag) dbprintf(_("agi_count %u, counted %u in ag %u\n"), be32_to_cpu(agi->agi_count), agicount, agno); error++; } if (be32_to_cpu(agi->agi_freecount) != agifreecount) { if (!sflag) dbprintf(_("agi_freecount %u, counted %u in ag %u\n"), be32_to_cpu(agi->agi_freecount), agifreecount, agno); error++; } for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) { if (!sflag) { xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]); dbprintf(_("agi unlinked bucket %d is %u in ag " "%u (inode=%lld)\n"), i, agino, agno, XFS_AGINO_TO_INO(mp, agno, agino)); } error++; } } pop3_out: pop_cur(); pop2_out: pop_cur(); pop1_out: pop_cur(); } struct agfl_state { xfs_agnumber_t agno; unsigned int count; }; static int scan_agfl( struct xfs_mount *mp, xfs_agblock_t bno, void *priv) { struct agfl_state *as = priv; set_dbmap(as->agno, bno, 1, DBM_FREELIST, as->agno, XFS_AGFL_BLOCK(mp)); as->count++; return 0; } static void scan_freelist( xfs_agf_t *agf) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); struct agfl_state state; if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp)) set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno, XFS_SB_BLOCK(mp)); if (be32_to_cpu(agf->agf_flcount) == 0) return; push_cur(); set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if (iocur_top->data == NULL) { dbprintf(_("can't read agfl block for ag %u\n"), seqno); serious_error++; pop_cur(); return; } /* verify agf values before proceeding */ if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) || be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) { dbprintf(_("agf %d freelist blocks bad, skipping " "freelist scan\n"), seqno); pop_cur(); return; } /* open coded XFS_BUF_TO_AGFL_BNO */ state.count = 0; state.agno = seqno; libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &state); if (state.count != be32_to_cpu(agf->agf_flcount)) { if (!sflag) dbprintf(_("freeblk count %u != flcount %u in ag %u\n"), state.count, be32_to_cpu(agf->agf_flcount), seqno); error++; } fdblocks += state.count; agf_aggr_freeblks += state.count; pop_cur(); } static void scan_lbtree( xfs_fsblock_t root, int nlevels, scan_lbtree_f_t func, dbm_t type, inodata_t *id, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int isroot, typnm_t btype) { push_cur(); set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { if (!sflag) dbprintf(_("can't read btree block %u/%u\n"), XFS_FSB_TO_AGNO(mp, root), XFS_FSB_TO_AGBNO(mp, root)); error++; pop_cur(); return; } (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex, blkmapp, isroot, btype); pop_cur(); } static void scan_sbtree( xfs_agf_t *agf, xfs_agblock_t root, int nlevels, int isroot, scan_sbtree_f_t func, typnm_t btype) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); push_cur(); set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { if (!sflag) dbprintf(_("can't read btree block %u/%u\n"), seqno, root); error++; pop_cur(); return; } (*func)(iocur_top->data, nlevels - 1, agf, root, isroot); pop_cur(); } static void scanfunc_bmap( struct xfs_btree_block *block, int level, dbm_t type, xfs_fsblock_t bno, inodata_t *id, xfs_rfsblock_t *totd, xfs_rfsblock_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int isroot, typnm_t btype) { xfs_agblock_t agbno; xfs_agnumber_t agno; int i; xfs_bmbt_ptr_t *pp; xfs_bmbt_rec_t *rp; agno = XFS_FSB_TO_AGNO(mp, bno); agbno = XFS_FSB_TO_AGBNO(mp, bno); if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC && be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("bad magic # %#x in inode %lld bmbt block " "%u/%u\n"), be32_to_cpu(block->bb_magic), id->ino, agno, agbno); error++; } if (be16_to_cpu(block->bb_level) != level) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("expected level %d got %d in inode %lld bmbt " "block %u/%u\n"), level, be16_to_cpu(block->bb_level), id->ino, agno, agbno); error++; } set_dbmap(agno, agbno, 1, type, agno, agbno); set_inomap(agno, agbno, 1, id); (*toti)++; if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) " "in inode %lld bmap block %lld\n"), be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0], mp->m_bmap_dmxr[0], id->ino, (xfs_fsblock_t)bno); error++; return; } rp = XFS_BMBT_REC_ADDR(mp, block, 1); *nex += be16_to_cpu(block->bb_numrecs); process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd, blkmapp); return; } if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "inode %lld bmap block %lld\n"), be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1], id->ino, (xfs_fsblock_t)bno); error++; return; } pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id, totd, toti, nex, blkmapp, 0, btype); } static void scanfunc_bno( struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot) { int i; xfs_alloc_ptr_t *pp; xfs_alloc_rec_t *rp; xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); xfs_agblock_t lastblock; if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC && be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) { dbprintf(_("bad magic # %#x in btbno block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; return; } fdblocks++; agfbtreeblks++; if (be16_to_cpu(block->bb_level) != level) { if (!sflag) dbprintf(_("expected level %d got %d in btbno block " "%u/%u\n"), level, be16_to_cpu(block->bb_level), seqno, bno); error++; } set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno); if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "btbno block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0], mp->m_alloc_mxr[0], seqno, bno); serious_error++; return; } rp = XFS_ALLOC_REC_ADDR(mp, block, 1); lastblock = 0; for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, seqno, bno); if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) { dbprintf(_( "out-of-order bno btree record %d (%u %u) block %u/%u\n"), i, be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount), be32_to_cpu(agf->agf_seqno), bno); serious_error++; } else { lastblock = be32_to_cpu(rp[i].ar_startblock); } } return; } if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block " "%u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1], mp->m_alloc_mxr[1], seqno, bno); serious_error++; return; } pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT); } static void scanfunc_cnt( struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int i; xfs_alloc_ptr_t *pp; xfs_alloc_rec_t *rp; xfs_extlen_t lastcount; if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC && be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) { dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; return; } fdblocks++; agfbtreeblks++; if (be16_to_cpu(block->bb_level) != level) { if (!sflag) dbprintf(_("expected level %d got %d in btcnt block " "%u/%u\n"), level, be16_to_cpu(block->bb_level), seqno, bno); error++; } set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno); if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "btbno block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0], mp->m_alloc_mxr[0], seqno, bno); serious_error++; return; } rp = XFS_ALLOC_REC_ADDR(mp, block, 1); lastcount = 0; for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2, seqno, bno); fdblocks += be32_to_cpu(rp[i].ar_blockcount); agffreeblks += be32_to_cpu(rp[i].ar_blockcount); if (be32_to_cpu(rp[i].ar_blockcount) > agflongest) agflongest = be32_to_cpu(rp[i].ar_blockcount); if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) { dbprintf(_( "out-of-order cnt btree record %d (%u %u) block %u/%u\n"), i, be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount), be32_to_cpu(agf->agf_seqno), bno); } else { lastcount = be32_to_cpu(rp[i].ar_blockcount); } } return; } if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block " "%u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1], mp->m_alloc_mxr[1], seqno, bno); serious_error++; return; } pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT); } static void scanfunc_ino( struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot) { xfs_agino_t agino; xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int i; int isfree; int j; int freecount; int nfree; int off; xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; xfs_agblock_t agbno; xfs_agblock_t end_agbno; struct xfs_dinode *dip; int blks_per_buf; int inodes_per_buf; int ioff; struct xfs_ino_geometry *igeo = M_IGEO(mp); if (xfs_sb_version_hassparseinodes(&mp->m_sb)) blks_per_buf = igeo->blocks_per_cluster; else blks_per_buf = igeo->ialloc_blks; inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf), XFS_INODES_PER_CHUNK); if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC && be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) { dbprintf(_("bad magic # %#x in inobt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; return; } if (be16_to_cpu(block->bb_level) != level) { if (!sflag) dbprintf(_("expected level %d got %d in inobt block " "%u/%u\n"), level, be16_to_cpu(block->bb_level), seqno, bno); error++; } set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno); if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "inobt block %u/%u\n"), be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0], igeo->inobt_mxr[0], seqno, bno); serious_error++; return; } rp = XFS_INOBT_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { agino = be32_to_cpu(rp[i].ir_startino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); off = XFS_AGINO_TO_OFFSET(mp, agino); end_agbno = agbno + igeo->ialloc_blks; if (off == 0) { if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && mp->m_sb.sb_inoalignmt && (XFS_INO_TO_AGBNO(mp, agino) % mp->m_sb.sb_inoalignmt)) sbversion &= ~XFS_SB_VERSION_ALIGNBIT; } push_cur(); ioff = 0; nfree = 0; while (agbno < end_agbno && ioff < XFS_INODES_PER_CHUNK) { if (xfs_inobt_is_sparse_disk(&rp[i], ioff)) goto next_buf; if (off < XFS_INODES_PER_CHUNK) set_dbmap(seqno, agbno, blks_per_buf, DBM_INODE, seqno, bno); icount += inodes_per_buf; agicount += inodes_per_buf; set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, seqno, agbno), XFS_FSB_TO_BB(mp, blks_per_buf), DB_RING_IGN, NULL); if (iocur_top->data == NULL) { if (!sflag) dbprintf(_("can't read inode block " "%u/%u\n"), seqno, agbno); error++; goto next_buf; } for (j = 0; j < inodes_per_buf; j++) { isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], ioff + j); if (isfree) nfree++; dip = (xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)); process_inode(agf, agino + ioff + j, dip, isfree); } next_buf: agbno += blks_per_buf; ioff += inodes_per_buf; } if (xfs_sb_version_hassparseinodes(&mp->m_sb)) freecount = rp[i].ir_u.sp.ir_freecount; else freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount); ifree += freecount; agifreecount += freecount; if (nfree != freecount) { if (!sflag) dbprintf(_("ir_freecount/free mismatch, " "inode chunk %u/%u, freecount " "%d nfree %d\n"), seqno, agino, freecount, nfree); error++; } pop_cur(); } return; } if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block " "%u/%u\n"), be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1], igeo->inobt_mxr[1], seqno, bno); serious_error++; return; } pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT); } static void scanfunc_fino( struct xfs_btree_block *block, int level, struct xfs_agf *agf, xfs_agblock_t bno, int isroot) { xfs_agino_t agino; xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int i; int off; xfs_inobt_ptr_t *pp; struct xfs_inobt_rec *rp; xfs_agblock_t agbno; xfs_agblock_t end_agbno; int blks_per_buf; int inodes_per_buf; int ioff; struct xfs_ino_geometry *igeo = M_IGEO(mp); if (xfs_sb_version_hassparseinodes(&mp->m_sb)) blks_per_buf = igeo->blocks_per_cluster; else blks_per_buf = igeo->ialloc_blks; inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf), XFS_INODES_PER_CHUNK); if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC && be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) { dbprintf(_("bad magic # %#x in finobt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; return; } if (be16_to_cpu(block->bb_level) != level) { if (!sflag) dbprintf(_("expected level %d got %d in finobt block " "%u/%u\n"), level, be16_to_cpu(block->bb_level), seqno, bno); error++; } set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno); if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "finobt block %u/%u\n"), be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0], igeo->inobt_mxr[0], seqno, bno); serious_error++; return; } rp = XFS_INOBT_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { agino = be32_to_cpu(rp[i].ir_startino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); off = XFS_AGINO_TO_OFFSET(mp, agino); end_agbno = agbno + igeo->ialloc_blks; if (off == 0) { if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && mp->m_sb.sb_inoalignmt && (XFS_INO_TO_AGBNO(mp, agino) % mp->m_sb.sb_inoalignmt)) sbversion &= ~XFS_SB_VERSION_ALIGNBIT; } ioff = 0; while (agbno < end_agbno && ioff < XFS_INODES_PER_CHUNK) { if (xfs_inobt_is_sparse_disk(&rp[i], ioff)) goto next_buf; check_set_dbmap(seqno, agbno, (xfs_extlen_t)max(1, inodes_per_buf >> mp->m_sb.sb_inopblog), DBM_INODE, DBM_INODE, seqno, bno); next_buf: agbno += blks_per_buf; ioff += inodes_per_buf; } } return; } if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block " "%u/%u\n"), be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1], igeo->inobt_mxr[1], seqno, bno); serious_error++; return; } pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_fino, TYP_FINOBT); } static void scanfunc_rmap( struct xfs_btree_block *block, int level, struct xfs_agf *agf, xfs_agblock_t bno, int isroot) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int i; xfs_rmap_ptr_t *pp; struct xfs_rmap_rec *rp; xfs_agblock_t lastblock; if (be32_to_cpu(block->bb_magic) != XFS_RMAP_CRC_MAGIC) { dbprintf(_("bad magic # %#x in rmapbt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; return; } if (be16_to_cpu(block->bb_level) != level) { if (!sflag) dbprintf(_("expected level %d got %d in rmapbt block " "%u/%u\n"), level, be16_to_cpu(block->bb_level), seqno, bno); error++; } if (!isroot) { fdblocks++; agfbtreeblks++; } set_dbmap(seqno, bno, 1, DBM_BTRMAP, seqno, bno); if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[0])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "rmapbt block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[0], mp->m_rmap_mxr[0], seqno, bno); serious_error++; return; } rp = XFS_RMAP_REC_ADDR(block, 1); lastblock = 0; for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { if (be32_to_cpu(rp[i].rm_startblock) < lastblock) { dbprintf(_( "out-of-order rmap btree record %d (%u %u) block %u/%u\n"), i, be32_to_cpu(rp[i].rm_startblock), be32_to_cpu(rp[i].rm_startblock), be32_to_cpu(agf->agf_seqno), bno); } else { lastblock = be32_to_cpu(rp[i].rm_startblock); } } return; } if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[1])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rmapbt " "block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1], mp->m_rmap_mxr[1], seqno, bno); serious_error++; return; } pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_rmap, TYP_RMAPBT); } static void scanfunc_refcnt( struct xfs_btree_block *block, int level, struct xfs_agf *agf, xfs_agblock_t bno, int isroot) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int i; xfs_refcount_ptr_t *pp; struct xfs_refcount_rec *rp; xfs_agblock_t lastblock; if (be32_to_cpu(block->bb_magic) != XFS_REFC_CRC_MAGIC) { dbprintf(_("bad magic # %#x in refcntbt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; return; } if (be16_to_cpu(block->bb_level) != level) { if (!sflag) dbprintf(_("expected level %d got %d in refcntbt block " "%u/%u\n"), level, be16_to_cpu(block->bb_level), seqno, bno); error++; } set_dbmap(seqno, bno, 1, DBM_BTREFC, seqno, bno); if (level == 0) { if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[0] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[0])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " "refcntbt block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[0], mp->m_refc_mxr[0], seqno, bno); serious_error++; return; } rp = XFS_REFCOUNT_REC_ADDR(block, 1); lastblock = 0; for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { if (be32_to_cpu(rp[i].rc_refcount) == 1) { xfs_agblock_t agbno; char *msg; agbno = be32_to_cpu(rp[i].rc_startblock); if (agbno >= XFS_REFC_COW_START) { agbno -= XFS_REFC_COW_START; msg = _( "leftover CoW extent (%u/%u) len %u\n"); } else { msg = _( "leftover CoW extent at unexpected address (%u/%u) len %u\n"); } dbprintf(msg, seqno, agbno, be32_to_cpu(rp[i].rc_blockcount)); set_dbmap(seqno, agbno, be32_to_cpu(rp[i].rc_blockcount), DBM_COWDATA, seqno, bno); } else { set_dbmap(seqno, be32_to_cpu(rp[i].rc_startblock), be32_to_cpu(rp[i].rc_blockcount), DBM_RLDATA, seqno, bno); } if (be32_to_cpu(rp[i].rc_startblock) < lastblock) { dbprintf(_( "out-of-order refcnt btree record %d (%u %u) block %u/%u\n"), i, be32_to_cpu(rp[i].rc_startblock), be32_to_cpu(rp[i].rc_startblock), be32_to_cpu(agf->agf_seqno), bno); } else { lastblock = be32_to_cpu(rp[i].rc_startblock) + be32_to_cpu(rp[i].rc_blockcount); } } return; } if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[1] || (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[1])) { dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in refcntbt " "block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[1], mp->m_refc_mxr[1], seqno, bno); serious_error++; return; } pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_refcnt, TYP_REFCBT); } static void set_dbmap( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type, xfs_agnumber_t c_agno, xfs_agblock_t c_agbno) { check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno); } static void set_inomap( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, inodata_t *id) { xfs_extlen_t i; inodata_t **idp; int mayprint; if (!check_inomap(agno, agbno, len, id->ino)) return; mayprint = verbose | id->ilist | blist_size; for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) { *idp = id; if (mayprint && (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i))) dbprintf(_("setting inode to %lld for block %u/%u\n"), id->ino, agno, agbno + i); } } static void set_rdbmap( xfs_rfsblock_t bno, xfs_extlen_t len, dbm_t type) { check_set_rdbmap(bno, len, DBM_UNKNOWN, type); } static void set_rinomap( xfs_rfsblock_t bno, xfs_extlen_t len, inodata_t *id) { xfs_extlen_t i; inodata_t **idp; int mayprint; if (!check_rinomap(bno, len, id->ino)) return; mayprint = verbose | id->ilist | blist_size; for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno]; i < len; i++, idp++) { *idp = id; if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i))) dbprintf(_("setting inode to %lld for rtblock %llu\n"), id->ino, bno + i); } } static void setlink_inode( inodata_t *id, nlink_t nlink, int isdir, int security) { id->link_set = nlink; id->isdir = isdir; id->security = security; if (verbose || id->ilist) dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink, isdir ? "is" : "not"); } xfsprogs-5.3.0/db/check.h0000644000175000017500000000023113435336036015061 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void check_init(void); xfsprogs-5.3.0/db/command.c0000644000175000017500000000502713570057155015427 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "addr.h" #include "attrset.h" #include "block.h" #include "bmap.h" #include "check.h" #include "command.h" #include "debug.h" #include "type.h" #include "echo.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "agf.h" #include "agfl.h" #include "agi.h" #include "frag.h" #include "freesp.h" #include "help.h" #include "hash.h" #include "inode.h" #include "input.h" #include "io.h" #include "logformat.h" #include "metadump.h" #include "output.h" #include "print.h" #include "quit.h" #include "sb.h" #include "write.h" #include "malloc.h" #include "dquot.h" #include "fsmap.h" #include "crc.h" #include "fuzz.h" cmdinfo_t *cmdtab; int ncmds; static int cmd_compare(const void *a, const void *b) { return strcmp(((const cmdinfo_t *)a)->name, ((const cmdinfo_t *)b)->name); } void add_command( const cmdinfo_t *ci) { cmdtab = xrealloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); cmdtab[ncmds - 1] = *ci; qsort(cmdtab, ncmds, sizeof(*cmdtab), cmd_compare); } int command( int argc, char **argv) { char *cmd; const cmdinfo_t *ct; cmd = argv[0]; ct = find_command(cmd); if (ct == NULL) { dbprintf(_("command %s not found\n"), cmd); return 0; } if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { dbprintf(_("bad argument count %d to %s, expected "), argc-1, cmd); if (ct->argmax == -1) dbprintf(_("at least %d"), ct->argmin); else if (ct->argmin == ct->argmax) dbprintf("%d", ct->argmin); else dbprintf(_("between %d and %d"), ct->argmin, ct->argmax); dbprintf(_(" arguments\n")); return 0; } platform_getoptreset(); return ct->cfunc(argc, argv); } const cmdinfo_t * find_command( const char *cmd) { cmdinfo_t *ct; for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { if (strcmp(ct->name, cmd) == 0 || (ct->altname && strcmp(ct->altname, cmd) == 0)) return (const cmdinfo_t *)ct; } return NULL; } void init_commands(void) { addr_init(); agf_init(); agfl_init(); agi_init(); attrset_init(); block_init(); bmap_init(); btdump_init(); btheight_init(); check_init(); convert_init(); crc_init(); debug_init(); echo_init(); frag_init(); freesp_init(); fsmap_init(); help_init(); hash_init(); info_init(); inode_init(); input_init(); logres_init(); logformat_init(); io_init(); metadump_init(); output_init(); print_init(); quit_init(); sb_init(); type_init(); write_init(); dquot_init(); fuzz_init(); } xfsprogs-5.3.0/db/command.h0000644000175000017500000000137513570057155015436 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ typedef int (*cfunc_t)(int argc, char **argv); typedef void (*helpfunc_t)(void); typedef struct cmdinfo { const char *name; const char *altname; cfunc_t cfunc; int argmin; int argmax; int canpush; const char *args; const char *oneline; helpfunc_t help; } cmdinfo_t; extern cmdinfo_t *cmdtab; extern int ncmds; extern void add_command(const cmdinfo_t *ci); extern int command(int argc, char **argv); extern const cmdinfo_t *find_command(const char *cmd); extern void init_commands(void); extern void convert_init(void); extern void btdump_init(void); extern void info_init(void); extern void btheight_init(void); xfsprogs-5.3.0/db/convert.c0000644000175000017500000001653413570057155015476 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "output.h" #include "init.h" #define M(A) (1 << CT_ ## A) #define agblock_to_bytes(x) \ ((uint64_t)(x) << mp->m_sb.sb_blocklog) #define agino_to_bytes(x) \ ((uint64_t)(x) << mp->m_sb.sb_inodelog) #define agnumber_to_bytes(x) \ agblock_to_bytes((uint64_t)(x) * mp->m_sb.sb_agblocks) #define daddr_to_bytes(x) \ ((uint64_t)(x) << BBSHIFT) #define fsblock_to_bytes(x) \ (agnumber_to_bytes(XFS_FSB_TO_AGNO(mp, (x))) + \ agblock_to_bytes(XFS_FSB_TO_AGBNO(mp, (x)))) #define ino_to_bytes(x) \ (agnumber_to_bytes(XFS_INO_TO_AGNO(mp, (x))) + \ agino_to_bytes(XFS_INO_TO_AGINO(mp, (x)))) #define inoidx_to_bytes(x) \ ((uint64_t)(x) << mp->m_sb.sb_inodelog) typedef enum { CT_NONE = -1, CT_AGBLOCK, /* xfs_agblock_t */ CT_AGINO, /* xfs_agino_t */ CT_AGNUMBER, /* xfs_agno_t */ CT_BBOFF, /* byte offset in daddr */ CT_BLKOFF, /* byte offset in fsb/agb */ CT_BYTE, /* byte in filesystem */ CT_DADDR, /* daddr_t */ CT_FSBLOCK, /* xfs_fsblock_t */ CT_INO, /* xfs_ino_t */ CT_INOIDX, /* index of inode in fsblock */ CT_INOOFF, /* byte offset in inode */ NCTS } ctype_t; typedef struct ctydesc { ctype_t ctype; int allowed; const char **names; } ctydesc_t; typedef union { xfs_agblock_t agblock; xfs_agino_t agino; xfs_agnumber_t agnumber; int bboff; int blkoff; uint64_t byte; xfs_daddr_t daddr; xfs_fsblock_t fsblock; xfs_ino_t ino; int inoidx; int inooff; } cval_t; static uint64_t bytevalue(ctype_t ctype, cval_t *val); static int convert_f(int argc, char **argv); static int getvalue(char *s, ctype_t ctype, cval_t *val); static ctype_t lookupcty(char *ctyname); static const char *agblock_names[] = { "agblock", "agbno", NULL }; static const char *agino_names[] = { "agino", "aginode", NULL }; static const char *agnumber_names[] = { "agnumber", "agno", NULL }; static const char *bboff_names[] = { "bboff", "daddroff", NULL }; static const char *blkoff_names[] = { "blkoff", "fsboff", "agboff", NULL }; static const char *byte_names[] = { "byte", "fsbyte", NULL }; static const char *daddr_names[] = { "daddr", "bb", NULL }; static const char *fsblock_names[] = { "fsblock", "fsb", "fsbno", NULL }; static const char *ino_names[] = { "ino", "inode", NULL }; static const char *inoidx_names[] = { "inoidx", "offset", NULL }; static const char *inooff_names[] = { "inooff", "inodeoff", NULL }; static const ctydesc_t ctydescs[NCTS] = { { CT_AGBLOCK, M(AGNUMBER)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF), agblock_names }, { CT_AGINO, M(AGNUMBER)|M(INOOFF), agino_names }, { CT_AGNUMBER, M(AGBLOCK)|M(AGINO)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF), agnumber_names }, { CT_BBOFF, M(AGBLOCK)|M(AGNUMBER)|M(DADDR)|M(FSBLOCK), bboff_names }, { CT_BLKOFF, M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK), blkoff_names }, { CT_BYTE, 0, byte_names }, { CT_DADDR, M(BBOFF), daddr_names }, { CT_FSBLOCK, M(BBOFF)|M(BLKOFF)|M(INOIDX), fsblock_names }, { CT_INO, M(INOOFF), ino_names }, { CT_INOIDX, M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK)|M(INOOFF), inoidx_names }, { CT_INOOFF, M(AGBLOCK)|M(AGINO)|M(AGNUMBER)|M(FSBLOCK)|M(INO)|M(INOIDX), inooff_names }, }; static const cmdinfo_t convert_cmd = { "convert", NULL, convert_f, 3, 9, 0, "type num [type num]... type", "convert from one address form to another", NULL }; static uint64_t bytevalue(ctype_t ctype, cval_t *val) { switch (ctype) { case CT_AGBLOCK: return agblock_to_bytes(val->agblock); case CT_AGINO: return agino_to_bytes(val->agino); case CT_AGNUMBER: return agnumber_to_bytes(val->agnumber); case CT_BBOFF: return (uint64_t)val->bboff; case CT_BLKOFF: return (uint64_t)val->blkoff; case CT_BYTE: return val->byte; case CT_DADDR: return daddr_to_bytes(val->daddr); case CT_FSBLOCK: return fsblock_to_bytes(val->fsblock); case CT_INO: return ino_to_bytes(val->ino); case CT_INOIDX: return inoidx_to_bytes(val->inoidx); case CT_INOOFF: return (uint64_t)val->inooff; case CT_NONE: case NCTS: break; } /* NOTREACHED */ return 0; } static int convert_f(int argc, char **argv) { ctype_t c; int conmask; cval_t cvals[NCTS] = {}; int i; int mask; uint64_t v; ctype_t wtype; /* move past the "convert" command */ argc--; argv++; if ((argc % 2) != 1) { dbprintf(_("bad argument count %d to convert, expected 3,5,7,9 " "arguments\n"), argc); return 0; } if ((wtype = lookupcty(argv[argc - 1])) == CT_NONE) { dbprintf(_("unknown conversion type %s\n"), argv[argc - 1]); return 0; } for (i = mask = conmask = 0; i < (argc - 1) / 2; i++) { c = lookupcty(argv[i * 2]); if (c == CT_NONE) { dbprintf(_("unknown conversion type %s\n"), argv[i * 2]); return 0; } if (c == wtype) { dbprintf(_("result type same as argument\n")); return 0; } if (conmask & (1 << c)) { dbprintf(_("conflicting conversion type %s\n"), argv[i * 2]); return 0; } if (!getvalue(argv[i * 2 + 1], c, &cvals[c])) return 0; mask |= 1 << c; conmask |= ~ctydescs[c].allowed; } if (cur_agno != NULLAGNUMBER && (conmask & M(AGNUMBER)) == 0) { cvals[CT_AGNUMBER].agnumber = cur_agno; mask |= M(AGNUMBER); } v = 0; for (c = (ctype_t)0; c < NCTS; c++) { if (!(mask & (1 << c))) continue; v += bytevalue(c, &cvals[c]); } switch (wtype) { case CT_AGBLOCK: v = xfs_daddr_to_agbno(mp, v >> BBSHIFT); break; case CT_AGINO: v = (v >> mp->m_sb.sb_inodelog) % XFS_AGB_TO_AGINO(mp, mp->m_sb.sb_agblocks); break; case CT_AGNUMBER: v = xfs_daddr_to_agno(mp, v >> BBSHIFT); break; case CT_BBOFF: v &= BBMASK; break; case CT_BLKOFF: v &= mp->m_blockmask; break; case CT_BYTE: break; case CT_DADDR: v >>= BBSHIFT; break; case CT_FSBLOCK: v = XFS_DADDR_TO_FSB(mp, v >> BBSHIFT); break; case CT_INO: v = XFS_AGINO_TO_INO(mp, xfs_daddr_to_agno(mp, v >> BBSHIFT), (v >> mp->m_sb.sb_inodelog) % XFS_AGB_TO_AGINO(mp, mp->m_sb.sb_agblocks)); break; case CT_INOIDX: v = (v >> mp->m_sb.sb_inodelog) & (mp->m_sb.sb_inopblock - 1); break; case CT_INOOFF: v &= mp->m_sb.sb_inodesize - 1; break; case CT_NONE: case NCTS: /* NOTREACHED */ break; } dbprintf("0x%llx (%llu)\n", v, v); return 0; } void convert_init(void) { add_command(&convert_cmd); } static int getvalue(char *s, ctype_t ctype, cval_t *val) { char *p; uint64_t v; v = strtoull(s, &p, 0); if (*p != '\0') { dbprintf(_("%s is not a number\n"), s); return 0; } switch (ctype) { case CT_AGBLOCK: val->agblock = (xfs_agblock_t)v; break; case CT_AGINO: val->agino = (xfs_agino_t)v; break; case CT_AGNUMBER: val->agnumber = (xfs_agnumber_t)v; break; case CT_BBOFF: val->bboff = (int)v; break; case CT_BLKOFF: val->blkoff = (int)v; break; case CT_BYTE: val->byte = (uint64_t)v; break; case CT_DADDR: val->daddr = (xfs_daddr_t)v; break; case CT_FSBLOCK: val->fsblock = (xfs_fsblock_t)v; break; case CT_INO: val->ino = (xfs_ino_t)v; break; case CT_INOIDX: val->inoidx = (int)v; break; case CT_INOOFF: val->inooff = (int)v; break; case CT_NONE: case NCTS: /* NOTREACHED */ break; } return 1; } static ctype_t lookupcty(char *ctyname) { ctype_t cty; const char **name; for (cty = (ctype_t)0; cty < NCTS; cty++) { for (name = ctydescs[cty].names; *name; name++) { if (strcmp(ctyname, *name) == 0) return cty; } } return CT_NONE; } xfsprogs-5.3.0/db/crc.c0000644000175000017500000000743013435336036014556 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "addr.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "flist.h" #include "io.h" #include "init.h" #include "output.h" #include "bit.h" #include "print.h" #include "crc.h" static int crc_f(int argc, char **argv); static void crc_help(void); static const cmdinfo_t crc_cmd = { "crc", NULL, crc_f, 0, 1, 0, "[-i|-r|-v]", N_("manipulate crc values for V5 filesystem structures"), crc_help }; void crc_init(void) { if (xfs_sb_version_hascrc(&mp->m_sb)) add_command(&crc_cmd); } static void crc_help(void) { dbprintf(_( "\n" " 'crc' validates, invalidates, or recalculates the crc value for\n" " the current on-disk metadata structures in Version 5 filesystems.\n" "\n" " Usage: \"crc [-i|-r|-v]\"\n" "\n" )); } static int crc_f( int argc, char **argv) { const struct xfs_buf_ops *stashed_ops = NULL; extern char *progname; const field_t *fields; const ftattr_t *fa; flist_t *fl; int invalidate = 0; int recalculate = 0; int validate = 0; int c; if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } if (cur_typ->fields == NULL) { dbprintf(_("current type (%s) is not a structure\n"), cur_typ->name); return 0; } if (argc) while ((c = getopt(argc, argv, "irv")) != EOF) { switch (c) { case 'i': invalidate = 1; break; case 'r': recalculate = 1; break; case 'v': validate = 1; break; default: dbprintf(_("bad option for crc command\n")); return 0; } } else validate = 1; if (invalidate + recalculate + validate > 1) { dbprintf(_("crc command accepts only one option\n")); return 0; } if ((invalidate || recalculate) && ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode)) { dbprintf(_("%s not in expert mode, writing disabled\n"), progname); return 0; } fields = cur_typ->fields; /* if we're a root field type, go down 1 layer to get field list */ if (fields->name[0] == '\0') { fa = &ftattrtab[fields->ftyp]; ASSERT(fa->ftyp == fields->ftyp); fields = fa->subfld; } /* Search for a CRC field */ fl = flist_find_ftyp(fields, FLDT_CRC); if (!fl) { dbprintf(_("No CRC field found for type %s\n"), cur_typ->name); return 0; } /* run down the field list and set offsets into the data */ if (!flist_parse(fields, fl, iocur_top->data, 0)) { flist_free(fl); dbprintf(_("parsing error\n")); return 0; } if (invalidate) { struct xfs_buf_ops nowrite_ops; flist_t *sfl; int bit_length; int parentoffset; uint32_t crc; sfl = fl; parentoffset = 0; while (sfl->child) { parentoffset = sfl->offset; sfl = sfl->child; } ASSERT(sfl->fld->ftyp == FLDT_CRC); bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0); bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset); crc = getbitval(iocur_top->data, sfl->offset, bit_length, BVUNSIGNED); /* Off by one, ignore endianness - we're just corrupting it. */ crc++; setbitval(iocur_top->data, sfl->offset, bit_length, &crc); /* Temporarily remove write verifier to write a bad CRC */ stashed_ops = iocur_top->bp->b_ops; nowrite_ops.verify_read = stashed_ops->verify_read; nowrite_ops.verify_write = xfs_dummy_verify; iocur_top->bp->b_ops = &nowrite_ops; } if (invalidate || recalculate) { if (invalidate) dbprintf(_("Invalidating CRC:\n")); else dbprintf(_("Recalculating CRC:\n")); write_cur(); if (stashed_ops) iocur_top->bp->b_ops = stashed_ops; /* re-verify to get proper b_error state */ iocur_top->bp->b_ops->verify_read(iocur_top->bp); } else dbprintf(_("Verifying CRC:\n")); /* And show us what we've got! */ flist_print(fl); print_flist(fl); flist_free(fl); return 0; } xfsprogs-5.3.0/db/crc.h0000644000175000017500000000022313466663244014564 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 Red Hat, Inc. * All Rights Reserved. */ struct field; extern void crc_init(void); xfsprogs-5.3.0/db/debug.c0000644000175000017500000000131013435336036015064 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "debug.h" #include "output.h" static int debug_f(int argc, char **argv); static const cmdinfo_t debug_cmd = { "debug", NULL, debug_f, 0, 1, 0, N_("[flagbits]"), N_("set debug option bits"), NULL }; long debug_state; static int debug_f( int argc, char **argv) { char *p; if (argc > 1) { debug_state = strtol(argv[1], &p, 0); if (*p != '\0') { dbprintf(_("bad value for debug %s\n"), argv[1]); return 0; } } dbprintf("debug = %ld\n", debug_state); return 0; } void debug_init(void) { add_command(&debug_cmd); } xfsprogs-5.3.0/db/debug.h0000644000175000017500000000031313435336036015073 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #define DEBUG_FLIST 0x1 extern long debug_state; extern void debug_init(void); xfsprogs-5.3.0/db/dir2.c0000644000175000017500000007300513435336036014650 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "bit.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "dir2.h" #include "init.h" #include "output.h" static int dir2_block_hdr_count(void *obj, int startoff); static int dir2_block_leaf_count(void *obj, int startoff); static int dir2_block_leaf_offset(void *obj, int startoff, int idx); static int dir2_block_tail_count(void *obj, int startoff); static int dir2_block_tail_offset(void *obj, int startoff, int idx); static int dir2_block_u_count(void *obj, int startoff); static int dir2_block_u_offset(void *obj, int startoff, int idx); static int dir2_data_union_freetag_count(void *obj, int startoff); static int dir2_data_union_inumber_count(void *obj, int startoff); static int dir2_data_union_length_count(void *obj, int startoff); static int dir2_data_union_name_count(void *obj, int startoff); static int dir2_data_union_namelen_count(void *obj, int startoff); static int dir2_data_union_tag_count(void *obj, int startoff); static int dir2_data_union_tag_offset(void *obj, int startoff, int idx); static int dir2_data_hdr_count(void *obj, int startoff); static int dir2_data_u_count(void *obj, int startoff); static int dir2_data_u_offset(void *obj, int startoff, int idx); static int dir2_free_bests_count(void *obj, int startoff); static int dir2_free_hdr_count(void *obj, int startoff); static int dir2_leaf_bests_count(void *obj, int startoff); static int dir2_leaf_bests_offset(void *obj, int startoff, int idx); static int dir2_leaf_ents_count(void *obj, int startoff); static int dir2_leaf_hdr_count(void *obj, int startoff); static int dir2_leaf_tail_count(void *obj, int startoff); static int dir2_leaf_tail_offset(void *obj, int startoff, int idx); static int dir2_node_btree_count(void *obj, int startoff); static int dir2_node_hdr_count(void *obj, int startoff); const field_t dir2_hfld[] = { { "", FLDT_DIR2, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define BOFF(f) bitize(offsetof(struct xfs_dir2_data_hdr, f)) #define DOFF(f) bitize(offsetof(struct xfs_dir2_data_hdr, f)) #define FOFF(f) bitize(offsetof(struct xfs_dir2_free, f)) #define LOFF(f) bitize(offsetof(struct xfs_dir2_leaf, f)) #define NOFF(f) bitize(offsetof(struct xfs_da_intnode, f)) const field_t dir2_flds[] = { { "bhdr", FLDT_DIR2_DATA_HDR, OI(BOFF(magic)), dir2_block_hdr_count, FLD_COUNT, TYP_NONE }, { "bu", FLDT_DIR2_DATA_UNION, dir2_block_u_offset, dir2_block_u_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "bleaf", FLDT_DIR2_LEAF_ENTRY, dir2_block_leaf_offset, dir2_block_leaf_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "btail", FLDT_DIR2_BLOCK_TAIL, dir2_block_tail_offset, dir2_block_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "dhdr", FLDT_DIR2_DATA_HDR, OI(DOFF(magic)), dir2_data_hdr_count, FLD_COUNT, TYP_NONE }, { "du", FLDT_DIR2_DATA_UNION, dir2_data_u_offset, dir2_data_u_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "lhdr", FLDT_DIR2_LEAF_HDR, OI(LOFF(hdr)), dir2_leaf_hdr_count, FLD_COUNT, TYP_NONE }, { "lbests", FLDT_DIR2_DATA_OFF, dir2_leaf_bests_offset, dir2_leaf_bests_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "lents", FLDT_DIR2_LEAF_ENTRY, OI(LOFF(__ents)), dir2_leaf_ents_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset, dir2_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "nhdr", FLDT_DA_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count, FLD_COUNT, TYP_NONE }, { "nbtree", FLDT_DA_NODE_ENTRY, OI(NOFF(__btree)), dir2_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "fhdr", FLDT_DIR2_FREE_HDR, OI(FOFF(hdr)), dir2_free_hdr_count, FLD_COUNT, TYP_NONE }, { "fbests", FLDT_DIR2_DATA_OFFNZ, OI(FOFF(bests)), dir2_free_bests_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { NULL } }; #define BTOFF(f) bitize(offsetof(xfs_dir2_block_tail_t, f)) const field_t dir2_block_tail_flds[] = { { "count", FLDT_UINT32D, OI(BTOFF(count)), C1, 0, TYP_NONE }, { "stale", FLDT_UINT32D, OI(BTOFF(stale)), C1, 0, TYP_NONE }, { NULL } }; #define DFOFF(f) bitize(offsetof(xfs_dir2_data_free_t, f)) const field_t dir2_data_free_flds[] = { { "offset", FLDT_DIR2_DATA_OFF, OI(DFOFF(offset)), C1, 0, TYP_NONE }, { "length", FLDT_DIR2_DATA_OFF, OI(DFOFF(length)), C1, 0, TYP_NONE }, { NULL } }; #define DHOFF(f) bitize(offsetof(xfs_dir2_data_hdr_t, f)) const field_t dir2_data_hdr_flds[] = { { "magic", FLDT_UINT32X, OI(DHOFF(magic)), C1, 0, TYP_NONE }, { "bestfree", FLDT_DIR2_DATA_FREE, OI(DHOFF(bestfree)), CI(XFS_DIR2_DATA_FD_COUNT), FLD_ARRAY, TYP_NONE }, { NULL } }; #define DEOFF(f) bitize(offsetof(xfs_dir2_data_entry_t, f)) #define DUOFF(f) bitize(offsetof(xfs_dir2_data_unused_t, f)) const field_t dir2_data_union_flds[] = { { "freetag", FLDT_UINT16X, OI(DUOFF(freetag)), dir2_data_union_freetag_count, FLD_COUNT, TYP_NONE }, { "inumber", FLDT_INO, OI(DEOFF(inumber)), dir2_data_union_inumber_count, FLD_COUNT, TYP_INODE }, { "length", FLDT_DIR2_DATA_OFF, OI(DUOFF(length)), dir2_data_union_length_count, FLD_COUNT, TYP_NONE }, { "namelen", FLDT_UINT8D, OI(DEOFF(namelen)), dir2_data_union_namelen_count, FLD_COUNT, TYP_NONE }, { "name", FLDT_CHARNS, OI(DEOFF(name)), dir2_data_union_name_count, FLD_COUNT, TYP_NONE }, { "tag", FLDT_DIR2_DATA_OFF, dir2_data_union_tag_offset, dir2_data_union_tag_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, { NULL } }; #define LEOFF(f) bitize(offsetof(xfs_dir2_leaf_entry_t, f)) const field_t dir2_leaf_entry_flds[] = { { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE }, { "address", FLDT_UINT32X, OI(LEOFF(address)), C1, 0, TYP_NONE }, { NULL } }; #define LHOFF(f) bitize(offsetof(xfs_dir2_leaf_hdr_t, f)) const field_t dir2_leaf_hdr_flds[] = { { "info", FLDT_DA_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, { "stale", FLDT_UINT16D, OI(LHOFF(stale)), C1, 0, TYP_NONE }, { NULL } }; #define LTOFF(f) bitize(offsetof(xfs_dir2_leaf_tail_t, f)) const field_t dir2_leaf_tail_flds[] = { { "bestcount", FLDT_UINT32D, OI(LTOFF(bestcount)), C1, 0, TYP_NONE }, { NULL } }; #define FHOFF(f) bitize(offsetof(xfs_dir2_free_hdr_t, f)) const field_t dir2_free_hdr_flds[] = { { "magic", FLDT_UINT32X, OI(FHOFF(magic)), C1, 0, TYP_NONE }, { "firstdb", FLDT_INT32D, OI(FHOFF(firstdb)), C1, 0, TYP_NONE }, { "nvalid", FLDT_INT32D, OI(FHOFF(nvalid)), C1, 0, TYP_NONE }, { "nused", FLDT_INT32D, OI(FHOFF(nused)), C1, 0, TYP_NONE }, { NULL } }; #define DBOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f)) const field_t da_blkinfo_flds[] = { { "forw", FLDT_DIRBLOCK, OI(DBOFF(forw)), C1, 0, TYP_INODATA }, { "back", FLDT_DIRBLOCK, OI(DBOFF(back)), C1, 0, TYP_INODATA }, { "magic", FLDT_UINT16X, OI(DBOFF(magic)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT16X, OI(DBOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f)) const field_t da_node_entry_flds[] = { { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE }, { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA }, { NULL } }; #define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f)) const field_t da_node_hdr_flds[] = { { "info", FLDT_DA_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(HOFF(__count)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(HOFF(__level)), C1, 0, TYP_NONE }, { NULL } }; /* * Worker functions shared between either dir2/dir3 or block/data formats */ static int __dir2_block_tail_offset( struct xfs_dir2_data_hdr *block, int startoff, int idx) { struct xfs_dir2_block_tail *btp; ASSERT(startoff == 0); ASSERT(idx == 0); btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); return bitize((int)((char *)btp - (char *)block)); } static int __dir2_data_entries_count( char *ptr, char *endptr) { int i; for (i = 0; ptr < endptr; i++) { struct xfs_dir2_data_entry *dep; struct xfs_dir2_data_unused *dup; dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) ptr += be16_to_cpu(dup->length); else { dep = (xfs_dir2_data_entry_t *)ptr; ptr += M_DIROPS(mp)->data_entsize(dep->namelen); } } return i; } static char * __dir2_data_entry_offset( char *ptr, char *endptr, int idx) { int i; for (i = 0; i < idx; i++) { struct xfs_dir2_data_entry *dep; struct xfs_dir2_data_unused *dup; ASSERT(ptr < endptr); dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) ptr += be16_to_cpu(dup->length); else { dep = (xfs_dir2_data_entry_t *)ptr; ptr += M_DIROPS(mp)->data_entsize(dep->namelen); } } return ptr; } /* * Block format functions */ static int dir2_block_hdr_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *block = obj; ASSERT(startoff == 0); return be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC; } static int dir3_block_hdr_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *block = obj; ASSERT(startoff == 0); return be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC; } static int dir2_block_leaf_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *block = obj; struct xfs_dir2_block_tail *btp; ASSERT(startoff == 0); if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC && be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC) return 0; btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); return be32_to_cpu(btp->count); } static int dir2_block_leaf_offset( void *obj, int startoff, int idx) { struct xfs_dir2_data_hdr *block = obj; struct xfs_dir2_block_tail *btp; struct xfs_dir2_leaf_entry *lep; ASSERT(startoff == 0); ASSERT(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC); btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); lep = xfs_dir2_block_leaf_p(btp) + idx; return bitize((int)((char *)lep - (char *)block)); } static int dir2_block_tail_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *block = obj; ASSERT(startoff == 0); return be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC; } static int dir3_block_tail_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *block = obj; ASSERT(startoff == 0); return be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC; } static int dir2_block_tail_offset( void *obj, int startoff, int idx) { struct xfs_dir2_data_hdr *block = obj; ASSERT(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC); return __dir2_block_tail_offset(block, startoff, idx); } static int dir2_block_u_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *block = obj; struct xfs_dir2_block_tail *btp; ASSERT(startoff == 0); if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC && be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC) return 0; btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); return __dir2_data_entries_count( (char *)M_DIROPS(mp)->data_unused_p(block), (char *)xfs_dir2_block_leaf_p(btp)); } static int dir2_block_u_offset( void *obj, int startoff, int idx) { struct xfs_dir2_data_hdr *block = obj; struct xfs_dir2_block_tail *btp; char *ptr; ASSERT(startoff == 0); ASSERT(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC); btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); ptr = __dir2_data_entry_offset( (char *)M_DIROPS(mp)->data_unused_p(block), (char *)xfs_dir2_block_leaf_p(btp), idx); return bitize((int)(ptr - (char *)block)); } /* * Data block format functions */ static int dir2_data_union_freetag_count( void *obj, int startoff) { xfs_dir2_data_unused_t *dup; char *end; ASSERT(bitoffs(startoff) == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); end = (char *)&dup->freetag + sizeof(dup->freetag); return end <= (char *)obj + mp->m_dir_geo->blksize && be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG; } static int dir2_data_union_inumber_count( void *obj, int startoff) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; char *end; ASSERT(bitoffs(startoff) == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); dep = (xfs_dir2_data_entry_t *)dup; end = (char *)&dep->inumber + sizeof(dep->inumber); return end <= (char *)obj + mp->m_dir_geo->blksize && be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG; } static int dir2_data_union_length_count( void *obj, int startoff) { xfs_dir2_data_unused_t *dup; char *end; ASSERT(bitoffs(startoff) == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); end = (char *)&dup->length + sizeof(dup->length); return end <= (char *)obj + mp->m_dir_geo->blksize && be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG; } static int dir2_data_union_name_count( void *obj, int startoff) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; char *end; ASSERT(bitoffs(startoff) == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); dep = (xfs_dir2_data_entry_t *)dup; end = (char *)&dep->namelen + sizeof(dep->namelen); if (end >= (char *)obj + mp->m_dir_geo->blksize || be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) return 0; end = (char *)&dep->name[0] + dep->namelen; return end <= (char *)obj + mp->m_dir_geo->blksize ? dep->namelen : 0; } static int dir2_data_union_namelen_count( void *obj, int startoff) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; char *end; ASSERT(bitoffs(startoff) == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); dep = (xfs_dir2_data_entry_t *)dup; end = (char *)&dep->namelen + sizeof(dep->namelen); return end <= (char *)obj + mp->m_dir_geo->blksize && be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG; } static int dir2_data_union_tag_count( void *obj, int startoff) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; char *end; __be16 *tagp; ASSERT(bitoffs(startoff) == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); dep = (xfs_dir2_data_entry_t *)dup; end = (char *)&dup->freetag + sizeof(dup->freetag); if (end > (char *)obj + mp->m_dir_geo->blksize) return 0; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { end = (char *)&dup->length + sizeof(dup->length); if (end > (char *)obj + mp->m_dir_geo->blksize) return 0; tagp = xfs_dir2_data_unused_tag_p(dup); } else { end = (char *)&dep->namelen + sizeof(dep->namelen); if (end > (char *)obj + mp->m_dir_geo->blksize) return 0; tagp = M_DIROPS(mp)->data_entry_tag_p(dep); } end = (char *)tagp + sizeof(*tagp); return end <= (char *)obj + mp->m_dir_geo->blksize; } static int dir2_data_union_tag_offset( void *obj, int startoff, int idx) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) return bitize((int)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)dup)); dep = (xfs_dir2_data_entry_t *)dup; return bitize((int)((char *)M_DIROPS(mp)->data_entry_tag_p(dep) - (char *)dep)); } static int dir2_data_hdr_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *data = obj; ASSERT(startoff == 0); return be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC; } static int dir3_data_hdr_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *data = obj; ASSERT(startoff == 0); return be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC; } static int dir2_data_u_count( void *obj, int startoff) { struct xfs_dir2_data_hdr *data = obj; ASSERT(startoff == 0); if (be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC && be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) return 0; return __dir2_data_entries_count( (char *)M_DIROPS(mp)->data_unused_p(data), (char *)data + mp->m_dir_geo->blksize); } static int dir2_data_u_offset( void *obj, int startoff, int idx) { struct xfs_dir2_data_hdr *data = obj; char *ptr; ASSERT(startoff == 0); ASSERT(be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC || be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC); ptr = __dir2_data_entry_offset( (char *)M_DIROPS(mp)->data_unused_p(data), (char *)data + mp->m_dir_geo->blksize, idx); return bitize((int)(ptr - (char *)data)); } int dir2_data_union_size( void *obj, int startoff, int idx) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) return bitize(be16_to_cpu(dup->length)); else { dep = (xfs_dir2_data_entry_t *)dup; return bitize(M_DIROPS(mp)->data_entsize(dep->namelen)); } } static int dir3_data_union_ftype_offset( void *obj, int startoff, int idx) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) return bitize((int)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)dup)); dep = (xfs_dir2_data_entry_t *)dup; return bitize((int)((char *)&dep->name[dep->namelen] - (char *)dep)); } /* * Free block functions */ static int dir2_free_bests_count( void *obj, int startoff) { struct xfs_dir2_free *free = obj; ASSERT(startoff == 0); if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC) return 0; return be32_to_cpu(free->hdr.nvalid); } static int dir3_free_bests_count( void *obj, int startoff) { struct xfs_dir3_free *free = obj; ASSERT(startoff == 0); if (be32_to_cpu(free->hdr.hdr.magic) != XFS_DIR3_FREE_MAGIC) return 0; return be32_to_cpu(free->hdr.nvalid); } static int dir2_free_hdr_count( void *obj, int startoff) { struct xfs_dir2_free *free = obj; ASSERT(startoff == 0); return be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC; } static int dir3_free_hdr_count( void *obj, int startoff) { struct xfs_dir3_free *free = obj; ASSERT(startoff == 0); return be32_to_cpu(free->hdr.hdr.magic) == XFS_DIR3_FREE_MAGIC; } /* * Leaf block functions */ static int dir2_leaf_bests_count( void *obj, int startoff) { struct xfs_dir2_leaf *leaf = obj; struct xfs_dir2_leaf_tail *ltp; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC && be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR3_LEAF1_MAGIC) return 0; ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); return be32_to_cpu(ltp->bestcount); } static int dir2_leaf_bests_offset( void *obj, int startoff, int idx) { struct xfs_dir2_leaf *leaf = obj; struct xfs_dir2_leaf_tail *ltp; __be16 *lbp; ASSERT(startoff == 0); ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC || be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR3_LEAF1_MAGIC); ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); lbp = xfs_dir2_leaf_bests_p(ltp) + idx; return bitize((int)((char *)lbp - (char *)leaf)); } static int dir2_leaf_ents_count( void *obj, int startoff) { struct xfs_dir2_leaf *leaf = obj; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC && be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) return 0; return be16_to_cpu(leaf->hdr.count); } static int dir3_leaf_ents_count( void *obj, int startoff) { struct xfs_dir3_leaf *leaf = obj; ASSERT(startoff == 0); if (be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_DIR3_LEAF1_MAGIC && be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_DIR3_LEAFN_MAGIC) return 0; return be16_to_cpu(leaf->hdr.count); } static int dir2_leaf_hdr_count( void *obj, int startoff) { struct xfs_dir2_leaf *leaf = obj; ASSERT(startoff == 0); return be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC || be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC; } static int dir3_leaf_hdr_count( void *obj, int startoff) { struct xfs_dir3_leaf *leaf = obj; ASSERT(startoff == 0); return be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_DIR3_LEAF1_MAGIC || be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_DIR3_LEAFN_MAGIC; } static int dir2_leaf_tail_count( void *obj, int startoff) { struct xfs_dir2_leaf *leaf = obj; ASSERT(startoff == 0); return be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC; } static int dir3_leaf_tail_count( void *obj, int startoff) { struct xfs_dir3_leaf *leaf = obj; ASSERT(startoff == 0); return be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_DIR3_LEAF1_MAGIC; } static int dir2_leaf_tail_offset( void *obj, int startoff, int idx) { struct xfs_dir2_leaf *leaf = obj; struct xfs_dir2_leaf_tail *ltp; ASSERT(startoff == 0); ASSERT(idx == 0); ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC || be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR3_LEAF1_MAGIC); ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); return bitize((int)((char *)ltp - (char *)leaf)); } /* * Node format functions */ static int dir2_node_btree_count( void *obj, int startoff) { xfs_da_intnode_t *node = obj; ASSERT(startoff == 0); if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) return 0; return be16_to_cpu(node->hdr.__count); } static int dir3_node_btree_count( void *obj, int startoff) { struct xfs_da3_intnode *node = obj; ASSERT(startoff == 0); if (be16_to_cpu(node->hdr.info.hdr.magic) != XFS_DA3_NODE_MAGIC) return 0; return be16_to_cpu(node->hdr.__count); } static int dir2_node_hdr_count( void *obj, int startoff) { struct xfs_da_intnode *node = obj; ASSERT(startoff == 0); return be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC; } static int dir3_node_hdr_count( void *obj, int startoff) { struct xfs_da3_intnode *node = obj; ASSERT(startoff == 0); return be16_to_cpu(node->hdr.info.hdr.magic) == XFS_DA3_NODE_MAGIC; } int dir2_size( void *obj, int startoff, int idx) { return bitize(mp->m_dir_geo->blksize); } /* * CRC enabled structure definitions */ const field_t dir3_hfld[] = { { "", FLDT_DIR3, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define B3OFF(f) bitize(offsetof(struct xfs_dir3_data_hdr, f)) #define D3OFF(f) bitize(offsetof(struct xfs_dir3_data_hdr, f)) #define F3OFF(f) bitize(offsetof(struct xfs_dir3_free, f)) #define L3OFF(f) bitize(offsetof(struct xfs_dir3_leaf, f)) #define N3OFF(f) bitize(offsetof(struct xfs_da3_intnode, f)) const field_t dir3_flds[] = { { "bhdr", FLDT_DIR3_DATA_HDR, OI(B3OFF(hdr)), dir3_block_hdr_count, FLD_COUNT, TYP_NONE }, { "bu", FLDT_DIR3_DATA_UNION, dir2_block_u_offset, dir2_block_u_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "bleaf", FLDT_DIR2_LEAF_ENTRY, dir2_block_leaf_offset, dir2_block_leaf_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "btail", FLDT_DIR2_BLOCK_TAIL, dir2_block_tail_offset, dir3_block_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "dhdr", FLDT_DIR3_DATA_HDR, OI(D3OFF(hdr)), dir3_data_hdr_count, FLD_COUNT, TYP_NONE }, { "du", FLDT_DIR3_DATA_UNION, dir2_data_u_offset, dir2_data_u_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "lhdr", FLDT_DIR3_LEAF_HDR, OI(L3OFF(hdr)), dir3_leaf_hdr_count, FLD_COUNT, TYP_NONE }, { "lbests", FLDT_DIR2_DATA_OFF, dir2_leaf_bests_offset, dir2_leaf_bests_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "lents", FLDT_DIR2_LEAF_ENTRY, OI(L3OFF(__ents)), dir3_leaf_ents_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset, dir3_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, { "nhdr", FLDT_DA3_NODE_HDR, OI(N3OFF(hdr)), dir3_node_hdr_count, FLD_COUNT, TYP_NONE }, { "nbtree", FLDT_DA_NODE_ENTRY, OI(N3OFF(__btree)), dir3_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "fhdr", FLDT_DIR3_FREE_HDR, OI(F3OFF(hdr)), dir3_free_hdr_count, FLD_COUNT, TYP_NONE }, { "fbests", FLDT_DIR2_DATA_OFFNZ, OI(F3OFF(bests)), dir3_free_bests_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { NULL } }; #define D3EOFF(f) bitize(offsetof(xfs_dir2_data_entry_t, f)) #define D3UOFF(f) bitize(offsetof(xfs_dir2_data_unused_t, f)) const field_t dir3_data_union_flds[] = { { "freetag", FLDT_UINT16X, OI(D3UOFF(freetag)), dir2_data_union_freetag_count, FLD_COUNT, TYP_NONE }, { "inumber", FLDT_INO, OI(D3EOFF(inumber)), dir2_data_union_inumber_count, FLD_COUNT, TYP_INODE }, { "length", FLDT_DIR2_DATA_OFF, OI(D3UOFF(length)), dir2_data_union_length_count, FLD_COUNT, TYP_NONE }, { "namelen", FLDT_UINT8D, OI(D3EOFF(namelen)), dir2_data_union_namelen_count, FLD_COUNT, TYP_NONE }, { "name", FLDT_CHARNS, OI(D3EOFF(name)), dir2_data_union_name_count, FLD_COUNT, TYP_NONE }, { "filetype", FLDT_UINT8D, dir3_data_union_ftype_offset, C1, FLD_OFFSET, TYP_NONE }, { "tag", FLDT_DIR2_DATA_OFF, dir2_data_union_tag_offset, dir2_data_union_tag_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, { NULL } }; #define DBH3OFF(f) bitize(offsetof(struct xfs_dir3_blk_hdr, f)) const field_t dir3_blkhdr_flds[] = { { "magic", FLDT_UINT32X, OI(DBH3OFF(magic)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(DBH3OFF(crc)), C1, 0, TYP_NONE }, { "bno", FLDT_DFSBNO, OI(DBH3OFF(blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(DBH3OFF(lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(DBH3OFF(uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(DBH3OFF(owner)), C1, 0, TYP_NONE }, { NULL } }; #define DH3OFF(f) bitize(offsetof(struct xfs_dir3_data_hdr, f)) const field_t dir3_data_hdr_flds[] = { { "hdr", FLDT_DIR3_BLKHDR, OI(DH3OFF(hdr)), C1, 0, TYP_NONE }, { "bestfree", FLDT_DIR2_DATA_FREE, OI(DH3OFF(best_free)), CI(XFS_DIR2_DATA_FD_COUNT), FLD_ARRAY, TYP_NONE }, { "pad", FLDT_UINT32X, OI(DH3OFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define LH3OFF(f) bitize(offsetof(struct xfs_dir3_leaf_hdr, f)) const field_t dir3_leaf_hdr_flds[] = { { "info", FLDT_DA3_BLKINFO, OI(LH3OFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(LH3OFF(count)), C1, 0, TYP_NONE }, { "stale", FLDT_UINT16D, OI(LH3OFF(stale)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT32X, OI(LH3OFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define FH3OFF(f) bitize(offsetof(struct xfs_dir3_free_hdr, f)) const field_t dir3_free_hdr_flds[] = { { "hdr", FLDT_DIR3_BLKHDR, OI(FH3OFF(hdr)), C1, 0, TYP_NONE }, { "firstdb", FLDT_INT32D, OI(FH3OFF(firstdb)), C1, 0, TYP_NONE }, { "nvalid", FLDT_INT32D, OI(FH3OFF(nvalid)), C1, 0, TYP_NONE }, { "nused", FLDT_INT32D, OI(FH3OFF(nused)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT32X, OI(FH3OFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; #define DB3OFF(f) bitize(offsetof(struct xfs_da3_blkinfo, f)) const field_t da3_blkinfo_flds[] = { { "hdr", FLDT_DA_BLKINFO, OI(DB3OFF(hdr)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(DB3OFF(crc)), C1, 0, TYP_NONE }, { "bno", FLDT_DFSBNO, OI(DB3OFF(blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(DB3OFF(lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(DB3OFF(uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(DB3OFF(owner)), C1, 0, TYP_NONE }, { NULL } }; #define H3OFF(f) bitize(offsetof(struct xfs_da3_node_hdr, f)) const field_t da3_node_hdr_flds[] = { { "info", FLDT_DA3_BLKINFO, OI(H3OFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(H3OFF(__count)), C1, 0, TYP_NONE }, { "level", FLDT_UINT16D, OI(H3OFF(__level)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT32X, OI(H3OFF(__pad32)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; /* Set the CRC. */ void xfs_dir3_set_crc( struct xfs_buf *bp) { __be32 magic32; __be16 magic16; magic32 = *(__be32 *)bp->b_addr; magic16 = ((struct xfs_da_blkinfo *)bp->b_addr)->magic; switch (magic32) { case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR3_DATA_MAGIC): xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); return; case cpu_to_be32(XFS_DIR3_FREE_MAGIC): xfs_buf_update_cksum(bp, XFS_DIR3_FREE_CRC_OFF); return; default: break; } switch (magic16) { case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC): case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC): xfs_buf_update_cksum(bp, XFS_DIR3_LEAF_CRC_OFF); return; case cpu_to_be16(XFS_DA3_NODE_MAGIC): xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF); return; default: dbprintf(_("Unknown directory buffer type! %x %x\n"), magic32, magic16); break; } } /* * Special read verifier for directory buffers. Detect the magic number * appropriately and set the correct verifier and call it. */ static void xfs_dir3_db_read_verify( struct xfs_buf *bp) { __be32 magic32; __be16 magic16; magic32 = *(__be32 *)bp->b_addr; magic16 = ((struct xfs_da_blkinfo *)bp->b_addr)->magic; switch (magic32) { case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): bp->b_ops = &xfs_dir3_block_buf_ops; goto verify; case cpu_to_be32(XFS_DIR3_DATA_MAGIC): bp->b_ops = &xfs_dir3_data_buf_ops; goto verify; case cpu_to_be32(XFS_DIR3_FREE_MAGIC): bp->b_ops = &xfs_dir3_free_buf_ops; goto verify; default: break; } switch (magic16) { case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC): bp->b_ops = &xfs_dir3_leaf1_buf_ops; break; case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC): bp->b_ops = &xfs_dir3_leafn_buf_ops; break; case cpu_to_be16(XFS_DA3_NODE_MAGIC): bp->b_ops = &xfs_da3_node_buf_ops; break; default: dbprintf(_("Unknown directory buffer type!\n")); xfs_buf_ioerror(bp, -EFSCORRUPTED); return; } verify: bp->b_ops->verify_read(bp); } static void xfs_dir3_db_write_verify( struct xfs_buf *bp) { dbprintf(_("Writing unknown directory buffer type!\n")); xfs_buf_ioerror(bp, -EFSCORRUPTED); } const struct xfs_buf_ops xfs_dir3_db_buf_ops = { .name = "xfs_dir3", .verify_read = xfs_dir3_db_read_verify, .verify_write = xfs_dir3_db_write_verify, }; xfsprogs-5.3.0/db/dir2.h0000644000175000017500000000272413435336036014655 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ /* * common types across directory formats */ extern const field_t dir2_block_tail_flds[]; extern const field_t dir2_data_free_flds[]; extern const field_t dir2_data_union_flds[]; extern const field_t dir2_leaf_tail_flds[]; extern const field_t dir2_leaf_entry_flds[]; extern const field_t da_node_entry_flds[]; /* * dirv2 specific types */ extern const field_t dir2_flds[]; extern const field_t dir2_hfld[]; extern const field_t dir2_data_hdr_flds[]; extern const field_t dir2_free_hdr_flds[]; extern const field_t dir2_leaf_hdr_flds[]; extern const field_t da_blkinfo_flds[]; extern const field_t da_node_hdr_flds[]; /* * dirv3 specific types */ extern const field_t dir3_flds[]; extern const field_t dir3_hfld[]; extern const field_t dir3_blkhdr_flds[]; extern const field_t dir3_data_hdr_flds[]; extern const field_t dir3_free_hdr_flds[]; extern const field_t dir3_leaf_hdr_flds[]; extern const field_t dir3_data_union_flds[]; extern const field_t da3_blkinfo_flds[]; extern const field_t da3_node_hdr_flds[]; static inline uint8_t *xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep) { return &(sfep)->name[(sfep)->namelen]; } extern int dir2_data_union_size(void *obj, int startoff, int idx); extern int dir2_size(void *obj, int startoff, int idx); extern void xfs_dir3_set_crc(struct xfs_buf *bp); extern const struct xfs_buf_ops xfs_dir3_db_buf_ops; xfsprogs-5.3.0/db/dir2sf.c0000644000175000017500000001427613435336036015206 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "bit.h" #include "dir2.h" #include "dir2sf.h" #include "init.h" static int dir2_inou_i4_count(void *obj, int startoff); static int dir2_inou_i8_count(void *obj, int startoff); static int dir2_sf_entry_inumber_offset(void *obj, int startoff, int idx); static int dir2_sf_entry_name_count(void *obj, int startoff); static int dir2_sf_list_count(void *obj, int startoff); static int dir2_sf_list_offset(void *obj, int startoff, int idx); #define OFF(f) bitize(offsetof(struct xfs_dir2_sf_hdr, f)) const field_t dir2sf_flds[] = { { "hdr", FLDT_DIR2_SF_HDR, OI(OFF(count)), C1, 0, TYP_NONE }, { "list", FLDT_DIR2_SF_ENTRY, dir2_sf_list_offset, dir2_sf_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; const field_t dir2_inou_flds[] = { { "i8", FLDT_DIR2_INO8, NULL, dir2_inou_i8_count, FLD_COUNT, TYP_INODE}, { "i4", FLDT_DIR2_INO4, NULL, dir2_inou_i4_count, FLD_COUNT, TYP_INODE}, { NULL } }; #define HOFF(f) bitize(offsetof(xfs_dir2_sf_hdr_t, f)) const field_t dir2_sf_hdr_flds[] = { { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE }, { "i8count", FLDT_UINT8D, OI(HOFF(i8count)), C1, 0, TYP_NONE }, { "parent", FLDT_DIR2_INOU, OI(HOFF(parent)), C1, 0, TYP_NONE }, { NULL } }; #define EOFF(f) bitize(offsetof(xfs_dir2_sf_entry_t, f)) const field_t dir2_sf_entry_flds[] = { { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, { "offset", FLDT_DIR2_SF_OFF, OI(EOFF(offset)), C1, 0, TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(name)), dir2_sf_entry_name_count, FLD_COUNT, TYP_NONE }, { "inumber", FLDT_DIR2_INOU, dir2_sf_entry_inumber_offset, C1, FLD_OFFSET, TYP_NONE }, { NULL } }; /*ARGSUSED*/ static int dir2_inou_i4_count( void *obj, int startoff) { struct xfs_dinode *dip = obj; struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); return sf->i8count == 0; } /*ARGSUSED*/ static int dir2_inou_i8_count( void *obj, int startoff) { struct xfs_dinode *dip = obj; struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); return sf->i8count != 0; } /*ARGSUSED*/ int dir2_inou_size( void *obj, int startoff, int idx) { struct xfs_dinode *dip = obj; struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); return bitize(sf->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE); } static int dir2_sf_entry_name_count( void *obj, int startoff) { xfs_dir2_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); e = (xfs_dir2_sf_entry_t *)((char *)obj + byteize(startoff)); return e->namelen; } static int dir2_sf_entry_inumber_offset( void *obj, int startoff, int idx) { xfs_dir2_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); e = (xfs_dir2_sf_entry_t *)((char *)obj + byteize(startoff)); return bitize((int)((char *)xfs_dir2_sf_inumberp(e) - (char *)e)); } static int dir3_sf_entry_inumber_offset( void *obj, int startoff, int idx) { xfs_dir2_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); e = (xfs_dir2_sf_entry_t *)((char *)obj + byteize(startoff)); /* plus 1 to skip the ftype entry */ return bitize((int)((char *)xfs_dir2_sf_inumberp(e) + 1 - (char *)e)); } static int dir3_sf_entry_ftype_offset( void *obj, int startoff, int idx) { xfs_dir2_sf_entry_t *e; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); e = (xfs_dir2_sf_entry_t *)((char *)obj + byteize(startoff)); return bitize((int)((char *)&e->name[e->namelen] - (char *)e)); } int dir2_sf_entry_size( void *obj, int startoff, int idx) { xfs_dir2_sf_entry_t *e; int i; struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); sf = (struct xfs_dir2_sf_hdr *)((char *)obj + byteize(startoff)); e = xfs_dir2_sf_firstentry(sf); for (i = 0; i < idx; i++) e = M_DIROPS(mp)->sf_nextentry(sf, e); return bitize((int)M_DIROPS(mp)->sf_entsize(sf, e->namelen)); } /*ARGSUSED*/ int dir2_sf_hdr_size( void *obj, int startoff, int idx) { struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); sf = (struct xfs_dir2_sf_hdr *)((char *)obj + byteize(startoff)); return bitize(xfs_dir2_sf_hdr_size(sf->i8count)); } static int dir2_sf_list_count( void *obj, int startoff) { struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); sf = (struct xfs_dir2_sf_hdr *)((char *)obj + byteize(startoff)); return sf->count; } static int dir2_sf_list_offset( void *obj, int startoff, int idx) { xfs_dir2_sf_entry_t *e; int i; struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); sf = (struct xfs_dir2_sf_hdr *)((char *)obj + byteize(startoff)); e = xfs_dir2_sf_firstentry(sf); for (i = 0; i < idx; i++) e = M_DIROPS(mp)->sf_nextentry(sf, e); return bitize((int)((char *)e - (char *)sf)); } /*ARGSUSED*/ int dir2sf_size( void *obj, int startoff, int idx) { xfs_dir2_sf_entry_t *e; int i; struct xfs_dir2_sf_hdr *sf; ASSERT(bitoffs(startoff) == 0); ASSERT(idx == 0); sf = (struct xfs_dir2_sf_hdr *)((char *)obj + byteize(startoff)); e = xfs_dir2_sf_firstentry(sf); for (i = 0; i < sf->count; i++) e = M_DIROPS(mp)->sf_nextentry(sf, e); return bitize((int)((char *)e - (char *)sf)); } #define OFF(f) bitize(offsetof(struct xfs_dir2_sf_hdr, f)) const field_t dir3sf_flds[] = { { "hdr", FLDT_DIR2_SF_HDR, OI(OFF(count)), C1, 0, TYP_NONE }, { "list", FLDT_DIR3_SF_ENTRY, dir2_sf_list_offset, dir2_sf_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; #define E3OFF(f) bitize(offsetof(xfs_dir2_sf_entry_t, f)) const field_t dir3_sf_entry_flds[] = { { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, { "offset", FLDT_DIR2_SF_OFF, OI(EOFF(offset)), C1, 0, TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(name)), dir2_sf_entry_name_count, FLD_COUNT, TYP_NONE }, { "inumber", FLDT_DIR2_INOU, dir3_sf_entry_inumber_offset, C1, FLD_OFFSET, TYP_NONE }, { "filetype", FLDT_UINT8D, dir3_sf_entry_ftype_offset, C1, FLD_OFFSET, TYP_NONE }, { NULL } }; xfsprogs-5.3.0/db/dir2sf.h0000644000175000017500000000114213435336036015177 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const field_t dir2sf_flds[]; extern const field_t dir2_inou_flds[]; extern const field_t dir2_sf_hdr_flds[]; extern const field_t dir2_sf_entry_flds[]; extern const field_t dir3sf_flds[]; extern const field_t dir3_sf_entry_flds[]; extern int dir2sf_size(void *obj, int startoff, int idx); extern int dir2_inou_size(void *obj, int startoff, int idx); extern int dir2_sf_entry_size(void *obj, int startoff, int idx); extern int dir2_sf_hdr_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/dquot.c0000644000175000017500000001100113435336036015130 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "bit.h" #include "bmap.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "inode.h" #include "io.h" #include "init.h" #include "output.h" #include "dquot.h" static int dquot_f(int argc, char **argv); static void dquot_help(void); static const cmdinfo_t dquot_cmd = { "dquot", NULL, dquot_f, 1, 2, 1, N_("[-g|-p|-u] id"), N_("set current address to a group, project or user quota block for given ID"), dquot_help, }; const field_t dqblk_hfld[] = { { "", FLDT_DQBLK, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define DDOFF(f) bitize(offsetof(xfs_dqblk_t, dd_ ## f)) #define DDSZC(f) szcount(xfs_dqblk_t, dd_ ## f) const field_t dqblk_flds[] = { { "diskdq", FLDT_DISK_DQUOT, OI(DDOFF(diskdq)), C1, 0, TYP_NONE }, { "fill", FLDT_CHARS, OI(DDOFF(fill)), CI(DDSZC(fill)), FLD_SKIPALL, TYP_NONE }, { "crc", FLDT_CRC, OI(DDOFF(crc)), C1, 0, TYP_NONE }, { "lsn", FLDT_UINT64X, OI(DDOFF(lsn)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(DDOFF(uuid)), C1, 0, TYP_NONE }, { NULL } }; #define DOFF(f) bitize(offsetof(xfs_disk_dquot_t, d_ ## f)) const field_t disk_dquot_flds[] = { { "magic", FLDT_UINT16X, OI(DOFF(magic)), C1, 0, TYP_NONE }, { "version", FLDT_UINT8X, OI(DOFF(version)), C1, 0, TYP_NONE }, { "flags", FLDT_UINT8X, OI(DOFF(flags)), C1, 0, TYP_NONE }, { "id", FLDT_DQID, OI(DOFF(id)), C1, 0, TYP_NONE }, { "blk_hardlimit", FLDT_QCNT, OI(DOFF(blk_hardlimit)), C1, 0, TYP_NONE }, { "blk_softlimit", FLDT_QCNT, OI(DOFF(blk_softlimit)), C1, 0, TYP_NONE }, { "ino_hardlimit", FLDT_QCNT, OI(DOFF(ino_hardlimit)), C1, 0, TYP_NONE }, { "ino_softlimit", FLDT_QCNT, OI(DOFF(ino_softlimit)), C1, 0, TYP_NONE }, { "bcount", FLDT_QCNT, OI(DOFF(bcount)), C1, 0, TYP_NONE }, { "icount", FLDT_QCNT, OI(DOFF(icount)), C1, 0, TYP_NONE }, { "itimer", FLDT_INT32D, OI(DOFF(itimer)), C1, 0, TYP_NONE }, { "btimer", FLDT_INT32D, OI(DOFF(btimer)), C1, 0, TYP_NONE }, { "iwarns", FLDT_QWARNCNT, OI(DOFF(iwarns)), C1, 0, TYP_NONE }, { "bwarns", FLDT_QWARNCNT, OI(DOFF(bwarns)), C1, 0, TYP_NONE }, { "pad0", FLDT_UINT32X, OI(DOFF(pad0)), C1, FLD_SKIPALL, TYP_NONE }, { "rtb_hardlimit", FLDT_QCNT, OI(DOFF(rtb_hardlimit)), C1, 0, TYP_NONE }, { "rtb_softlimit", FLDT_QCNT, OI(DOFF(rtb_softlimit)), C1, 0, TYP_NONE }, { "rtbcount", FLDT_QCNT, OI(DOFF(rtbcount)), C1, 0, TYP_NONE }, { "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE }, { "rtbwarns", FLDT_QWARNCNT, OI(DOFF(rtbwarns)), C1, 0, TYP_NONE }, { "pad", FLDT_UINT16X, OI(DOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; static void dquot_help(void) { } static int dquot_f( int argc, char **argv) { bmap_ext_t bm; int c; int dogrp; int doprj; xfs_dqid_t id; xfs_ino_t ino; int nex; char *p; int perblock; xfs_fileoff_t qbno; int qoff; char *s; dogrp = doprj = optind = 0; while ((c = getopt(argc, argv, "gpu")) != EOF) { switch (c) { case 'g': dogrp = 1; doprj = 0; break; case 'p': doprj = 1; dogrp = 0; break; case 'u': dogrp = doprj = 0; break; default: dbprintf(_("bad option for dquot command\n")); return 0; } } s = doprj ? _("project") : dogrp ? _("group") : _("user"); if (optind != argc - 1) { dbprintf(_("dquot command requires one %s id argument\n"), s); return 0; } ino = mp->m_sb.sb_uquotino; if (doprj) ino = mp->m_sb.sb_pquotino; else if (dogrp) ino = mp->m_sb.sb_gquotino; if (ino == 0 || ino == NULLFSINO) { dbprintf(_("no %s quota inode present\n"), s); return 0; } id = (xfs_dqid_t)strtol(argv[optind], &p, 0); if (*p != '\0') { dbprintf(_("bad %s id for dquot %s\n"), s, argv[optind]); return 0; } perblock = (int)(mp->m_sb.sb_blocksize / sizeof(xfs_dqblk_t)); qbno = (xfs_fileoff_t)id / perblock; qoff = (int)(id % perblock); push_cur(); set_cur_inode(ino); nex = 1; bmap(qbno, 1, XFS_DATA_FORK, &nex, &bm); pop_cur(); if (nex == 0) { dbprintf(_("no %s quota data for id %d\n"), s, id); return 0; } set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bm.startblock), blkbb, DB_RING_IGN, NULL); iocur_top->dquot_buf = 1; off_cur(qoff * (int)sizeof(xfs_dqblk_t), sizeof(xfs_dqblk_t)); ring_add(); return 0; } void xfs_dquot_set_crc( struct xfs_buf *bp) { ASSERT((iocur_top->dquot_buf)); ASSERT(iocur_top->bp == bp); xfs_update_cksum(iocur_top->data, sizeof(struct xfs_dqblk), XFS_DQUOT_CRC_OFF); } void dquot_init(void) { add_command(&dquot_cmd); } xfsprogs-5.3.0/db/dquot.h0000644000175000017500000000051013435336036015140 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field disk_dquot_flds[]; extern const struct field dqblk_flds[]; extern const struct field dqblk_hfld[]; extern void xfs_dquot_set_crc(struct xfs_buf *); extern void dquot_init(void); xfsprogs-5.3.0/db/echo.c0000644000175000017500000000110213435336036014713 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "echo.h" #include "output.h" static int echo_f(int argc, char **argv); static const cmdinfo_t echo_cmd = { "echo", NULL, echo_f, 0, -1, 0, N_("[args]..."), N_("echo arguments"), NULL }; /*ARGSUSED*/ static int echo_f( int argc, char **argv) { char *c; for (c = *(++argv); c; c = *(++argv)) dbprintf("%s ", c); dbprintf("\n"); return 0; } void echo_init(void) { add_command(&echo_cmd); } xfsprogs-5.3.0/db/echo.h0000644000175000017500000000023013435336036014721 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void echo_init(void); xfsprogs-5.3.0/db/faddr.c0000644000175000017500000001733613435336036015075 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "fprint.h" #include "faddr.h" #include "field.h" #include "inode.h" #include "io.h" #include "bit.h" #include "bmap.h" #include "output.h" #include "init.h" void fa_agblock( void *obj, int bit, typnm_t next) { xfs_agblock_t bno; if (cur_agno == NULLAGNUMBER) { dbprintf(_("no current allocation group, cannot set new addr\n")); return; } bno = (xfs_agblock_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == NULLAGBLOCK) { dbprintf(_("null block number, cannot set new addr\n")); return; } ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], XFS_AGB_TO_DADDR(mp, cur_agno, bno), blkbb, DB_RING_ADD, NULL); } /*ARGSUSED*/ void fa_agino( void *obj, int bit, typnm_t next) { xfs_agino_t agino; if (cur_agno == NULLAGNUMBER) { dbprintf(_("no current allocation group, cannot set new addr\n")); return; } agino = (xfs_agino_t)getbitval(obj, bit, bitsz(agino), BVUNSIGNED); if (agino == NULLAGINO) { dbprintf(_("null inode number, cannot set new addr\n")); return; } set_cur_inode(XFS_AGINO_TO_INO(mp, cur_agno, agino)); } /*ARGSUSED*/ void fa_attrblock( void *obj, int bit, typnm_t next) { bmap_ext_t bm; uint32_t bno; xfs_fsblock_t dfsbno; int nex; bno = (uint32_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == 0) { dbprintf(_("null attribute block number, cannot set new addr\n")); return; } nex = 1; bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); if (nex == 0) { dbprintf(_("attribute block is unmapped\n")); return; } dfsbno = bm.startblock + (bno - bm.startoff); ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], (int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, DB_RING_ADD, NULL); } void fa_cfileoffa( void *obj, int bit, typnm_t next) { bmap_ext_t bm; xfs_fileoff_t bno; xfs_fsblock_t dfsbno; int nex; bno = (xfs_fileoff_t)getbitval(obj, bit, BMBT_STARTOFF_BITLEN, BVUNSIGNED); if (bno == NULLFILEOFF) { dbprintf(_("null block number, cannot set new addr\n")); return; } nex = 1; bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); if (nex == 0) { dbprintf(_("file block is unmapped\n")); return; } dfsbno = bm.startblock + (bno - bm.startoff); ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, DB_RING_ADD, NULL); } void fa_cfileoffd( void *obj, int bit, typnm_t next) { bbmap_t bbmap; bmap_ext_t *bmp; xfs_fileoff_t bno; xfs_fsblock_t dfsbno; int nb; int nex; bno = (xfs_fileoff_t)getbitval(obj, bit, BMBT_STARTOFF_BITLEN, BVUNSIGNED); if (bno == NULLFILEOFF) { dbprintf(_("null block number, cannot set new addr\n")); return; } nex = nb = next == TYP_DIR2 ? mp->m_dir_geo->fsbcount : 1; bmp = malloc(nb * sizeof(*bmp)); bmap(bno, nb, XFS_DATA_FORK, &nex, bmp); if (nex == 0) { dbprintf(_("file block is unmapped\n")); free(bmp); return; } dfsbno = bmp->startblock + (bno - bmp->startoff); ASSERT(typtab[next].typnm == next); if (nex > 1) make_bbmap(&bbmap, nex, bmp); set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), nb * blkbb, DB_RING_ADD, nex > 1 ? &bbmap: NULL); free(bmp); } void fa_cfsblock( void *obj, int bit, typnm_t next) { xfs_fsblock_t bno; int nb; bno = (xfs_fsblock_t)getbitval(obj, bit, BMBT_STARTBLOCK_BITLEN, BVUNSIGNED); if (bno == NULLFSBLOCK) { dbprintf(_("null block number, cannot set new addr\n")); return; } nb = next == TYP_DIR2 ? mp->m_dir_geo->fsbcount : 1; ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, bno), nb * blkbb, DB_RING_ADD, NULL); } void fa_dfiloffa( void *obj, int bit, typnm_t next) { bmap_ext_t bm; xfs_fileoff_t bno; xfs_fsblock_t dfsbno; int nex; bno = (xfs_fileoff_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == NULLFILEOFF) { dbprintf(_("null block number, cannot set new addr\n")); return; } nex = 1; bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); if (nex == 0) { dbprintf(_("file block is unmapped\n")); return; } dfsbno = bm.startblock + (bno - bm.startoff); ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, DB_RING_ADD, NULL); } void fa_dfiloffd( void *obj, int bit, typnm_t next) { bbmap_t bbmap; bmap_ext_t *bmp; xfs_fileoff_t bno; xfs_fsblock_t dfsbno; int nb; int nex; bno = (xfs_fileoff_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == NULLFILEOFF) { dbprintf(_("null block number, cannot set new addr\n")); return; } nex = nb = next == TYP_DIR2 ? mp->m_dir_geo->fsbcount : 1; bmp = malloc(nb * sizeof(*bmp)); bmap(bno, nb, XFS_DATA_FORK, &nex, bmp); if (nex == 0) { dbprintf(_("file block is unmapped\n")); free(bmp); return; } dfsbno = bmp->startblock + (bno - bmp->startoff); ASSERT(typtab[next].typnm == next); if (nex > 1) make_bbmap(&bbmap, nex, bmp); set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), nb * blkbb, DB_RING_ADD, nex > 1 ? &bbmap : NULL); free(bmp); } void fa_dfsbno( void *obj, int bit, typnm_t next) { xfs_fsblock_t bno; bno = (xfs_fsblock_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == NULLFSBLOCK) { dbprintf(_("null block number, cannot set new addr\n")); return; } ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_ADD, NULL); } /*ARGSUSED*/ void fa_dirblock( void *obj, int bit, typnm_t next) { bbmap_t bbmap; bmap_ext_t *bmp; uint32_t bno; xfs_fsblock_t dfsbno; int nex; bno = (uint32_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == 0) { dbprintf(_("null directory block number, cannot set new addr\n")); return; } nex = mp->m_dir_geo->fsbcount; bmp = malloc(nex * sizeof(*bmp)); bmap(bno, mp->m_dir_geo->fsbcount, XFS_DATA_FORK, &nex, bmp); if (nex == 0) { dbprintf(_("directory block is unmapped\n")); free(bmp); return; } dfsbno = bmp->startblock + (bno - bmp->startoff); ASSERT(typtab[next].typnm == next); if (nex > 1) make_bbmap(&bbmap, nex, bmp); set_cur(&typtab[next], (int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), XFS_FSB_TO_BB(mp, mp->m_dir_geo->fsbcount), DB_RING_ADD, nex > 1 ? &bbmap : NULL); free(bmp); } void fa_drfsbno( void *obj, int bit, typnm_t next) { xfs_rfsblock_t bno; bno = (xfs_rfsblock_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == NULLRFSBLOCK) { dbprintf(_("null block number, cannot set new addr\n")); return; } ASSERT(typtab[next].typnm == next); set_cur(&typtab[next], (int64_t)XFS_FSB_TO_BB(mp, bno), blkbb, DB_RING_ADD, NULL); } /*ARGSUSED*/ void fa_drtbno( void *obj, int bit, typnm_t next) { xfs_rtblock_t bno; bno = (xfs_rtblock_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); if (bno == NULLRTBLOCK) { dbprintf(_("null block number, cannot set new addr\n")); return; } /* need set_cur to understand rt subvolume */ } /*ARGSUSED*/ void fa_ino( void *obj, int bit, typnm_t next) { xfs_ino_t ino; ASSERT(next == TYP_INODE); ino = (xfs_ino_t)getbitval(obj, bit, bitsz(ino), BVUNSIGNED); if (ino == NULLFSINO) { dbprintf(_("null inode number, cannot set new addr\n")); return; } set_cur_inode(ino); } void fa_ino4( void *obj, int bit, typnm_t next) { xfs_ino_t ino; ASSERT(next == TYP_INODE); ino = (xfs_ino_t)getbitval(obj, bit, bitsz(XFS_INO32_SIZE), BVUNSIGNED); if (ino == NULLFSINO) { dbprintf(_("null inode number, cannot set new addr\n")); return; } set_cur_inode(ino); } void fa_ino8( void *obj, int bit, typnm_t next) { xfs_ino_t ino; ASSERT(next == TYP_INODE); ino = (xfs_ino_t)getbitval(obj, bit, bitsz(XFS_INO64_SIZE), BVUNSIGNED); if (ino == NULLFSINO) { dbprintf(_("null inode number, cannot set new addr\n")); return; } set_cur_inode(ino); } xfsprogs-5.3.0/db/faddr.h0000644000175000017500000000203113466663244015074 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ typedef void (*adfnc_t)(void *obj, int bit, typnm_t next); extern void fa_agblock(void *obj, int bit, typnm_t next); extern void fa_agino(void *obj, int bit, typnm_t next); extern void fa_attrblock(void *obj, int bit, typnm_t next); extern void fa_cfileoffd(void *obj, int bit, typnm_t next); extern void fa_cfsblock(void *obj, int bit, typnm_t next); extern void fa_dfiloffd(void *obj, int bit, typnm_t next); extern void fa_dfsbno(void *obj, int bit, typnm_t next); extern void fa_dirblock(void *obj, int bit, typnm_t next); extern void fa_drfsbno(void *obj, int bit, typnm_t next); extern void fa_drtbno(void *obj, int bit, typnm_t next); extern void fa_ino(void *obj, int bit, typnm_t next); extern void fa_cfileoffa(void *obj, int bit, typnm_t next); extern void fa_dfiloffa(void *obj, int bit, typnm_t next); extern void fa_ino4(void *obj, int bit, typnm_t next); extern void fa_ino8(void *obj, int bit, typnm_t next); xfsprogs-5.3.0/db/field.c0000644000175000017500000004664613435336036015106 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "inode.h" #include "btblock.h" #include "bmroot.h" #include "bit.h" #include "agf.h" #include "agfl.h" #include "agi.h" #include "sb.h" #include "attr.h" #include "attrshort.h" #include "dquot.h" #include "dir2.h" #include "dir2sf.h" #include "symlink.h" const ftattr_t ftattrtab[] = { { FLDT_AEXTNUM, "aextnum", fp_num, "%d", SI(bitsz(xfs_aextnum_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_AGBLOCK, "agblock", fp_num, "%u", SI(bitsz(xfs_agblock_t)), FTARG_DONULL, fa_agblock, NULL }, { FLDT_AGBLOCKNZ, "agblocknz", fp_num, "%u", SI(bitsz(xfs_agblock_t)), FTARG_SKIPZERO|FTARG_DONULL, fa_agblock, NULL }, { FLDT_AGF, "agf", NULL, (char *)agf_flds, agf_size, FTARG_SIZE, NULL, agf_flds }, { FLDT_AGFL, "agfl", NULL, (char *)agfl_flds, agfl_size, FTARG_SIZE, NULL, agfl_flds }, { FLDT_AGFL_CRC, "agfl", NULL, (char *)agfl_crc_flds, agfl_size, FTARG_SIZE, NULL, agfl_crc_flds }, { FLDT_AGI, "agi", NULL, (char *)agi_flds, agi_size, FTARG_SIZE, NULL, agi_flds }, { FLDT_AGINO, "agino", fp_num, "%u", SI(bitsz(xfs_agino_t)), FTARG_DONULL, fa_agino, NULL }, { FLDT_AGINONN, "aginonn", fp_num, "%u", SI(bitsz(xfs_agino_t)), FTARG_SKIPNULL, fa_agino, NULL }, { FLDT_AGNUMBER, "agnumber", fp_num, "%u", SI(bitsz(xfs_agnumber_t)), FTARG_DONULL, NULL, NULL }, /* attr fields */ { FLDT_ATTR, "attr", NULL, (char *)attr_flds, attr_size, FTARG_SIZE, NULL, attr_flds }, { FLDT_ATTR_BLKINFO, "attr_blkinfo", NULL, (char *)attr_blkinfo_flds, SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, attr_blkinfo_flds }, { FLDT_ATTR_LEAF_ENTRY, "attr_leaf_entry", fp_sarray, (char *)attr_leaf_entry_flds, SI(bitsz(struct xfs_attr_leaf_entry)), 0, NULL, attr_leaf_entry_flds }, { FLDT_ATTR_LEAF_HDR, "attr_leaf_hdr", NULL, (char *)attr_leaf_hdr_flds, SI(bitsz(struct xfs_attr_leaf_hdr)), 0, NULL, attr_leaf_hdr_flds }, { FLDT_ATTR_LEAF_MAP, "attr_leaf_map", fp_sarray, (char *)attr_leaf_map_flds, SI(bitsz(struct xfs_attr_leaf_map)), 0, NULL, attr_leaf_map_flds }, { FLDT_ATTR_LEAF_NAME, "attr_leaf_name", NULL, (char *)attr_leaf_name_flds, attr_leaf_name_size, FTARG_SIZE, NULL, attr_leaf_name_flds }, { FLDT_ATTR_NODE_ENTRY, "attr_node_entry", fp_sarray, (char *)attr_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0, NULL, attr_node_entry_flds }, { FLDT_ATTR_NODE_HDR, "attr_node_hdr", NULL, (char *)attr_node_hdr_flds, SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, attr_node_hdr_flds }, { FLDT_ATTR_SF_ENTRY, "attr_sf_entry", NULL, (char *)attr_sf_entry_flds, attr_sf_entry_size, FTARG_SIZE, NULL, attr_sf_entry_flds }, { FLDT_ATTR_SF_HDR, "attr_sf_hdr", NULL, (char *)attr_sf_hdr_flds, SI(bitsz(struct xfs_attr_sf_hdr)), 0, NULL, attr_sf_hdr_flds }, { FLDT_ATTRBLOCK, "attrblock", fp_num, "%u", SI(bitsz(uint32_t)), 0, fa_attrblock, NULL }, { FLDT_ATTRSHORT, "attrshort", NULL, (char *)attr_shortform_flds, attrshort_size, FTARG_SIZE, NULL, attr_shortform_flds }, /* attr3 specific fields */ { FLDT_ATTR3, "attr3", NULL, (char *)attr3_flds, attr_size, FTARG_SIZE, NULL, attr3_flds }, { FLDT_ATTR3_BLKINFO, "attr3_blkinfo", NULL, (char *)attr3_blkinfo_flds, SI(bitsz(struct xfs_da3_blkinfo)), 0, NULL, attr3_blkinfo_flds }, { FLDT_ATTR3_LEAF_HDR, "attr3_leaf_hdr", NULL, (char *)attr3_leaf_hdr_flds, SI(bitsz(struct xfs_attr3_leaf_hdr)), 0, NULL, attr3_leaf_hdr_flds }, { FLDT_ATTR3_NODE_HDR, "attr3_node_hdr", NULL, (char *)attr3_node_hdr_flds, SI(bitsz(struct xfs_da3_node_hdr)), 0, NULL, attr3_node_hdr_flds }, { FLDT_ATTR3_REMOTE_HDR, "attr3_remote_hdr", NULL, (char *)attr3_remote_crc_flds, attr_size, FTARG_SIZE, NULL, attr3_remote_crc_flds }, { FLDT_BMAPBTA, "bmapbta", NULL, (char *)bmapbta_flds, btblock_size, FTARG_SIZE, NULL, bmapbta_flds }, { FLDT_BMAPBTA_CRC, "bmapbta", NULL, (char *)bmapbta_crc_flds, btblock_size, FTARG_SIZE, NULL, bmapbta_crc_flds }, { FLDT_BMAPBTAKEY, "bmapbtakey", fp_sarray, (char *)bmapbta_key_flds, SI(bitsz(xfs_bmbt_key_t)), 0, NULL, bmapbta_key_flds }, { FLDT_BMAPBTAPTR, "bmapbtaptr", fp_num, "%llu", SI(bitsz(xfs_bmbt_ptr_t)), 0, fa_dfsbno, NULL }, { FLDT_BMAPBTAREC, "bmapbtarec", fp_sarray, (char *)bmapbta_rec_flds, SI(bitsz(xfs_bmbt_rec_t)), 0, NULL, bmapbta_rec_flds }, { FLDT_BMAPBTD, "bmapbtd", NULL, (char *)bmapbtd_flds, btblock_size, FTARG_SIZE, NULL, bmapbtd_flds }, { FLDT_BMAPBTD_CRC, "bmapbtd", NULL, (char *)bmapbtd_crc_flds, btblock_size, FTARG_SIZE, NULL, bmapbtd_crc_flds }, { FLDT_BMAPBTDKEY, "bmapbtdkey", fp_sarray, (char *)bmapbtd_key_flds, SI(bitsz(xfs_bmbt_key_t)), 0, NULL, bmapbtd_key_flds }, { FLDT_BMAPBTDPTR, "bmapbtdptr", fp_num, "%llu", SI(bitsz(xfs_bmbt_ptr_t)), 0, fa_dfsbno, NULL }, { FLDT_BMAPBTDREC, "bmapbtdrec", fp_sarray, (char *)bmapbtd_rec_flds, SI(bitsz(xfs_bmbt_rec_t)), 0, NULL, bmapbtd_rec_flds }, { FLDT_BMROOTA, "bmroota", NULL, (char *)bmroota_flds, bmroota_size, FTARG_SIZE, NULL, bmroota_flds }, { FLDT_BMROOTAKEY, "bmrootakey", fp_sarray, (char *)bmroota_key_flds, SI(bitsz(xfs_bmdr_key_t)), 0, NULL, bmroota_key_flds }, { FLDT_BMROOTAPTR, "bmrootaptr", fp_num, "%llu", SI(bitsz(xfs_bmdr_ptr_t)), 0, fa_dfsbno, NULL }, { FLDT_BMROOTD, "bmrootd", NULL, (char *)bmrootd_flds, bmrootd_size, FTARG_SIZE, NULL, bmrootd_flds }, { FLDT_BMROOTDKEY, "bmrootdkey", fp_sarray, (char *)bmrootd_key_flds, SI(bitsz(xfs_bmdr_key_t)), 0, NULL, bmrootd_key_flds }, { FLDT_BMROOTDPTR, "bmrootdptr", fp_num, "%llu", SI(bitsz(xfs_bmdr_ptr_t)), 0, fa_dfsbno, NULL }, { FLDT_BNOBT, "bnobt", NULL, (char *)bnobt_flds, btblock_size, FTARG_SIZE, NULL, bnobt_flds }, { FLDT_BNOBT_CRC, "bnobt", NULL, (char *)bnobt_crc_flds, btblock_size, FTARG_SIZE, NULL, bnobt_crc_flds }, { FLDT_BNOBTKEY, "bnobtkey", fp_sarray, (char *)bnobt_key_flds, SI(bitsz(xfs_alloc_key_t)), 0, NULL, bnobt_key_flds }, { FLDT_BNOBTPTR, "bnobtptr", fp_num, "%u", SI(bitsz(xfs_alloc_ptr_t)), 0, fa_agblock, NULL }, { FLDT_BNOBTREC, "bnobtrec", fp_sarray, (char *)bnobt_rec_flds, SI(bitsz(xfs_alloc_rec_t)), 0, NULL, bnobt_rec_flds }, { FLDT_CEXTFLG, "cextflag", fp_num, "%u", SI(BMBT_EXNTFLAG_BITLEN), 0, NULL, NULL }, { FLDT_CEXTLEN, "cextlen", fp_num, "%u", SI(BMBT_BLOCKCOUNT_BITLEN), 0, NULL, NULL }, { FLDT_CFILEOFFA, "cfileoffa", fp_num, "%llu", SI(BMBT_STARTOFF_BITLEN), 0, fa_cfileoffa, NULL }, { FLDT_CFILEOFFD, "cfileoffd", fp_num, "%llu", SI(BMBT_STARTOFF_BITLEN), 0, fa_cfileoffd, NULL }, { FLDT_CFSBLOCK, "cfsblock", fp_num, "%llu", SI(BMBT_STARTBLOCK_BITLEN), 0, fa_cfsblock, NULL }, { FLDT_CHARNS, "charns", fp_charns, NULL, SI(bitsz(char)), 0, NULL, NULL }, { FLDT_CHARS, "chars", fp_num, "%c", SI(bitsz(char)), 0, NULL, NULL }, { FLDT_REXTLEN, "rextlen", fp_num, "%u", SI(RMAPBT_BLOCKCOUNT_BITLEN), 0, NULL, NULL }, { FLDT_RFILEOFFD, "rfileoffd", fp_num, "%llu", SI(RMAPBT_OFFSET_BITLEN), 0, NULL, NULL }, { FLDT_REXTFLG, "rextflag", fp_num, "%u", SI(RMAPBT_EXNTFLAG_BITLEN), 0, NULL, NULL }, { FLDT_RATTRFORKFLG, "rattrforkflag", fp_num, "%u", SI(RMAPBT_ATTRFLAG_BITLEN), 0, NULL, NULL }, { FLDT_RBMBTFLG, "rbmbtflag", fp_num, "%u", SI(RMAPBT_BMBTFLAG_BITLEN), 0, NULL, NULL }, { FLDT_CAGBLOCK, "cagblock", fp_num, "%u", SI(REFCNTBT_AGBLOCK_BITLEN), FTARG_DONULL, fa_agblock, NULL }, { FLDT_CCOWFLG, "ccowflag", fp_num, "%u", SI(REFCNTBT_COWFLAG_BITLEN), 0, NULL, NULL }, { FLDT_CNTBT, "cntbt", NULL, (char *)cntbt_flds, btblock_size, FTARG_SIZE, NULL, cntbt_flds }, { FLDT_CNTBT_CRC, "cntbt", NULL, (char *)cntbt_crc_flds, btblock_size, FTARG_SIZE, NULL, cntbt_crc_flds }, { FLDT_CNTBTKEY, "cntbtkey", fp_sarray, (char *)cntbt_key_flds, SI(bitsz(xfs_alloc_key_t)), 0, NULL, cntbt_key_flds }, { FLDT_CNTBTPTR, "cntbtptr", fp_num, "%u", SI(bitsz(xfs_alloc_ptr_t)), 0, fa_agblock, NULL }, { FLDT_CNTBTREC, "cntbtrec", fp_sarray, (char *)cntbt_rec_flds, SI(bitsz(xfs_alloc_rec_t)), 0, NULL, cntbt_rec_flds }, { FLDT_RMAPBT_CRC, "rmapbt", NULL, (char *)rmapbt_crc_flds, btblock_size, FTARG_SIZE, NULL, rmapbt_crc_flds }, { FLDT_RMAPBTKEY, "rmapbtkey", fp_sarray, (char *)rmapbt_key_flds, SI(bitize(2 * sizeof(struct xfs_rmap_key))), 0, NULL, rmapbt_key_flds }, { FLDT_RMAPBTPTR, "rmapbtptr", fp_num, "%u", SI(bitsz(xfs_rmap_ptr_t)), 0, fa_agblock, NULL }, { FLDT_RMAPBTREC, "rmapbtrec", fp_sarray, (char *)rmapbt_rec_flds, SI(bitsz(struct xfs_rmap_rec)), 0, NULL, rmapbt_rec_flds }, { FLDT_REFCBT_CRC, "refcntbt", NULL, (char *)refcbt_crc_flds, btblock_size, FTARG_SIZE, NULL, refcbt_crc_flds }, { FLDT_REFCBTKEY, "refcntbtkey", fp_sarray, (char *)refcbt_key_flds, SI(bitsz(struct xfs_refcount_key)), 0, NULL, refcbt_key_flds }, { FLDT_REFCBTPTR, "refcntbtptr", fp_num, "%u", SI(bitsz(xfs_refcount_ptr_t)), 0, fa_agblock, NULL }, { FLDT_REFCBTREC, "refcntbtrec", fp_sarray, (char *)refcbt_rec_flds, SI(bitsz(struct xfs_refcount_rec)), 0, NULL, refcbt_rec_flds }, /* CRC field */ { FLDT_CRC, "crc", fp_crc, "%#x (%s)", SI(bitsz(uint32_t)), 0, NULL, NULL }, { FLDT_DEV, "dev", fp_num, "%#x", SI(bitsz(xfs_dev_t)), 0, NULL, NULL }, { FLDT_DFILOFFA, "dfiloffa", fp_num, "%llu", SI(bitsz(xfs_fileoff_t)), 0, fa_dfiloffa, NULL }, { FLDT_DFILOFFD, "dfiloffd", fp_num, "%llu", SI(bitsz(xfs_fileoff_t)), 0, fa_dfiloffd, NULL }, { FLDT_DFSBNO, "dfsbno", fp_num, "%llu", SI(bitsz(xfs_fsblock_t)), FTARG_DONULL, fa_dfsbno, NULL }, { FLDT_DINODE_A, "dinode_a", NULL, (char *)inode_a_flds, inode_a_size, FTARG_SIZE|FTARG_OKEMPTY, NULL, inode_a_flds }, { FLDT_DINODE_CORE, "dinode_core", NULL, (char *)inode_core_flds, SI(bitsz(xfs_dinode_t)), 0, NULL, inode_core_flds }, { FLDT_DINODE_FMT, "dinode_fmt", fp_dinode_fmt, NULL, SI(bitsz(int8_t)), 0, NULL, NULL }, { FLDT_DINODE_U, "dinode_u", NULL, (char *)inode_u_flds, inode_u_size, FTARG_SIZE|FTARG_OKEMPTY, NULL, inode_u_flds }, { FLDT_DINODE_V3, "dinode_v3", NULL, (char *)inode_v3_flds, SI(bitsz(xfs_dinode_t)), 0, NULL, inode_v3_flds }, /* dir v2 fields */ { FLDT_DIR2, "dir2", NULL, (char *)dir2_flds, dir2_size, FTARG_SIZE, NULL, dir2_flds }, { FLDT_DIR2_BLOCK_TAIL, "dir2_block_tail", NULL, (char *)dir2_block_tail_flds, SI(bitsz(xfs_dir2_block_tail_t)), 0, NULL, dir2_block_tail_flds }, { FLDT_DIR2_DATA_FREE, "dir2_data_free", NULL, (char *)dir2_data_free_flds, SI(bitsz(xfs_dir2_data_free_t)), 0, NULL, dir2_data_free_flds }, { FLDT_DIR2_DATA_HDR, "dir2_data_hdr", NULL, (char *)dir2_data_hdr_flds, SI(bitsz(xfs_dir2_data_hdr_t)), 0, NULL, dir2_data_hdr_flds }, { FLDT_DIR2_DATA_OFF, "dir2_data_off", fp_num, "%#x", SI(bitsz(xfs_dir2_data_off_t)), 0, NULL, NULL }, { FLDT_DIR2_DATA_OFFNZ, "dir2_data_offnz", fp_num, "%#x", SI(bitsz(xfs_dir2_data_off_t)), FTARG_SKIPZERO, NULL, NULL }, { FLDT_DIR2_DATA_UNION, "dir2_data_union", NULL, (char *)dir2_data_union_flds, dir2_data_union_size, FTARG_SIZE, NULL, dir2_data_union_flds }, { FLDT_DIR2_FREE_HDR, "dir2_free_hdr", NULL, (char *)dir2_free_hdr_flds, SI(bitsz(xfs_dir2_free_hdr_t)), 0, NULL, dir2_free_hdr_flds }, { FLDT_DIR2_INO4, "dir2_ino4", fp_num, "%u", SI(bitize(XFS_INO32_SIZE)), 0, fa_ino4, NULL }, { FLDT_DIR2_INO8, "dir2_ino8", fp_num, "%llu", SI(bitize(XFS_INO64_SIZE)), 0, fa_ino8, NULL }, { FLDT_DIR2_INOU, "dir2_inou", NULL, (char *)dir2_inou_flds, dir2_inou_size, FTARG_SIZE, NULL, dir2_inou_flds }, { FLDT_DIR2_LEAF_ENTRY, "dir2_leaf_entry", NULL, (char *)dir2_leaf_entry_flds, SI(bitsz(xfs_dir2_leaf_entry_t)), 0, NULL, dir2_leaf_entry_flds }, { FLDT_DIR2_LEAF_HDR, "dir2_leaf_hdr", NULL, (char *)dir2_leaf_hdr_flds, SI(bitsz(xfs_dir2_leaf_hdr_t)), 0, NULL, dir2_leaf_hdr_flds }, { FLDT_DIR2_LEAF_TAIL, "dir2_leaf_tail", NULL, (char *)dir2_leaf_tail_flds, SI(bitsz(xfs_dir2_leaf_tail_t)), 0, NULL, dir2_leaf_tail_flds }, { FLDT_DIR2_SF_ENTRY, "dir2_sf_entry", NULL, (char *)dir2_sf_entry_flds, dir2_sf_entry_size, FTARG_SIZE, NULL, dir2_sf_entry_flds }, { FLDT_DIR2_SF_HDR, "dir2_sf_hdr", NULL, (char *)dir2_sf_hdr_flds, dir2_sf_hdr_size, FTARG_SIZE, NULL, dir2_sf_hdr_flds }, { FLDT_DIR2_SF_OFF, "dir2_sf_off", fp_num, "%#x", SI(bitize(2*sizeof(__u8))), 0, NULL, NULL }, { FLDT_DIR2SF, "dir2sf", NULL, (char *)dir2sf_flds, dir2sf_size, FTARG_SIZE, NULL, dir2sf_flds }, /* dir v3 fields */ { FLDT_DIR3, "dir3", NULL, (char *)dir3_flds, dir2_size, FTARG_SIZE, NULL, dir3_flds }, { FLDT_DIR3_BLKHDR, "dir3_blk_hdr", NULL, (char *)dir3_blkhdr_flds, SI(bitsz(struct xfs_dir3_blk_hdr)), 0, NULL, dir3_blkhdr_flds }, { FLDT_DIR3_DATA_HDR, "dir3_data_hdr", NULL, (char *)dir3_data_hdr_flds, SI(bitsz(struct xfs_dir3_data_hdr)), 0, NULL, dir3_data_hdr_flds }, { FLDT_DIR3_FREE_HDR, "dir3_free_hdr", NULL, (char *)dir3_free_hdr_flds, SI(bitsz(struct xfs_dir3_free_hdr)), 0, NULL, dir3_free_hdr_flds }, { FLDT_DIR3_LEAF_HDR, "dir3_leaf_hdr", NULL, (char *)dir3_leaf_hdr_flds, SI(bitsz(struct xfs_dir3_leaf_hdr)), 0, NULL, dir3_leaf_hdr_flds }, { FLDT_DIR3_DATA_UNION, "dir3_data_union", NULL, (char *)dir3_data_union_flds, dir2_data_union_size, FTARG_SIZE, NULL, dir3_data_union_flds }, { FLDT_DIR3_SF_ENTRY, "dir3_sf_entry", NULL, (char *)dir3_sf_entry_flds, dir2_sf_entry_size, FTARG_SIZE, NULL, dir3_sf_entry_flds }, { FLDT_DIR3SF, "dir3sf", NULL, (char *)dir3sf_flds, dir2sf_size, FTARG_SIZE, NULL, dir3sf_flds }, /* dir v2/3 node fields */ { FLDT_DA_BLKINFO, "dir_blkinfo", NULL, (char *)da_blkinfo_flds, SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, da_blkinfo_flds }, { FLDT_DA_NODE_ENTRY, "dir_node_entry", fp_sarray, (char *)da_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0, NULL, da_node_entry_flds }, { FLDT_DA_NODE_HDR, "dir_node_hdr", NULL, (char *)da_node_hdr_flds, SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, da_node_hdr_flds }, { FLDT_DA3_BLKINFO, "dir_blkinfo", NULL, (char *)da3_blkinfo_flds, SI(bitsz(struct xfs_da3_blkinfo)), 0, NULL, da3_blkinfo_flds }, { FLDT_DA3_NODE_HDR, "dir_node_hdr", NULL, (char *)da3_node_hdr_flds, SI(bitsz(struct xfs_da3_node_hdr)), 0, NULL, da3_node_hdr_flds }, { FLDT_DIRBLOCK, "dirblock", fp_num, "%u", SI(bitsz(uint32_t)), 0, fa_dirblock, NULL }, { FLDT_DISK_DQUOT, "disk_dquot", NULL, (char *)disk_dquot_flds, SI(bitsz(xfs_disk_dquot_t)), 0, NULL, disk_dquot_flds }, { FLDT_DQBLK, "dqblk", NULL, (char *)dqblk_flds, SI(bitsz(xfs_dqblk_t)), 0, NULL, dqblk_flds }, { FLDT_DQID, "dqid", fp_num, "%d", SI(bitsz(xfs_dqid_t)), 0, NULL, NULL }, { FLDT_DRFSBNO, "drfsbno", fp_num, "%llu", SI(bitsz(xfs_rfsblock_t)), FTARG_DONULL, fa_drfsbno, NULL }, { FLDT_DRTBNO, "drtbno", fp_num, "%llu", SI(bitsz(xfs_rtblock_t)), FTARG_DONULL, fa_drtbno, NULL }, { FLDT_EXTLEN, "extlen", fp_num, "%u", SI(bitsz(xfs_extlen_t)), 0, NULL, NULL }, { FLDT_EXTNUM, "extnum", fp_num, "%d", SI(bitsz(xfs_extnum_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_FSIZE, "fsize", fp_num, "%lld", SI(bitsz(xfs_fsize_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_INO, "ino", fp_num, "%llu", SI(bitsz(xfs_ino_t)), FTARG_DONULL, fa_ino, NULL }, { FLDT_INOBT, "inobt", NULL, (char *)inobt_flds, btblock_size, FTARG_SIZE, NULL, inobt_flds }, { FLDT_INOBT_CRC, "inobt", NULL, (char *)inobt_crc_flds, btblock_size, FTARG_SIZE, NULL, inobt_crc_flds }, { FLDT_INOBT_SPCRC, "inobt", NULL, (char *)inobt_spcrc_flds, btblock_size, FTARG_SIZE, NULL, inobt_spcrc_flds }, { FLDT_INOBTKEY, "inobtkey", fp_sarray, (char *)inobt_key_flds, SI(bitsz(xfs_inobt_key_t)), 0, NULL, inobt_key_flds }, { FLDT_INOBTPTR, "inobtptr", fp_num, "%u", SI(bitsz(xfs_inobt_ptr_t)), 0, fa_agblock, NULL }, { FLDT_INOBTREC, "inobtrec", fp_sarray, (char *)inobt_rec_flds, SI(bitsz(xfs_inobt_rec_t)), 0, NULL, inobt_rec_flds }, { FLDT_INOBTSPREC, "inobtsprec", fp_sarray, (char *) inobt_sprec_flds, SI(bitsz(xfs_inobt_rec_t)), 0, NULL, inobt_sprec_flds }, { FLDT_INODE, "inode", NULL, (char *)inode_flds, inode_size, FTARG_SIZE, NULL, inode_flds }, { FLDT_INODE_CRC, "inode", NULL, (char *)inode_crc_flds, inode_size, FTARG_SIZE, NULL, inode_crc_flds }, { FLDT_INOFREE, "inofree", fp_num, "%#llx", SI(bitsz(xfs_inofree_t)), 0, NULL, NULL }, { FLDT_INT16D, "int16d", fp_num, "%d", SI(bitsz(int16_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_INT32D, "int32d", fp_num, "%d", SI(bitsz(int32_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_INT64D, "int64d", fp_num, "%lld", SI(bitsz(int64_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_INT8D, "int8d", fp_num, "%d", SI(bitsz(int8_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_NSEC, "nsec", fp_num, "%09d", SI(bitsz(int32_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_QCNT, "qcnt", fp_num, "%llu", SI(bitsz(xfs_qcnt_t)), 0, NULL, NULL }, { FLDT_QWARNCNT, "qwarncnt", fp_num, "%u", SI(bitsz(xfs_qwarncnt_t)), 0, NULL, NULL }, { FLDT_SB, "sb", NULL, (char *)sb_flds, sb_size, FTARG_SIZE, NULL, sb_flds }, /* CRC enabled symlink */ { FLDT_SYMLINK_CRC, "symlink", NULL, (char *)symlink_crc_flds, symlink_size, FTARG_SIZE, NULL, symlink_crc_flds }, { FLDT_TIME, "time", fp_time, NULL, SI(bitsz(int32_t)), FTARG_SIGNED, NULL, NULL }, { FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds, SI(bitsz(xfs_timestamp_t)), 0, NULL, timestamp_flds }, { FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL }, { FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(uint16_t)), 0, NULL, NULL }, { FLDT_UINT16O, "uint16o", fp_num, "%#o", SI(bitsz(uint16_t)), 0, NULL, NULL }, { FLDT_UINT16X, "uint16x", fp_num, "%#x", SI(bitsz(uint16_t)), 0, NULL, NULL }, { FLDT_UINT32D, "uint32d", fp_num, "%u", SI(bitsz(uint32_t)), 0, NULL, NULL }, { FLDT_UINT32O, "uint32o", fp_num, "%#o", SI(bitsz(uint32_t)), 0, NULL, NULL }, { FLDT_UINT32X, "uint32x", fp_num, "%#x", SI(bitsz(uint32_t)), 0, NULL, NULL }, { FLDT_UINT64D, "uint64d", fp_num, "%llu", SI(bitsz(uint64_t)), 0, NULL, NULL }, { FLDT_UINT64O, "uint64o", fp_num, "%#llo", SI(bitsz(uint64_t)), 0, NULL, NULL }, { FLDT_UINT64X, "uint64x", fp_num, "%#llx", SI(bitsz(uint64_t)), 0, NULL, NULL }, { FLDT_UINT8D, "uint8d", fp_num, "%u", SI(bitsz(uint8_t)), 0, NULL, NULL }, { FLDT_UINT8O, "uint8o", fp_num, "%#o", SI(bitsz(uint8_t)), 0, NULL, NULL }, { FLDT_UINT8X, "uint8x", fp_num, "%#x", SI(bitsz(uint8_t)), 0, NULL, NULL }, { FLDT_UUID, "uuid", fp_uuid, NULL, SI(bitsz(uuid_t)), 0, NULL, NULL }, { FLDT_ZZZ, NULL } }; int bitoffset( const field_t *f, void *obj, int startoff, int idx) { if (!(f->flags & FLD_OFFSET)) { if (f->flags & FLD_ARRAY) { int abase; #ifdef DEBUG const ftattr_t *fa = &ftattrtab[f->ftyp]; #endif abase = (f->flags & FLD_ABASE1) != 0; ASSERT(fa->ftyp == f->ftyp); ASSERT((fa->arg & FTARG_SIZE) == 0); return (int)(intptr_t)f->offset + (idx - abase) * fsize(f, obj, startoff, idx); } else return (int)(intptr_t)f->offset; } else return (*f->offset)(obj, startoff, idx); } int fcount( const field_t *f, void *obj, int startoff) { if (!(f->flags & FLD_COUNT)) return (int)(intptr_t)f->count; else return (*f->count)(obj, startoff); } const field_t * findfield( char *name, const field_t *fields, void *obj, int startoff) { const field_t *f; /* we only match if this field name matches and has a non-zero count */ for (f = fields; f->name; f++) if (strcmp(f->name, name) == 0 && fcount(f, obj, startoff)) return f; return NULL; } int fsize( const field_t *f, void *obj, int startoff, int idx) { const ftattr_t *fa; fa = &ftattrtab[f->ftyp]; ASSERT(fa->ftyp == f->ftyp); if (!(fa->arg & FTARG_SIZE)) return (int)(intptr_t)fa->size; else return (*fa->size)(obj, startoff, idx); } xfsprogs-5.3.0/db/field.h0000644000175000017500000001121713435336036015075 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ typedef enum fldt { FLDT_AEXTNUM, FLDT_AGBLOCK, FLDT_AGBLOCKNZ, FLDT_AGF, FLDT_AGFL, FLDT_AGFL_CRC, FLDT_AGI, FLDT_AGINO, FLDT_AGINONN, FLDT_AGNUMBER, /* attr fields */ FLDT_ATTR, FLDT_ATTR_BLKINFO, FLDT_ATTR_LEAF_ENTRY, FLDT_ATTR_LEAF_HDR, FLDT_ATTR_LEAF_MAP, FLDT_ATTR_LEAF_NAME, FLDT_ATTR_NODE_ENTRY, FLDT_ATTR_NODE_HDR, FLDT_ATTR_SF_ENTRY, FLDT_ATTR_SF_HDR, FLDT_ATTRBLOCK, FLDT_ATTRSHORT, /* attr 3 specific fields */ FLDT_ATTR3, FLDT_ATTR3_BLKINFO, FLDT_ATTR3_LEAF_HDR, FLDT_ATTR3_NODE_HDR, FLDT_ATTR3_REMOTE_HDR, FLDT_BMAPBTA, FLDT_BMAPBTA_CRC, FLDT_BMAPBTAKEY, FLDT_BMAPBTAPTR, FLDT_BMAPBTAREC, FLDT_BMAPBTD, FLDT_BMAPBTD_CRC, FLDT_BMAPBTDKEY, FLDT_BMAPBTDPTR, FLDT_BMAPBTDREC, FLDT_BMROOTA, FLDT_BMROOTAKEY, FLDT_BMROOTAPTR, FLDT_BMROOTD, FLDT_BMROOTDKEY, FLDT_BMROOTDPTR, FLDT_BNOBT, FLDT_BNOBT_CRC, FLDT_BNOBTKEY, FLDT_BNOBTPTR, FLDT_BNOBTREC, FLDT_CEXTFLG, FLDT_CEXTLEN, FLDT_CFILEOFFA, FLDT_CFILEOFFD, FLDT_CFSBLOCK, FLDT_CHARNS, FLDT_CHARS, FLDT_REXTLEN, FLDT_RFILEOFFD, FLDT_REXTFLG, FLDT_RATTRFORKFLG, FLDT_RBMBTFLG, FLDT_CAGBLOCK, FLDT_CCOWFLG, FLDT_CNTBT, FLDT_CNTBT_CRC, FLDT_CNTBTKEY, FLDT_CNTBTPTR, FLDT_CNTBTREC, FLDT_RMAPBT_CRC, FLDT_RMAPBTKEY, FLDT_RMAPBTPTR, FLDT_RMAPBTREC, FLDT_REFCBT_CRC, FLDT_REFCBTKEY, FLDT_REFCBTPTR, FLDT_REFCBTREC, /* CRC field type */ FLDT_CRC, FLDT_DEV, FLDT_DFILOFFA, FLDT_DFILOFFD, FLDT_DFSBNO, FLDT_DINODE_A, FLDT_DINODE_CORE, FLDT_DINODE_FMT, FLDT_DINODE_U, FLDT_DINODE_V3, /* dir v2 fields */ FLDT_DIR2, FLDT_DIR2_BLOCK_TAIL, FLDT_DIR2_DATA_FREE, FLDT_DIR2_DATA_HDR, FLDT_DIR2_DATA_OFF, FLDT_DIR2_DATA_OFFNZ, FLDT_DIR2_DATA_UNION, FLDT_DIR2_FREE_HDR, FLDT_DIR2_INO4, FLDT_DIR2_INO8, FLDT_DIR2_INOU, FLDT_DIR2_LEAF_ENTRY, FLDT_DIR2_LEAF_HDR, FLDT_DIR2_LEAF_TAIL, FLDT_DIR2_SF_ENTRY, FLDT_DIR2_SF_HDR, FLDT_DIR2_SF_OFF, FLDT_DIR2SF, /* dir v3 fields */ FLDT_DIR3, FLDT_DIR3_BLKHDR, FLDT_DIR3_DATA_HDR, FLDT_DIR3_FREE_HDR, FLDT_DIR3_LEAF_HDR, FLDT_DIR3_DATA_UNION, FLDT_DIR3_SF_ENTRY, FLDT_DIR3SF, /* dir v2/3 node fields */ FLDT_DA_BLKINFO, FLDT_DA_NODE_ENTRY, FLDT_DA_NODE_HDR, FLDT_DA3_BLKINFO, FLDT_DA3_NODE_HDR, FLDT_DIRBLOCK, FLDT_DISK_DQUOT, FLDT_DQBLK, FLDT_DQID, FLDT_DRFSBNO, FLDT_DRTBNO, FLDT_EXTLEN, FLDT_EXTNUM, FLDT_FSIZE, FLDT_INO, FLDT_INOBT, FLDT_INOBT_CRC, FLDT_INOBT_SPCRC, FLDT_INOBTKEY, FLDT_INOBTPTR, FLDT_INOBTREC, FLDT_INOBTSPREC, FLDT_INODE, FLDT_INODE_CRC, FLDT_INOFREE, FLDT_INT16D, FLDT_INT32D, FLDT_INT64D, FLDT_INT8D, FLDT_NSEC, FLDT_QCNT, FLDT_QWARNCNT, FLDT_SB, /* CRC enabled symlink */ FLDT_SYMLINK_CRC, FLDT_TIME, FLDT_TIMESTAMP, FLDT_UINT1, FLDT_UINT16D, FLDT_UINT16O, FLDT_UINT16X, FLDT_UINT32D, FLDT_UINT32O, FLDT_UINT32X, FLDT_UINT64D, FLDT_UINT64O, FLDT_UINT64X, FLDT_UINT8D, FLDT_UINT8O, FLDT_UINT8X, FLDT_UUID, FLDT_ZZZ /* mark last entry */ } fldt_t; typedef int (*offset_fnc_t)(void *obj, int startoff, int idx); #define OI(o) ((offset_fnc_t)(intptr_t)(o)) typedef int (*count_fnc_t)(void *obj, int startoff); #define CI(c) ((count_fnc_t)(intptr_t)(c)) #define C1 CI(1) typedef struct field { char *name; fldt_t ftyp; offset_fnc_t offset; count_fnc_t count; int flags; typnm_t next; } field_t; /* * flag values */ #define FLD_ABASE1 1 /* field array base is 1 not 0 */ #define FLD_SKIPALL 2 /* skip this field in an all-fields print */ #define FLD_ARRAY 4 /* this field is an array */ #define FLD_OFFSET 8 /* offset value is a function pointer */ #define FLD_COUNT 16 /* count value is a function pointer */ typedef int (*size_fnc_t)(void *obj, int startoff, int idx); #define SI(s) ((size_fnc_t)(intptr_t)(s)) typedef struct ftattr { fldt_t ftyp; char *name; prfnc_t prfunc; char *fmtstr; size_fnc_t size; int arg; adfnc_t adfunc; const field_t *subfld; } ftattr_t; extern const ftattr_t ftattrtab[]; /* * arg values */ #define FTARG_SKIPZERO 1 /* skip 0 words */ #define FTARG_DONULL 2 /* make -1 words be "null" */ #define FTARG_SKIPNULL 4 /* skip -1 words */ #define FTARG_SIGNED 8 /* field value is signed */ #define FTARG_SIZE 16 /* size field is a function */ #define FTARG_SKIPNMS 32 /* skip printing names this time */ #define FTARG_OKEMPTY 64 /* ok if this (union type) is empty */ extern int bitoffset(const field_t *f, void *obj, int startoff, int idx); extern int fcount(const field_t *f, void *obj, int startoff); extern const field_t *findfield(char *name, const field_t *fields, void *obj, int startoff); extern int fsize(const field_t *f, void *obj, int startoff, int idx); xfsprogs-5.3.0/db/flist.c0000644000175000017500000002151213435336036015125 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "flist.h" #include "debug.h" #include "output.h" #include "malloc.h" static void flist_expand_arrays(flist_t *fl); static void flist_expand_structs(flist_t *fl, void *obj); static flist_t *flist_replicate(flist_t *fl); static ftok_t *flist_split(char *s); static void ftok_free(ftok_t *ft); static void flist_expand_arrays( flist_t *fl) { const field_t *f; #ifdef DEBUG const ftattr_t *fa; #endif int high; int idx; int low; flist_t *new; flist_t *prev; flist_t *sib; f = fl->fld; #ifdef DEBUG fa = &ftattrtab[f->ftyp]; #endif ASSERT(fa->ftyp == f->ftyp); ASSERT(f->flags & FLD_ARRAY); low = fl->low; high = fl->high; fl->high = fl->low; sib = fl->sibling; for (idx = low + 1, prev = fl; idx <= high; idx++) { new = flist_make(f->name); new->fld = f; new->low = new->high = idx; new->flags |= FL_OKLOW | FL_OKHIGH; new->child = flist_replicate(fl->child); prev->sibling = new; prev = new; } prev->sibling = sib; } static void flist_expand_structs( flist_t *fl, void *obj) { const field_t *cf; const field_t *f; const ftattr_t *fa; flist_t *new; flist_t *prev; f = fl->fld; fa = &ftattrtab[f->ftyp]; ASSERT(fa->ftyp == f->ftyp); ASSERT(fa->subfld != NULL); ASSERT(fl->child == NULL); for (cf = fa->subfld, prev = NULL; cf->name != NULL; cf++) { if (fcount(cf, obj, fl->offset) == 0) continue; if (cf->flags & FLD_SKIPALL) continue; new = flist_make(cf->name); new->fld = cf; if (prev) prev->sibling = new; else fl->child = new; prev = new; } } void flist_free( flist_t *fl) { if (fl->child) flist_free(fl->child); if (fl->sibling) flist_free(fl->sibling); if (fl->name) xfree(fl->name); xfree(fl); } flist_t * flist_make( char *name) { flist_t *fl; fl = xmalloc(sizeof(*fl)); fl->name = xstrdup(name); fl->fld = NULL; fl->child = NULL; fl->sibling = NULL; fl->low = 0; fl->high = 0; fl->flags = 0; fl->offset = 0; return fl; } int flist_parse( const field_t *fields, flist_t *fl, void *obj, int startoff) { const field_t *f; const ftattr_t *fa; int high; int low; while (fl) { f = findfield(fl->name, fields, obj, startoff); if (f == NULL) { dbprintf(_("field %s not found\n"), fl->name); return 0; } fl->fld = f; fa = &ftattrtab[f->ftyp]; ASSERT(fa->ftyp == f->ftyp); if (f->flags & FLD_ARRAY) { low = (f->flags & FLD_ABASE1) != 0; high = fcount(f, obj, startoff) + low - 1; if (low > high) { dbprintf(_("no elements in %s\n"), fl->name); return 0; } if (fl->flags & FL_OKHIGH) { if (fl->low < low || fl->low > high || fl->high < low || fl->high > high) { dbprintf(_("indices %d-%d for field %s " "out of range %d-%d\n"), fl->low, fl->high, fl->name, low, high); return 0; } } else if (fl->flags & FL_OKLOW) { if (fl->low < low || fl->low > high) { dbprintf(_("index %d for field %s out of " "range %d-%d\n"), fl->low, fl->name, low, high); return 0; } fl->high = fl->low; fl->flags |= FL_OKHIGH; } else { fl->low = low; fl->high = high; fl->flags |= FL_OKLOW | FL_OKHIGH; } } else { if (fl->flags & FL_OKLOW) { dbprintf(_("field %s is not an array\n"), fl->name); return 0; } } fl->offset = startoff + bitoffset(f, obj, startoff, fl->low); if ((fl->child != NULL || fa->prfunc == NULL) && (f->flags & FLD_ARRAY) && fl->low != fl->high) flist_expand_arrays(fl); if (fa->prfunc == NULL && fl->child == NULL) flist_expand_structs(fl, obj); if (fl->child) { if (fa->subfld == NULL) { dbprintf(_("field %s has no subfields\n"), fl->name); return 0; } if (!flist_parse(fa->subfld, fl->child, obj, fl->offset)) return 0; } fl = fl->sibling; } return 1; } void flist_print( flist_t *fl) { if (!(debug_state & DEBUG_FLIST)) return; while (fl) { dbprintf(_("fl@%p:\n"), fl); dbprintf(_("\tname=%s, fld=%p, child=%p, sibling=%p\n"), fl->name, fl->fld, fl->child, fl->sibling); dbprintf(_("\tlow=%d, high=%d, flags=%d (%s%s), offset=%d\n"), fl->low, fl->high, fl->flags, fl->flags & FL_OKLOW ? _("oklow ") : "", fl->flags & FL_OKHIGH ? _("okhigh") : "", fl->offset); dbprintf(_("\tfld->name=%s, fld->ftyp=%d (%s)\n"), fl->fld->name, fl->fld->ftyp, ftattrtab[fl->fld->ftyp].name); dbprintf(_("\tfld->flags=%d (%s%s%s%s%s)\n"), fl->fld->flags, fl->fld->flags & FLD_ABASE1 ? "abase1 " : "", fl->fld->flags & FLD_SKIPALL ? "skipall " : "", fl->fld->flags & FLD_ARRAY ? "array " : "", fl->fld->flags & FLD_OFFSET ? "offset " : "", fl->fld->flags & FLD_COUNT ? "count " : ""); if (fl->child) flist_print(fl->child); fl = fl->sibling; } } static flist_t * flist_replicate( flist_t *f) { flist_t *new; if (f == NULL) return NULL; new = flist_make(f->name); new->fld = f->fld; new->child = flist_replicate(f->child); new->sibling = flist_replicate(f->sibling); new->low = f->low; new->high = f->high; new->flags = f->flags; new->offset = f->offset; return new; } flist_t * flist_scan( char *name) { flist_t *fl; flist_t *lfl; flist_t *nfl; int num; ftok_t *p; ftok_t *v; char *x; v = flist_split(name); if (!v) return NULL; p = v; fl = lfl = NULL; while (p->tokty != TT_END) { if (p->tokty != TT_NAME) goto bad; nfl = flist_make(p->tok); if (lfl) lfl->child = nfl; else fl = nfl; lfl = nfl; p++; if (p->tokty == TT_LB) { p++; if (p->tokty != TT_NUM) goto bad; num = (int)strtoul(p->tok, &x, 0); if (*x != '\0') goto bad; nfl->flags |= FL_OKLOW; nfl->low = num; p++; if (p->tokty == TT_DASH) { p++; if (p->tokty != TT_NUM) goto bad; num = (int)strtoul(p->tok, &x, 0); if (*x != '\0') goto bad; nfl->flags |= FL_OKHIGH; nfl->high = num; p++; } if (p->tokty != TT_RB) goto bad; p++; } if (p->tokty == TT_DOT) { p++; if (p->tokty == TT_END) goto bad; } } ftok_free(v); return fl; bad: dbprintf(_("bad syntax in field name %s\n"), name); ftok_free(v); if (fl) flist_free(fl); return NULL; } static ftok_t * flist_split( char *s) { char *a; int i; static char *idchars; static char *initidchar; int l; int tailskip = 0; static char *numchars; static char *xnumchars; /* extended for hex conversion */ int nv; static char punctchars[] = "[-]."; static tokty_t puncttypes[] = { TT_LB, TT_DASH, TT_RB, TT_DOT }; tokty_t t; ftok_t *v; if (idchars == NULL) { idchars = xmalloc(26 + 10 + 1 + 1); initidchar = xmalloc(26 + 1); numchars = xmalloc(10 + 1); xnumchars = xmalloc(12 + 1); for (i = 'a'; i <= 'z'; i++) { idchars[i - 'a'] = i; initidchar[i - 'a'] = i; } for (i = '0'; i <= '9'; i++) { idchars[26 + (i - '0')] = i; numchars[i - '0'] = i; xnumchars[i - '0'] = i; } idchars[26 + 10] = '_'; idchars[26 + 10 + 1] = '\0'; initidchar[26] = '\0'; numchars[10] = '\0'; xnumchars[10] = 'x'; xnumchars[11] = 'X'; xnumchars[12] = '\0'; } nv = 0; v = xmalloc(sizeof(*v)); v->tok = NULL; while (*s) { /* need to add string handling */ if (*s == '\"') { s++; /* skip first quote */ if ((a = strrchr(s, '\"')) == NULL) { dbprintf(_("missing closing quote %s\n"), s); ftok_free(v); return NULL; } tailskip = 1; /* skip remaing quote */ l = (int)(a - s); t = TT_STRING; } else if (strchr(initidchar, *s)) { l = (int)strspn(s, idchars); t = TT_NAME; } else if (strchr(numchars, *s)) { l = (int)strspn(s, xnumchars); t = TT_NUM; } else if ((a = strchr(punctchars, *s))) { l = 1; t = puncttypes[a - punctchars]; } else { dbprintf(_("bad character in field %s\n"), s); ftok_free(v); return NULL; } a = xmalloc(l + 1); strncpy(a, s, l); a[l] = '\0'; v = xrealloc(v, (nv + 2) * sizeof(*v)); v[nv + 1].tok = NULL; v[nv].tok = a; v[nv].tokty = t; nv++; s += l + tailskip; tailskip = 0; } v[nv].tok = NULL; v[nv].tokty = TT_END; return v; } /* * Given a set of fields, scan for a field of the given type. * Return an flist leading to the first found field * of that type. * Return NULL if no field of the given type is found. */ flist_t * flist_find_ftyp( const field_t *fields, fldt_t type) { flist_t *fl; const field_t *f; const ftattr_t *fa; for (f = fields; f->name; f++) { fl = flist_make(f->name); fl->fld = f; if (f->ftyp == type) return fl; fa = &ftattrtab[f->ftyp]; if (fa->subfld) { flist_t *nfl; nfl = flist_find_ftyp(fa->subfld, type); if (nfl) { fl->child = nfl; return fl; } } flist_free(fl); } return NULL; } static void ftok_free( ftok_t *ft) { ftok_t *p; for (p = ft; p->tok; p++) xfree(p->tok); xfree(ft); } xfsprogs-5.3.0/db/flist.h0000644000175000017500000000154113435336036015132 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct field; typedef struct flist { char *name; const struct field *fld; struct flist *child; struct flist *sibling; int low; int high; int flags; int offset; } flist_t; /* * Flags for flist */ #define FL_OKLOW 1 #define FL_OKHIGH 2 typedef enum tokty { TT_NAME, TT_NUM, TT_STRING, TT_LB, TT_RB, TT_DASH, TT_DOT, TT_END } tokty_t; typedef struct ftok { char *tok; tokty_t tokty; } ftok_t; extern void flist_free(flist_t *fl); extern flist_t *flist_make(char *name); extern int flist_parse(const struct field *fields, flist_t *fl, void *obj, int startoff); extern void flist_print(flist_t *fl); extern flist_t *flist_scan(char *name); extern flist_t *flist_find_ftyp(const field_t *fields, fldt_t type); xfsprogs-5.3.0/db/fprint.c0000644000175000017500000000752313435336036015314 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "inode.h" #include "btblock.h" #include "bit.h" #include "print.h" #include "output.h" #include "sig.h" #include "malloc.h" #include "io.h" int fp_charns( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { int i; char *p; ASSERT(bitoffs(bit) == 0); ASSERT(size == bitsz(char)); dbprintf("\""); for (i = 0, p = (char *)obj + byteize(bit); i < count && !seenint(); i++, p++) { if (*p == '\\' || *p == '\'' || *p == '"' || *p == '\?') dbprintf("\\%c", *p); else if (isgraph((int)*p) || *p == ' ') dbprintf("%c", *p); else if (*p == '\a' || *p == '\b' || *p == '\f' || *p == '\n' || *p == '\r' || *p == '\t' || *p == '\v') dbprintf("\\%c", *p + ('a' - '\a')); else dbprintf("\\%03o", *p & 0xff); } dbprintf("\""); return 1; } int fp_num( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { int bitpos; int i; int isnull; int64_t val; for (i = 0, bitpos = bit; i < count && !seenint(); i++, bitpos += size) { val = getbitval(obj, bitpos, size, (arg & FTARG_SIGNED) ? BVSIGNED : BVUNSIGNED); if ((arg & FTARG_SKIPZERO) && val == 0) continue; isnull = (arg & FTARG_SIGNED) || size == 64 ? val == -1LL : val == ((1LL << size) - 1LL); if ((arg & FTARG_SKIPNULL) && isnull) continue; if (array && count > 1) dbprintf("%d:", i + base); if ((arg & FTARG_DONULL) && isnull) dbprintf(_("null")); else if (size > 32) dbprintf(fmtstr, val); else dbprintf(fmtstr, (int32_t)val); if (i < count - 1) dbprintf(" "); } return 1; } /*ARGSUSED*/ int fp_sarray( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { print_sarray(obj, bit, count, size, base, array, (const field_t *)fmtstr, (arg & FTARG_SKIPNMS) != 0); return 1; } /*ARGSUSED*/ int fp_time( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { int bitpos; char *c; int i; time_t t; ASSERT(bitoffs(bit) == 0); for (i = 0, bitpos = bit; i < count && !seenint(); i++, bitpos += size) { if (array) dbprintf("%d:", i + base); t = (time_t)getbitval((char *)obj + byteize(bitpos), 0, sizeof(int32_t) * 8, BVSIGNED); c = ctime(&t); dbprintf("%24.24s", c); if (i < count - 1) dbprintf(" "); } return 1; } /*ARGSUSED*/ int fp_uuid( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { char bp[40]; /* UUID string is 36 chars + trailing '\0' */ int i; uuid_t *p; ASSERT(bitoffs(bit) == 0); for (p = (uuid_t *)((char *)obj + byteize(bit)), i = 0; i < count && !seenint(); i++, p++) { if (array) dbprintf("%d:", i + base); platform_uuid_unparse(p, bp); dbprintf("%s", bp); if (i < count - 1) dbprintf(" "); } return 1; } /* * CRC is correct is the current buffer it is being pulled out * of is not marked with a EFSCORRUPTED error. */ int fp_crc( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { int bitpos; int i; int64_t val; char *ok; switch (iocur_crc_valid()) { case -1: ok = "unchecked"; break; case 0: ok = "bad"; break; case 1: ok = "correct"; break; default: ok = "unknown state"; break; } for (i = 0, bitpos = bit; i < count && !seenint(); i++, bitpos += size) { if (array) dbprintf("%d:", i + base); val = getbitval(obj, bitpos, size, BVUNSIGNED); if (size > 32) dbprintf(fmtstr, val, ok); else dbprintf(fmtstr, (int32_t)val, ok); if (i < count - 1) dbprintf(" "); } return 1; } xfsprogs-5.3.0/db/fprint.h0000644000175000017500000000161413435336036015314 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ typedef int (*prfnc_t)(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int fp_charns(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int fp_num(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int fp_sarray(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int fp_time(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int fp_uuid(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int fp_crc(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); xfsprogs-5.3.0/db/frag.c0000644000175000017500000002736213570057155014736 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "bmap.h" #include "command.h" #include "frag.h" #include "io.h" #include "output.h" #include "type.h" #include "init.h" #include "malloc.h" typedef struct extent { xfs_fileoff_t startoff; xfs_filblks_t blockcount; } extent_t; typedef struct extmap { int naents; int nents; extent_t ents[1]; } extmap_t; #define EXTMAP_SIZE(n) \ (offsetof(extmap_t, ents) + (sizeof(extent_t) * (n))) static int aflag; static int dflag; static uint64_t extcount_actual; static uint64_t extcount_ideal; static int fflag; static int lflag; static int qflag; static int Rflag; static int rflag; static int vflag; typedef void (*scan_lbtree_f_t)(struct xfs_btree_block *block, int level, extmap_t **extmapp, typnm_t btype); typedef void (*scan_sbtree_f_t)(struct xfs_btree_block *block, int level, xfs_agf_t *agf); static extmap_t *extmap_alloc(xfs_extnum_t nex); static xfs_extnum_t extmap_ideal(extmap_t *extmap); static void extmap_set_ext(extmap_t **extmapp, xfs_fileoff_t o, xfs_extlen_t c); static int frag_f(int argc, char **argv); static int init(int argc, char **argv); static void process_bmbt_reclist(xfs_bmbt_rec_t *rp, int numrecs, extmap_t **extmapp); static void process_btinode(xfs_dinode_t *dip, extmap_t **extmapp, int whichfork); static void process_exinode(xfs_dinode_t *dip, extmap_t **extmapp, int whichfork); static void process_fork(xfs_dinode_t *dip, int whichfork); static void process_inode(xfs_agf_t *agf, xfs_agino_t agino, xfs_dinode_t *dip); static void scan_ag(xfs_agnumber_t agno); static void scan_lbtree(xfs_fsblock_t root, int nlevels, scan_lbtree_f_t func, extmap_t **extmapp, typnm_t btype); static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, int nlevels, scan_sbtree_f_t func, typnm_t btype); static void scanfunc_bmap(struct xfs_btree_block *block, int level, extmap_t **extmapp, typnm_t btype); static void scanfunc_ino(struct xfs_btree_block *block, int level, xfs_agf_t *agf); static const cmdinfo_t frag_cmd = { "frag", NULL, frag_f, 0, -1, 0, "[-a] [-d] [-f] [-l] [-q] [-R] [-r] [-v]", "get file fragmentation data", NULL }; static extmap_t * extmap_alloc( xfs_extnum_t nex) { extmap_t *extmap; if (nex < 1) nex = 1; extmap = xmalloc(EXTMAP_SIZE(nex)); extmap->naents = nex; extmap->nents = 0; return extmap; } static xfs_extnum_t extmap_ideal( extmap_t *extmap) { extent_t *ep; xfs_extnum_t rval; for (ep = &extmap->ents[0], rval = 0; ep < &extmap->ents[extmap->nents]; ep++) { if (ep == &extmap->ents[0] || ep->startoff != ep[-1].startoff + ep[-1].blockcount) rval++; } return rval; } static void extmap_set_ext( extmap_t **extmapp, xfs_fileoff_t o, xfs_extlen_t c) { extmap_t *extmap; extent_t *ent; extmap = *extmapp; if (extmap->nents == extmap->naents) { extmap->naents++; extmap = xrealloc(extmap, EXTMAP_SIZE(extmap->naents)); *extmapp = extmap; } ent = &extmap->ents[extmap->nents]; ent->startoff = o; ent->blockcount = c; extmap->nents++; } void frag_init(void) { add_command(&frag_cmd); } /* * Get file fragmentation information. */ static int frag_f( int argc, char **argv) { xfs_agnumber_t agno; double answer; if (!init(argc, argv)) return 0; for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) scan_ag(agno); if (extcount_actual) answer = (double)(extcount_actual - extcount_ideal) * 100.0 / (double)extcount_actual; else answer = 0.0; dbprintf(_("actual %llu, ideal %llu, fragmentation factor %.2f%%\n"), extcount_actual, extcount_ideal, answer); dbprintf(_("Note, this number is largely meaningless.\n")); answer = (double)extcount_actual / (double)extcount_ideal; dbprintf(_("Files on this filesystem average %.2f extents per file\n"), answer); return 0; } static int init( int argc, char **argv) { int c; aflag = dflag = fflag = lflag = qflag = Rflag = rflag = vflag = 0; optind = 0; while ((c = getopt(argc, argv, "adflqRrv")) != EOF) { switch (c) { case 'a': aflag = 1; break; case 'd': dflag = 1; break; case 'f': fflag = 1; break; case 'l': lflag = 1; break; case 'q': qflag = 1; break; case 'R': Rflag = 1; break; case 'r': rflag = 1; break; case 'v': vflag = 1; break; default: dbprintf(_("bad option for frag command\n")); return 0; } } if (!aflag && !dflag && !fflag && !lflag && !qflag && !Rflag && !rflag) aflag = dflag = fflag = lflag = qflag = Rflag = rflag = 1; extcount_actual = extcount_ideal = 0; return 1; } static void process_bmbt_reclist( xfs_bmbt_rec_t *rp, int numrecs, extmap_t **extmapp) { xfs_filblks_t c; int f; int i; xfs_fileoff_t o; xfs_fsblock_t s; for (i = 0; i < numrecs; i++, rp++) { convert_extent(rp, &o, &s, &c, &f); extmap_set_ext(extmapp, (xfs_fileoff_t)o, (xfs_extlen_t)c); } } static void process_btinode( xfs_dinode_t *dip, extmap_t **extmapp, int whichfork) { xfs_bmdr_block_t *dib; int i; xfs_bmbt_ptr_t *pp; dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); if (be16_to_cpu(dib->bb_level) == 0) { xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1); process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), extmapp); return; } pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0)); for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++) scan_lbtree(get_unaligned_be64(&pp[i]), be16_to_cpu(dib->bb_level), scanfunc_bmap, extmapp, whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA); } static void process_exinode( xfs_dinode_t *dip, extmap_t **extmapp, int whichfork) { xfs_bmbt_rec_t *rp; rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork); process_bmbt_reclist(rp, XFS_DFORK_NEXTENTS(dip, whichfork), extmapp); } static void process_fork( xfs_dinode_t *dip, int whichfork) { extmap_t *extmap; int nex; nex = XFS_DFORK_NEXTENTS(dip, whichfork); if (!nex) return; extmap = extmap_alloc(nex); switch (XFS_DFORK_FORMAT(dip, whichfork)) { case XFS_DINODE_FMT_EXTENTS: process_exinode(dip, &extmap, whichfork); break; case XFS_DINODE_FMT_BTREE: process_btinode(dip, &extmap, whichfork); break; } extcount_actual += extmap->nents; extcount_ideal += extmap_ideal(extmap); xfree(extmap); } static void process_inode( xfs_agf_t *agf, xfs_agino_t agino, xfs_dinode_t *dip) { uint64_t actual; uint64_t ideal; xfs_ino_t ino; int skipa; int skipd; ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino); switch (be16_to_cpu(dip->di_mode) & S_IFMT) { case S_IFDIR: skipd = !dflag; break; case S_IFREG: if (!rflag && (be16_to_cpu(dip->di_flags) & XFS_DIFLAG_REALTIME)) skipd = 1; else if (!Rflag && (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino)) skipd = 1; else if (!qflag && (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino || ino == mp->m_sb.sb_pquotino)) skipd = 1; else skipd = !fflag; break; case S_IFLNK: skipd = !lflag; break; default: skipd = 1; break; } actual = extcount_actual; ideal = extcount_ideal; if (!skipd) process_fork(dip, XFS_DATA_FORK); skipa = !aflag || !XFS_DFORK_Q(dip); if (!skipa) process_fork(dip, XFS_ATTR_FORK); if (vflag && (!skipd || !skipa)) dbprintf(_("inode %lld actual %lld ideal %lld\n"), ino, extcount_actual - actual, extcount_ideal - ideal); } static void scan_ag( xfs_agnumber_t agno) { xfs_agf_t *agf; xfs_agi_t *agi; push_cur(); set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if ((agf = iocur_top->data) == NULL) { dbprintf(_("can't read agf block for ag %u\n"), agno); pop_cur(); return; } push_cur(); set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if ((agi = iocur_top->data) == NULL) { dbprintf(_("can't read agi block for ag %u\n"), agno); pop_cur(); pop_cur(); return; } scan_sbtree(agf, be32_to_cpu(agi->agi_root), be32_to_cpu(agi->agi_level), scanfunc_ino, TYP_INOBT); pop_cur(); pop_cur(); } static void scan_lbtree( xfs_fsblock_t root, int nlevels, scan_lbtree_f_t func, extmap_t **extmapp, typnm_t btype) { push_cur(); set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { dbprintf(_("can't read btree block %u/%u\n"), XFS_FSB_TO_AGNO(mp, root), XFS_FSB_TO_AGBNO(mp, root)); return; } (*func)(iocur_top->data, nlevels - 1, extmapp, btype); pop_cur(); } static void scan_sbtree( xfs_agf_t *agf, xfs_agblock_t root, int nlevels, scan_sbtree_f_t func, typnm_t btype) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); push_cur(); set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { dbprintf(_("can't read btree block %u/%u\n"), seqno, root); return; } (*func)(iocur_top->data, nlevels - 1, agf); pop_cur(); } static void scanfunc_bmap( struct xfs_btree_block *block, int level, extmap_t **extmapp, typnm_t btype) { int i; xfs_bmbt_ptr_t *pp; xfs_bmbt_rec_t *rp; int nrecs; nrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (nrecs > mp->m_bmap_dmxr[0]) { dbprintf(_("invalid numrecs (%u) in %s block\n"), nrecs, typtab[btype].name); return; } rp = XFS_BMBT_REC_ADDR(mp, block, 1); process_bmbt_reclist(rp, nrecs, extmapp); return; } if (nrecs > mp->m_bmap_dmxr[1]) { dbprintf(_("invalid numrecs (%u) in %s block\n"), nrecs, typtab[btype].name); return; } pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]); for (i = 0; i < nrecs; i++) scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, extmapp, btype); } static void scanfunc_ino( struct xfs_btree_block *block, int level, xfs_agf_t *agf) { xfs_agino_t agino; xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int i; int j; int off; xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; xfs_agblock_t agbno; xfs_agblock_t end_agbno; struct xfs_dinode *dip; int blks_per_buf; int inodes_per_buf; int ioff; struct xfs_ino_geometry *igeo = M_IGEO(mp); if (xfs_sb_version_hassparseinodes(&mp->m_sb)) blks_per_buf = igeo->blocks_per_cluster; else blks_per_buf = igeo->ialloc_blks; inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf), XFS_INODES_PER_CHUNK); if (level == 0) { rp = XFS_INOBT_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { agino = be32_to_cpu(rp[i].ir_startino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); off = XFS_AGINO_TO_OFFSET(mp, agino); end_agbno = agbno + igeo->ialloc_blks; push_cur(); ioff = 0; while (agbno < end_agbno && ioff < XFS_INODES_PER_CHUNK) { if (xfs_inobt_is_sparse_disk(&rp[i], ioff)) goto next_buf; set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, seqno, agbno), XFS_FSB_TO_BB(mp, blks_per_buf), DB_RING_IGN, NULL); if (iocur_top->data == NULL) { dbprintf(_("can't read inode block %u/%u\n"), seqno, agbno); goto next_buf; } for (j = 0; j < inodes_per_buf; j++) { if (XFS_INOBT_IS_FREE_DISK(&rp[i], ioff + j)) continue; dip = (xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)); process_inode(agf, agino + ioff + j, dip); } next_buf: agbno += blks_per_buf; ioff += inodes_per_buf; } pop_cur(); } return; } pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), level, scanfunc_ino, TYP_INOBT); } xfsprogs-5.3.0/db/frag.h0000644000175000017500000000023013435336036014722 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void frag_init(void); xfsprogs-5.3.0/db/freesp.c0000644000175000017500000002110413435336036015265 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "freesp.h" #include "io.h" #include "type.h" #include "output.h" #include "init.h" #include "malloc.h" typedef struct histent { int low; int high; long long count; long long blocks; } histent_t; static void addhistent(int h); static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len); static int freesp_f(int argc, char **argv); static void histinit(int maxlen); static int init(int argc, char **argv); static void printhist(void); static void scan_ag(xfs_agnumber_t agno); static void scanfunc_bno(struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf); static void scanfunc_cnt(struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf); static void scan_freelist(xfs_agf_t *agf); static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ, int nlevels, void (*func)(struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf)); static int usage(void); static int agcount; static xfs_agnumber_t *aglist; static int alignment; static int countflag; static int dumpflag; static int equalsize; static histent_t *hist; static int histcount; static int multsize; static int seen1; static int summaryflag; static long long totblocks; static long long totexts; static const cmdinfo_t freesp_cmd = { "freesp", NULL, freesp_f, 0, -1, 0, "[-bcdfs] [-A alignment] [-a agno]... [-e binsize] [-h h1]... [-m binmult]", "summarize free space for filesystem", NULL }; static int inaglist( xfs_agnumber_t agno) { int i; if (agcount == 0) return 1; for (i = 0; i < agcount; i++) if (aglist[i] == agno) return 1; return 0; } /* * Report on freespace usage in xfs filesystem. */ static int freesp_f( int argc, char **argv) { xfs_agnumber_t agno; if (!init(argc, argv)) return 0; if (dumpflag) dbprintf("%8s %8s %8s\n", "agno", "agbno", "len"); for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { if (inaglist(agno)) scan_ag(agno); } if (histcount) printhist(); if (summaryflag) { dbprintf(_("total free extents %lld\n"), totexts); dbprintf(_("total free blocks %lld\n"), totblocks); dbprintf(_("average free extent size %g\n"), (double)totblocks / (double)totexts); } if (aglist) xfree(aglist); if (hist) xfree(hist); return 0; } void freesp_init(void) { add_command(&freesp_cmd); } static void aglistadd( char *a) { aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist)); aglist[agcount] = (xfs_agnumber_t)atoi(a); agcount++; } static int init( int argc, char **argv) { int c; int speced = 0; agcount = countflag = dumpflag = equalsize = multsize = optind = 0; histcount = seen1 = summaryflag = 0; totblocks = totexts = 0; aglist = NULL; hist = NULL; while ((c = getopt(argc, argv, "A:a:bcde:h:m:s")) != EOF) { switch (c) { case 'A': alignment = atoi(optarg); break; case 'a': aglistadd(optarg); break; case 'b': if (speced) return usage(); multsize = 2; speced = 1; break; case 'c': countflag = 1; break; case 'd': dumpflag = 1; break; case 'e': if (speced) return usage(); equalsize = atoi(optarg); speced = 1; break; case 'h': if (speced && !histcount) return usage(); addhistent(atoi(optarg)); speced = 1; break; case 'm': if (speced) return usage(); multsize = atoi(optarg); speced = 1; break; case 's': summaryflag = 1; break; case '?': return usage(); } } if (optind != argc) return usage(); if (!speced) multsize = 2; histinit((int)mp->m_sb.sb_agblocks); return 1; } static int usage(void) { dbprintf(_("freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... " "[-m binmult]\n")); return 0; } static void scan_ag( xfs_agnumber_t agno) { xfs_agf_t *agf; push_cur(); set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); agf = iocur_top->data; scan_freelist(agf); if (countflag) scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]), TYP_CNTBT, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]), scanfunc_cnt); else scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), TYP_BNOBT, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]), scanfunc_bno); pop_cur(); } static int scan_agfl( struct xfs_mount *mp, xfs_agblock_t bno, void *priv) { addtohist(*(xfs_agnumber_t *)priv, bno, 1); return 0; } static void scan_freelist( xfs_agf_t *agf) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); if (be32_to_cpu(agf->agf_flcount) == 0) return; push_cur(); set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); /* verify agf values before proceeding */ if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) || be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) { dbprintf(_("agf %d freelist blocks bad, skipping " "freelist scan\n"), seqno); pop_cur(); return; } libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &seqno); pop_cur(); } static void scan_sbtree( xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ, int nlevels, void (*func)(struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf)) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); push_cur(); set_cur(&typtab[typ], XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { dbprintf(_("can't read btree block %u/%u\n"), seqno, root); return; } (*func)(iocur_top->data, typ, nlevels - 1, agf); pop_cur(); } /*ARGSUSED*/ static void scanfunc_bno( struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf) { int i; xfs_alloc_ptr_t *pp; xfs_alloc_rec_t *rp; if (!(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC || be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC)) return; if (level == 0) { rp = XFS_ALLOC_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) addtohist(be32_to_cpu(agf->agf_seqno), be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount)); return; } pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_bno); } static void scanfunc_cnt( struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf) { int i; xfs_alloc_ptr_t *pp; xfs_alloc_rec_t *rp; if (!(be32_to_cpu(block->bb_magic) == XFS_ABTC_MAGIC || be32_to_cpu(block->bb_magic) == XFS_ABTC_CRC_MAGIC)) return; if (level == 0) { rp = XFS_ALLOC_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) addtohist(be32_to_cpu(agf->agf_seqno), be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount)); return; } pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_cnt); } static void addhistent( int h) { hist = xrealloc(hist, (histcount + 1) * sizeof(*hist)); if (h == 0) h = 1; hist[histcount].low = h; hist[histcount].count = hist[histcount].blocks = 0; histcount++; if (h == 1) seen1 = 1; } static void addtohist( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len) { int i; if (alignment && (XFS_AGB_TO_FSB(mp,agno,agbno) % alignment)) return; if (dumpflag) dbprintf("%8d %8d %8d\n", agno, agbno, len); totexts++; totblocks += len; for (i = 0; i < histcount; i++) { if (hist[i].high >= len) { hist[i].count++; hist[i].blocks += len; break; } } } static int hcmp( const void *a, const void *b) { return ((histent_t *)a)->low - ((histent_t *)b)->low; } static void histinit( int maxlen) { int i; if (equalsize) { for (i = 1; i < maxlen; i += equalsize) addhistent(i); } else if (multsize) { for (i = 1; i < maxlen; i *= multsize) addhistent(i); } else { if (!seen1) addhistent(1); qsort(hist, histcount, sizeof(*hist), hcmp); } for (i = 0; i < histcount; i++) { if (i < histcount - 1) hist[i].high = hist[i + 1].low - 1; else hist[i].high = maxlen; } } static void printhist(void) { int i; dbprintf("%7s %7s %7s %7s %6s\n", _("from"), _("to"), _("extents"), _("blocks"), _("pct")); for (i = 0; i < histcount; i++) { if (hist[i].count) dbprintf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low, hist[i].high, hist[i].count, hist[i].blocks, hist[i].blocks * 100.0 / totblocks); } } xfsprogs-5.3.0/db/freesp.h0000644000175000017500000000023213435336036015271 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void freesp_init(void); xfsprogs-5.3.0/db/fsmap.c0000644000175000017500000000660513435336036015120 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs.h" #include "command.h" #include "fsmap.h" #include "output.h" #include "init.h" struct fsmap_info { unsigned long long nr; xfs_agnumber_t agno; }; static int fsmap_fn( struct xfs_btree_cur *cur, struct xfs_rmap_irec *rec, void *priv) { struct fsmap_info *info = priv; dbprintf(_("%llu: %u/%u len %u owner %lld offset %llu bmbt %d attrfork %d extflag %d\n"), info->nr, info->agno, rec->rm_startblock, rec->rm_blockcount, rec->rm_owner, rec->rm_offset, !!(rec->rm_flags & XFS_RMAP_BMBT_BLOCK), !!(rec->rm_flags & XFS_RMAP_ATTR_FORK), !!(rec->rm_flags & XFS_RMAP_UNWRITTEN)); info->nr++; return 0; } static void fsmap( xfs_fsblock_t start_fsb, xfs_fsblock_t end_fsb) { struct fsmap_info info; xfs_agnumber_t start_ag; xfs_agnumber_t end_ag; xfs_agnumber_t agno; xfs_daddr_t eofs; struct xfs_rmap_irec low = {0}; struct xfs_rmap_irec high = {0}; struct xfs_btree_cur *bt_cur; struct xfs_buf *agbp; int error; eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); if (XFS_FSB_TO_DADDR(mp, end_fsb) >= eofs) end_fsb = XFS_DADDR_TO_FSB(mp, eofs - 1); low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb); high.rm_startblock = -1U; high.rm_owner = ULLONG_MAX; high.rm_offset = ULLONG_MAX; high.rm_flags = XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK | XFS_RMAP_UNWRITTEN; start_ag = XFS_FSB_TO_AGNO(mp, start_fsb); end_ag = XFS_FSB_TO_AGNO(mp, end_fsb); info.nr = 0; for (agno = start_ag; agno <= end_ag; agno++) { if (agno == end_ag) high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsb); error = -libxfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); if (error) { dbprintf(_("Error %d while reading AGF.\n"), error); return; } bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, agno); if (!bt_cur) { libxfs_putbuf(agbp); dbprintf(_("Not enough memory.\n")); return; } info.agno = agno; error = -libxfs_rmap_query_range(bt_cur, &low, &high, fsmap_fn, &info); if (error) { libxfs_btree_del_cursor(bt_cur, XFS_BTREE_ERROR); libxfs_putbuf(agbp); dbprintf(_("Error %d while querying fsmap btree.\n"), error); return; } libxfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR); libxfs_putbuf(agbp); if (agno == start_ag) low.rm_startblock = 0; } } static int fsmap_f( int argc, char **argv) { char *p; int c; xfs_fsblock_t start_fsb = 0; xfs_fsblock_t end_fsb = NULLFSBLOCK; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) { dbprintf(_("Filesystem does not support reverse mapping btree.\n")); return 0; } while ((c = getopt(argc, argv, "")) != EOF) { switch (c) { default: dbprintf(_("Bad option for fsmap command.\n")); return 0; } } if (argc > optind) { start_fsb = strtoull(argv[optind], &p, 0); if (*p != '\0' || start_fsb >= mp->m_sb.sb_dblocks) { dbprintf(_("Bad fsmap start_fsb %s.\n"), argv[optind]); return 0; } } if (argc > optind + 1) { end_fsb = strtoull(argv[optind + 1], &p, 0); if (*p != '\0') { dbprintf(_("Bad fsmap end_fsb %s.\n"), argv[optind + 1]); return 0; } } fsmap(start_fsb, end_fsb); return 0; } static const cmdinfo_t fsmap_cmd = { "fsmap", NULL, fsmap_f, 0, 2, 0, N_("[start_fsb] [end_fsb]"), N_("display reverse mapping(s)"), NULL }; void fsmap_init(void) { add_command(&fsmap_cmd); } xfsprogs-5.3.0/db/fsmap.h0000644000175000017500000000026313435336036015117 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ extern void fsmap_init(void); xfsprogs-5.3.0/db/fuzz.c0000644000175000017500000002366113435336036015011 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include #include "bit.h" #include "block.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "flist.h" #include "io.h" #include "init.h" #include "output.h" #include "print.h" #include "write.h" #include "malloc.h" #include "fuzz.h" static int fuzz_f(int argc, char **argv); static void fuzz_help(void); static const cmdinfo_t fuzz_cmd = { "fuzz", NULL, fuzz_f, 0, -1, 0, N_("[-c] [-d] field fuzzcmd..."), N_("fuzz values on disk"), fuzz_help }; void fuzz_init(void) { if (!expert_mode) return; add_command(&fuzz_cmd); srand48(clock()); } static void fuzz_help(void) { dbprintf(_( "\n" " The 'fuzz' command fuzzes fields in any on-disk data structure. For\n" " block fuzzing, see the 'blocktrash' or 'write' commands." "\n" " Examples:\n" " Struct mode: 'fuzz core.uid zeroes' - set an inode uid field to 0.\n" " 'fuzz crc ones' - set a crc filed to all ones.\n" " 'fuzz bno[11] firstbit' - set the high bit of a block array.\n" " 'fuzz keys[5].startblock add' - increase a btree key value.\n" " 'fuzz uuid random' - randomize the superblock uuid.\n" "\n" " Type 'fuzz' by itself for a list of specific commands.\n\n" " Specifying the -c option will allow writes of invalid (corrupt) data with\n" " an invalid CRC. Specifying the -d option will allow writes of invalid data,\n" " but still recalculate the CRC so we are forced to check and detect the\n" " invalid data appropriately.\n\n" )); } static int fuzz_f( int argc, char **argv) { pfunc_t pf; extern char *progname; int c; bool corrupt = false; /* Allow write of bad data w/ invalid CRC */ bool invalid_data = false; /* Allow write of bad data w/ valid CRC */ struct xfs_buf_ops local_ops; const struct xfs_buf_ops *stashed_ops = NULL; if (x.isreadonly & LIBXFS_ISREADONLY) { dbprintf(_("%s started in read only mode, fuzzing disabled\n"), progname); return 0; } if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } pf = cur_typ->pfunc; if (pf == NULL) { dbprintf(_("no handler function for type %s, fuzz unsupported.\n"), cur_typ->name); return 0; } while ((c = getopt(argc, argv, "cd")) != EOF) { switch (c) { case 'c': corrupt = true; break; case 'd': invalid_data = true; break; default: dbprintf(_("bad option for fuzz command\n")); return 0; } } if (corrupt && invalid_data) { dbprintf(_("Cannot specify both -c and -d options\n")); return 0; } if (invalid_data && iocur_top->typ->crc_off == TYP_F_NO_CRC_OFF && xfs_sb_version_hascrc(&mp->m_sb)) { dbprintf(_("Cannot recalculate CRCs on this type of object\n")); return 0; } argc -= optind; argv += optind; /* * If the buffer has no verifier or we are using standard verifier * paths, then just fuzz it and return */ if (!iocur_top->bp->b_ops || !(corrupt || invalid_data)) { (*pf)(DB_FUZZ, cur_typ->fields, argc, argv); return 0; } /* Temporarily remove write verifier to write bad data */ stashed_ops = iocur_top->bp->b_ops; local_ops.verify_read = stashed_ops->verify_read; iocur_top->bp->b_ops = &local_ops; if (!xfs_sb_version_hascrc(&mp->m_sb)) { local_ops.verify_write = xfs_dummy_verify; } else if (corrupt) { local_ops.verify_write = xfs_dummy_verify; dbprintf(_("Allowing fuzz of corrupted data and bad CRC\n")); } else if (iocur_top->typ->crc_off == TYP_F_CRC_FUNC) { local_ops.verify_write = iocur_top->typ->set_crc; dbprintf(_("Allowing fuzz of corrupted data with good CRC\n")); } else { /* invalid data */ local_ops.verify_write = xfs_verify_recalc_crc; dbprintf(_("Allowing fuzz of corrupted data with good CRC\n")); } (*pf)(DB_FUZZ, cur_typ->fields, argc, argv); iocur_top->bp->b_ops = stashed_ops; return 0; } /* Write zeroes to the field */ static bool fuzz_zeroes( void *buf, int bitoff, int nbits) { char *out = buf; int bit; if (bitoff % NBBY || nbits % NBBY) { for (bit = 0; bit < nbits; bit++) setbit_l(out, bit + bitoff, 0); } else memset(out + byteize(bitoff), 0, byteize(nbits)); return true; } /* Write ones to the field */ static bool fuzz_ones( void *buf, int bitoff, int nbits) { char *out = buf; int bit; if (bitoff % NBBY || nbits % NBBY) { for (bit = 0; bit < nbits; bit++) setbit_l(out, bit + bitoff, 1); } else memset(out + byteize(bitoff), 0xFF, byteize(nbits)); return true; } /* Flip the high bit in the (presumably big-endian) field */ static bool fuzz_firstbit( void *buf, int bitoff, int nbits) { setbit_l((char *)buf, bitoff, !getbit_l((char *)buf, bitoff)); return true; } /* Flip the low bit in the (presumably big-endian) field */ static bool fuzz_lastbit( void *buf, int bitoff, int nbits) { setbit_l((char *)buf, bitoff + nbits - 1, !getbit_l((char *)buf, bitoff + nbits - 1)); return true; } /* Flip the middle bit in the (presumably big-endian) field */ static bool fuzz_middlebit( void *buf, int bitoff, int nbits) { setbit_l((char *)buf, bitoff + nbits / 2, !getbit_l((char *)buf, bitoff + nbits / 2)); return true; } /* Format and shift a number into a buffer for setbitval. */ static char * format_number( uint64_t val, __be64 *out, int bit_length) { int offset; char *rbuf = (char *)out; /* * If the length of the field is not a multiple of a byte, push * the bits up in the field, so the most signicant field bit is * the most significant bit in the byte: * * before: * val |----|----|----|----|----|--MM|mmmm|llll| * after * val |----|----|----|----|----|MMmm|mmll|ll00| */ offset = bit_length % NBBY; if (offset) val <<= (NBBY - offset); /* * convert to big endian and copy into the array * rbuf |----|----|----|----|----|MMmm|mmll|ll00| */ *out = cpu_to_be64(val); /* * Align the array to point to the field in the array. * rbuf = |MMmm|mmll|ll00| */ offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64)); return rbuf + offset; } /* Increase the value by some small prime number. */ static bool fuzz_add( void *buf, int bitoff, int nbits) { uint64_t val; __be64 out; char *b; if (nbits > 64) return false; val = getbitval(buf, bitoff, nbits, BVUNSIGNED); val += (nbits > 8 ? 2017 : 137); b = format_number(val, &out, nbits); setbitval(buf, bitoff, nbits, b); return true; } /* Decrease the value by some small prime number. */ static bool fuzz_sub( void *buf, int bitoff, int nbits) { uint64_t val; __be64 out; char *b; if (nbits > 64) return false; val = getbitval(buf, bitoff, nbits, BVUNSIGNED); val -= (nbits > 8 ? 2017 : 137); b = format_number(val, &out, nbits); setbitval(buf, bitoff, nbits, b); return true; } /* Randomize the field. */ static bool fuzz_random( void *buf, int bitoff, int nbits) { int i, bytes; char *b, *rbuf; bytes = byteize_up(nbits); rbuf = b = malloc(bytes); if (!b) { perror("fuzz_random"); return false; } for (i = 0; i < bytes; i++) *b++ = (char)lrand48(); setbitval(buf, bitoff, nbits, rbuf); free(rbuf); return true; } struct fuzzcmd { const char *verb; bool (*fn)(void *buf, int bitoff, int nbits); }; /* Keep these verbs in sync with enum fuzzcmds. */ static struct fuzzcmd fuzzverbs[] = { {"zeroes", fuzz_zeroes}, {"ones", fuzz_ones}, {"firstbit", fuzz_firstbit}, {"middlebit", fuzz_middlebit}, {"lastbit", fuzz_lastbit}, {"add", fuzz_add}, {"sub", fuzz_sub}, {"random", fuzz_random}, {NULL, NULL}, }; /* ARGSUSED */ void fuzz_struct( const field_t *fields, int argc, char **argv) { const ftattr_t *fa; flist_t *fl; flist_t *sfl; int bit_length; struct fuzzcmd *fc; bool success; int parentoffset; if (argc != 2) { dbprintf(_("Usage: fuzz fieldname fuzzcmd\n")); dbprintf("Fuzz commands: %s", fuzzverbs->verb); for (fc = fuzzverbs + 1; fc->verb != NULL; fc++) dbprintf(", %s", fc->verb); dbprintf(".\n"); return; } fl = flist_scan(argv[0]); if (!fl) { dbprintf(_("unable to parse '%s'.\n"), argv[0]); return; } /* Find our fuzz verb */ for (fc = fuzzverbs; fc->verb != NULL; fc++) if (!strcmp(fc->verb, argv[1])) break; if (fc->fn == NULL) { dbprintf(_("Unknown fuzz command '%s'.\n"), argv[1]); goto out_free; } /* if we're a root field type, go down 1 layer to get field list */ if (fields->name[0] == '\0') { fa = &ftattrtab[fields->ftyp]; ASSERT(fa->ftyp == fields->ftyp); fields = fa->subfld; } /* run down the field list and set offsets into the data */ if (!flist_parse(fields, fl, iocur_top->data, 0)) { dbprintf(_("parsing error\n")); goto out_free; } sfl = fl; parentoffset = 0; while (sfl->child) { parentoffset = sfl->offset; sfl = sfl->child; } /* * For structures, fsize * fcount tells us the size of the region we are * modifying, which is usually a single structure member and is pointed * to by the last child in the list. * * However, if the base structure is an array and we have a direct index * into the array (e.g. write bno[5]) then we are returned a single * flist object with the offset pointing directly at the location we * need to modify. The length of the object we are modifying is then * determined by the size of the individual array entry (fsize) and the * indexes defined in the object, not the overall size of the array * (which is what fcount returns). */ bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0); if (sfl->fld->flags & FLD_ARRAY) bit_length *= sfl->high - sfl->low + 1; else bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset); /* Fuzz the value */ success = fc->fn(iocur_top->data, sfl->offset, bit_length); if (!success) { dbprintf(_("unable to fuzz field '%s'\n"), argv[0]); goto out_free; } /* Write the fuzzed value back */ write_cur(); flist_print(fl); print_flist(fl); out_free: flist_free(fl); } xfsprogs-5.3.0/db/fuzz.h0000644000175000017500000000037113435336036015007 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ extern void fuzz_init(void); extern void fuzz_struct(const field_t *fields, int argc, char **argv); xfsprogs-5.3.0/db/hash.c0000644000175000017500000000163713435336036014735 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "addr.h" #include "command.h" #include "type.h" #include "io.h" #include "output.h" #include "hash.h" static int hash_f(int argc, char **argv); static void hash_help(void); static const cmdinfo_t hash_cmd = { "hash", NULL, hash_f, 1, 1, 0, N_("string"), N_("calculate hash value"), hash_help }; static void hash_help(void) { dbprintf(_( "\n" " 'hash' prints out the calculated hash value for a string using the\n" "directory/attribute code hash function.\n" "\n" " Usage: \"hash \"\n" "\n" )); } /* ARGSUSED */ static int hash_f( int argc, char **argv) { xfs_dahash_t hashval; hashval = libxfs_da_hashname((unsigned char *)argv[1], (int)strlen(argv[1])); dbprintf("0x%x\n", hashval); return 0; } void hash_init(void) { add_command(&hash_cmd); } xfsprogs-5.3.0/db/hash.h0000644000175000017500000000022413435336036014731 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002 Silicon Graphics, Inc. * All Rights Reserved. */ extern void hash_init(void); xfsprogs-5.3.0/db/help.c0000644000175000017500000000266013435336036014737 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "help.h" #include "output.h" static void help_all(void); static void help_onecmd(const char *cmd, const cmdinfo_t *ct); static int help_f(int argc, char **argv); static void help_oneline(const char *cmd, const cmdinfo_t *ct); static const cmdinfo_t help_cmd = { "help", "?", help_f, 0, 1, 0, N_("[command]"), N_("help for one or all commands"), NULL }; static void help_all(void) { const cmdinfo_t *ct; for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) help_oneline(ct->name, ct); dbprintf(_("\nUse 'help commandname' for extended help.\n")); } static int help_f( int argc, char **argv) { const cmdinfo_t *ct; if (argc == 1) { help_all(); return 0; } ct = find_command(argv[1]); if (ct == NULL) { dbprintf(_("command %s not found\n"), argv[1]); return 0; } help_onecmd(argv[1], ct); return 0; } void help_init(void) { add_command(&help_cmd); } static void help_onecmd( const char *cmd, const cmdinfo_t *ct) { help_oneline(cmd, ct); if (ct->help) ct->help(); } static void help_oneline( const char *cmd, const cmdinfo_t *ct) { if (cmd) dbprintf("%s ", cmd); else { dbprintf("%s ", ct->name); if (ct->altname) dbprintf(_("(or %s) "), ct->altname); } if (ct->args) dbprintf("%s ", ct->args); dbprintf("-- %s\n", ct->oneline); } xfsprogs-5.3.0/db/help.h0000644000175000017500000000023013435336036014733 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void help_init(void); xfsprogs-5.3.0/db/info.c0000644000175000017500000000170213570057155014740 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs.h" #include "command.h" #include "init.h" #include "output.h" #include "libfrog/fsgeom.h" static void info_help(void) { dbprintf(_( "\n" " Pretty-prints the filesystem geometry as derived from the superblock.\n" " The output has the same format as mkfs.xfs, xfs_info, and other utilities.\n" "\n" )); } static int info_f( int argc, char **argv) { struct xfs_fsop_geom geo; libxfs_fs_geometry(&mp->m_sb, &geo, XFS_FS_GEOM_MAX_STRUCT_VER); xfs_report_geom(&geo, fsdevice, x.logname, x.rtname); return 0; } static const struct cmdinfo info_cmd = { .name = "info", .altname = "i", .cfunc = info_f, .argmin = 0, .argmax = 0, .canpush = 0, .args = NULL, .oneline = N_("pretty-print superblock info"), .help = info_help, }; void info_init(void) { add_command(&info_cmd); } xfsprogs-5.3.0/db/init.c0000644000175000017500000001132313435336036014746 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include #include "command.h" #include "init.h" #include "input.h" #include "io.h" #include "init.h" #include "sig.h" #include "output.h" #include "malloc.h" #include "type.h" static char **cmdline; static int ncmdline; char *fsdevice; int blkbb; int exitcode; int expert_mode; static int force; static struct xfs_mount xmount; struct xfs_mount *mp; static struct xlog xlog; libxfs_init_t x; xfs_agnumber_t cur_agno = NULLAGNUMBER; static void usage(void) { fprintf(stderr, _( "Usage: %s [-ifFrxV] [-p prog] [-l logdev] [-c cmd]... device\n" ), progname); exit(1); } static void init( int argc, char **argv) { struct xfs_sb *sbp; struct xfs_buf *bp; unsigned int agcount; int c; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); progname = basename(argv[0]); while ((c = getopt(argc, argv, "c:fFip:rxVl:")) != EOF) { switch (c) { case 'c': cmdline = xrealloc(cmdline, (ncmdline+1)*sizeof(char*)); cmdline[ncmdline++] = optarg; break; case 'f': x.disfile = 1; break; case 'F': force = 1; break; case 'i': x.isreadonly = (LIBXFS_ISREADONLY|LIBXFS_ISINACTIVE); break; case 'p': progname = optarg; break; case 'r': x.isreadonly = LIBXFS_ISREADONLY; break; case 'l': x.logname = optarg; break; case 'x': expert_mode = 1; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); case '?': usage(); /*NOTREACHED*/ } } if (optind + 1 != argc) { usage(); /*NOTREACHED*/ } fsdevice = argv[optind]; if (!x.disfile) x.volname = fsdevice; else x.dname = fsdevice; x.bcache_flags = CACHE_MISCOMPARE_PURGE; if (!libxfs_init(&x)) { fputs(_("\nfatal error -- couldn't initialize XFS library\n"), stderr); exit(1); } /* * Read the superblock, but don't validate it - we are a diagnostic * tool and so need to be able to mount busted filesystems. */ memset(&xmount, 0, sizeof(struct xfs_mount)); libxfs_buftarg_init(&xmount, x.ddev, x.logdev, x.rtdev); bp = libxfs_readbuf(xmount.m_ddev_targp, XFS_SB_DADDR, 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL); if (!bp || bp->b_error) { fprintf(stderr, _("%s: %s is invalid (cannot read first 512 " "bytes)\n"), progname, fsdevice); exit(1); } /* copy SB from buffer to in-core, converting architecture as we go */ libxfs_sb_from_disk(&xmount.m_sb, XFS_BUF_TO_SBP(bp)); libxfs_putbuf(bp); libxfs_purgebuf(bp); sbp = &xmount.m_sb; if (sbp->sb_magicnum != XFS_SB_MAGIC) { fprintf(stderr, _("%s: %s is not a valid XFS filesystem (unexpected SB magic number 0x%08x)\n"), progname, fsdevice, sbp->sb_magicnum); if (!force) { fprintf(stderr, _("Use -F to force a read attempt.\n")); exit(EXIT_FAILURE); } } agcount = sbp->sb_agcount; mp = libxfs_mount(&xmount, sbp, x.ddev, x.logdev, x.rtdev, LIBXFS_MOUNT_DEBUGGER); if (!mp) { fprintf(stderr, _("%s: device %s unusable (not an XFS filesystem?)\n"), progname, fsdevice); exit(1); } mp->m_log = &xlog; blkbb = 1 << mp->m_blkbb_log; /* Did we limit a broken agcount in libxfs_mount? */ if (sbp->sb_agcount != agcount) exitcode = 1; /* * xfs_check needs corrected incore superblock values */ if (sbp->sb_rootino != NULLFSINO && xfs_sb_version_haslazysbcount(&mp->m_sb)) { int error = -libxfs_initialize_perag_data(mp, sbp->sb_agcount); if (error) { fprintf(stderr, _("%s: cannot init perag data (%d). Continuing anyway.\n"), progname, error); } } if (xfs_sb_version_hassparseinodes(&mp->m_sb)) type_set_tab_spcrc(); else if (xfs_sb_version_hascrc(&mp->m_sb)) type_set_tab_crc(); push_cur(); init_commands(); init_sig(); } int main( int argc, char **argv) { int c, i, done = 0; char *input; char **v; int start_iocur_sp; init(argc, argv); start_iocur_sp = iocur_sp; for (i = 0; !done && i < ncmdline; i++) { v = breakline(cmdline[i], &c); if (c) done = command(c, v); xfree(v); } if (cmdline) { xfree(cmdline); goto close_devices; } pushfile(stdin); while (!done) { if ((input = fetchline()) == NULL) break; v = breakline(input, &c); if (c) done = command(c, v); doneline(input, v); } close_devices: /* * Make sure that we pop the all the buffer contexts we hold so that * they are released before we purge the caches during unmount. */ while (iocur_sp > start_iocur_sp) pop_cur(); libxfs_umount(mp); if (x.ddev) libxfs_device_close(x.ddev); if (x.logdev && x.logdev != x.ddev) libxfs_device_close(x.logdev); if (x.rtdev) libxfs_device_close(x.rtdev); libxfs_destroy(); return exitcode; } xfsprogs-5.3.0/db/init.h0000644000175000017500000000044513435336036014756 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern char *fsdevice; extern int blkbb; extern int exitcode; extern int expert_mode; extern xfs_mount_t *mp; extern libxfs_init_t x; extern xfs_agnumber_t cur_agno; xfsprogs-5.3.0/db/inode.c0000644000175000017500000004521013570057155015105 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "inode.h" #include "io.h" #include "print.h" #include "block.h" #include "bit.h" #include "output.h" #include "init.h" static int inode_a_bmbt_count(void *obj, int startoff); static int inode_a_bmx_count(void *obj, int startoff); static int inode_a_count(void *obj, int startoff); static int inode_a_offset(void *obj, int startoff, int idx); static int inode_a_sfattr_count(void *obj, int startoff); static int inode_core_nlinkv2_count(void *obj, int startoff); static int inode_core_onlink_count(void *obj, int startoff); static int inode_core_projid_count(void *obj, int startoff); static int inode_core_nlinkv1_count(void *obj, int startoff); static int inode_f(int argc, char **argv); static int inode_u_offset(void *obj, int startoff, int idx); static int inode_u_bmbt_count(void *obj, int startoff); static int inode_u_bmx_count(void *obj, int startoff); static int inode_u_c_count(void *obj, int startoff); static int inode_u_dev_count(void *obj, int startoff); static int inode_u_muuid_count(void *obj, int startoff); static int inode_u_sfdir2_count(void *obj, int startoff); static int inode_u_sfdir3_count(void *obj, int startoff); static int inode_u_symlink_count(void *obj, int startoff); static const cmdinfo_t inode_cmd = { "inode", NULL, inode_f, 0, 1, 1, "[inode#]", "set current inode", NULL }; const field_t inode_hfld[] = { { "", FLDT_INODE, OI(0), C1, 0, TYP_NONE }, { NULL } }; const field_t inode_crc_hfld[] = { { "", FLDT_INODE_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; /* XXX: fix this up! */ #define OFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f)) const field_t inode_flds[] = { { "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE }, { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0, TYP_INODE }, { "u", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE }, { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; const field_t inode_crc_flds[] = { { "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE }, { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0, TYP_INODE }, { "v3", FLDT_DINODE_V3, OI(OFF(magic)), C1, 0, TYP_NONE }, { "u3", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE }, { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; #define COFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f)) const field_t inode_core_flds[] = { { "magic", FLDT_UINT16X, OI(COFF(magic)), C1, 0, TYP_NONE }, { "mode", FLDT_UINT16O, OI(COFF(mode)), C1, 0, TYP_NONE }, { "version", FLDT_INT8D, OI(COFF(version)), C1, 0, TYP_NONE }, { "format", FLDT_DINODE_FMT, OI(COFF(format)), C1, 0, TYP_NONE }, { "nlinkv1", FLDT_UINT16D, OI(COFF(onlink)), inode_core_nlinkv1_count, FLD_COUNT, TYP_NONE }, { "nlinkv2", FLDT_UINT32D, OI(COFF(nlink)), inode_core_nlinkv2_count, FLD_COUNT, TYP_NONE }, { "onlink", FLDT_UINT16D, OI(COFF(onlink)), inode_core_onlink_count, FLD_COUNT, TYP_NONE }, { "projid_lo", FLDT_UINT16D, OI(COFF(projid_lo)), inode_core_projid_count, FLD_COUNT, TYP_NONE }, { "projid_hi", FLDT_UINT16D, OI(COFF(projid_hi)), inode_core_projid_count, FLD_COUNT, TYP_NONE }, { "pad", FLDT_UINT8X, OI(OFF(pad)), CI(6), FLD_ARRAY|FLD_SKIPALL, TYP_NONE }, { "uid", FLDT_UINT32D, OI(COFF(uid)), C1, 0, TYP_NONE }, { "gid", FLDT_UINT32D, OI(COFF(gid)), C1, 0, TYP_NONE }, { "flushiter", FLDT_UINT16D, OI(COFF(flushiter)), C1, 0, TYP_NONE }, { "atime", FLDT_TIMESTAMP, OI(COFF(atime)), C1, 0, TYP_NONE }, { "mtime", FLDT_TIMESTAMP, OI(COFF(mtime)), C1, 0, TYP_NONE }, { "ctime", FLDT_TIMESTAMP, OI(COFF(ctime)), C1, 0, TYP_NONE }, { "size", FLDT_FSIZE, OI(COFF(size)), C1, 0, TYP_NONE }, { "nblocks", FLDT_DRFSBNO, OI(COFF(nblocks)), C1, 0, TYP_NONE }, { "extsize", FLDT_EXTLEN, OI(COFF(extsize)), C1, 0, TYP_NONE }, { "nextents", FLDT_EXTNUM, OI(COFF(nextents)), C1, 0, TYP_NONE }, { "naextents", FLDT_AEXTNUM, OI(COFF(anextents)), C1, 0, TYP_NONE }, { "forkoff", FLDT_UINT8D, OI(COFF(forkoff)), C1, 0, TYP_NONE }, { "aformat", FLDT_DINODE_FMT, OI(COFF(aformat)), C1, 0, TYP_NONE }, { "dmevmask", FLDT_UINT32X, OI(COFF(dmevmask)), C1, 0, TYP_NONE }, { "dmstate", FLDT_UINT16D, OI(COFF(dmstate)), C1, 0, TYP_NONE }, { "flags", FLDT_UINT16X, OI(COFF(flags)), C1, FLD_SKIPALL, TYP_NONE }, { "newrtbm", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NEWRTBM_BIT - 1), C1, 0, TYP_NONE }, { "prealloc", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PREALLOC_BIT - 1), C1, 0, TYP_NONE }, { "realtime", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_REALTIME_BIT - 1), C1, 0, TYP_NONE }, { "immutable", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_IMMUTABLE_BIT-1), C1, 0, TYP_NONE }, { "append", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_APPEND_BIT - 1), C1, 0, TYP_NONE }, { "sync", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_SYNC_BIT - 1), C1, 0, TYP_NONE }, { "noatime", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOATIME_BIT - 1), C1, 0, TYP_NONE }, { "nodump", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODUMP_BIT - 1), C1, 0, TYP_NONE }, { "rtinherit", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_RTINHERIT_BIT-1), C1, 0, TYP_NONE }, { "projinherit", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PROJINHERIT_BIT-1), C1, 0, TYP_NONE }, { "nosymlinks", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOSYMLINKS_BIT-1), C1, 0, TYP_NONE }, { "extsz", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSIZE_BIT-1), C1, 0, TYP_NONE }, { "extszinherit", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSZINHERIT_BIT-1), C1, 0, TYP_NONE }, { "nodefrag", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODEFRAG_BIT-1), C1, 0, TYP_NONE }, { "filestream", FLDT_UINT1, OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_FILESTREAM_BIT-1), C1, 0, TYP_NONE }, { "gen", FLDT_UINT32D, OI(COFF(gen)), C1, 0, TYP_NONE }, { NULL } }; const field_t inode_v3_flds[] = { { "crc", FLDT_CRC, OI(COFF(crc)), C1, 0, TYP_NONE }, { "change_count", FLDT_UINT64D, OI(COFF(changecount)), C1, 0, TYP_NONE }, { "lsn", FLDT_UINT64X, OI(COFF(lsn)), C1, 0, TYP_NONE }, { "flags2", FLDT_UINT64X, OI(COFF(flags2)), C1, 0, TYP_NONE }, { "cowextsize", FLDT_EXTLEN, OI(COFF(cowextsize)), C1, 0, TYP_NONE }, { "pad2", FLDT_UINT8X, OI(OFF(pad2)), CI(12), FLD_ARRAY|FLD_SKIPALL, TYP_NONE }, { "crtime", FLDT_TIMESTAMP, OI(COFF(crtime)), C1, 0, TYP_NONE }, { "inumber", FLDT_INO, OI(COFF(ino)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(COFF(uuid)), C1, 0, TYP_NONE }, { "reflink", FLDT_UINT1, OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_REFLINK_BIT-1), C1, 0, TYP_NONE }, { "cowextsz", FLDT_UINT1, OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_COWEXTSIZE_BIT-1), C1, 0, TYP_NONE }, { NULL } }; #define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f)) const field_t timestamp_flds[] = { { "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE }, { "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE }, { NULL } }; const field_t inode_u_flds[] = { { "bmbt", FLDT_BMROOTD, NULL, inode_u_bmbt_count, FLD_COUNT, TYP_NONE }, { "bmx", FLDT_BMAPBTDREC, NULL, inode_u_bmx_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "c", FLDT_CHARNS, NULL, inode_u_c_count, FLD_COUNT, TYP_NONE }, { "dev", FLDT_DEV, NULL, inode_u_dev_count, FLD_COUNT, TYP_NONE }, { "muuid", FLDT_UUID, NULL, inode_u_muuid_count, FLD_COUNT, TYP_NONE }, { "sfdir2", FLDT_DIR2SF, NULL, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE }, { "sfdir3", FLDT_DIR3SF, NULL, inode_u_sfdir3_count, FLD_COUNT, TYP_NONE }, { "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT, TYP_NONE }, { NULL } }; const field_t inode_a_flds[] = { { "bmbt", FLDT_BMROOTA, NULL, inode_a_bmbt_count, FLD_COUNT, TYP_NONE }, { "bmx", FLDT_BMAPBTAREC, NULL, inode_a_bmx_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "sfattr", FLDT_ATTRSHORT, NULL, inode_a_sfattr_count, FLD_COUNT, TYP_NONE }, { NULL } }; static const char *dinode_fmt_name[] = { "dev", "local", "extents", "btree", "uuid" }; static const int dinode_fmt_name_size = sizeof(dinode_fmt_name) / sizeof(dinode_fmt_name[0]); /*ARGSUSED*/ int fp_dinode_fmt( void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array) { int bitpos; xfs_dinode_fmt_t f; int i; for (i = 0, bitpos = bit; i < count; i++, bitpos += size) { f = (xfs_dinode_fmt_t)getbitval(obj, bitpos, size, BVUNSIGNED); if (array) dbprintf("%d:", i + base); if (f < 0 || f >= dinode_fmt_name_size) dbprintf("%d", (int)f); else dbprintf("%d (%s)", (int)f, dinode_fmt_name[(int)f]); if (i < count - 1) dbprintf(" "); } return 1; } static int inode_a_bmbt_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; if (!XFS_DFORK_Q(dip)) return 0; ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff)); return dip->di_aformat == XFS_DINODE_FMT_BTREE; } static int inode_a_bmx_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; if (!XFS_DFORK_Q(dip)) return 0; ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff)); return dip->di_aformat == XFS_DINODE_FMT_EXTENTS ? be16_to_cpu(dip->di_anextents) : 0; } static int inode_a_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(startoff == 0); dip = obj; return XFS_DFORK_Q(dip); } static int inode_a_offset( void *obj, int startoff, int idx) { xfs_dinode_t *dip; ASSERT(startoff == 0); ASSERT(idx == 0); dip = obj; ASSERT(XFS_DFORK_Q(dip)); return bitize((int)((char *)XFS_DFORK_APTR(dip) - (char *)dip)); } static int inode_a_sfattr_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; if (!XFS_DFORK_Q(dip)) return 0; ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff)); return dip->di_aformat == XFS_DINODE_FMT_LOCAL; } int inode_a_size( void *obj, int startoff, int idx) { xfs_attr_shortform_t *asf; xfs_dinode_t *dip; ASSERT(startoff == 0); ASSERT(idx == 0); dip = obj; switch (dip->di_aformat) { case XFS_DINODE_FMT_LOCAL: asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); return bitize(be16_to_cpu(asf->hdr.totsize)); case XFS_DINODE_FMT_EXTENTS: return (int)be16_to_cpu(dip->di_anextents) * bitsz(xfs_bmbt_rec_t); case XFS_DINODE_FMT_BTREE: return bitize((int)XFS_DFORK_ASIZE(dip, mp)); default: return 0; } } static int inode_core_nlinkv1_count( void *obj, int startoff) { xfs_dinode_t *dic; ASSERT(startoff == 0); ASSERT(obj == iocur_top->data); dic = obj; return dic->di_version == 1; } static int inode_core_nlinkv2_count( void *obj, int startoff) { xfs_dinode_t *dic; ASSERT(startoff == 0); ASSERT(obj == iocur_top->data); dic = obj; return dic->di_version >= 2; } static int inode_core_onlink_count( void *obj, int startoff) { xfs_dinode_t *dic; ASSERT(startoff == 0); ASSERT(obj == iocur_top->data); dic = obj; return dic->di_version >= 2; } static int inode_core_projid_count( void *obj, int startoff) { xfs_dinode_t *dic; ASSERT(startoff == 0); ASSERT(obj == iocur_top->data); dic = obj; return dic->di_version >= 2; } static int inode_f( int argc, char **argv) { xfs_ino_t ino; char *p; if (argc > 1) { ino = strtoull(argv[1], &p, 0); if (*p != '\0') { dbprintf(_("bad value for inode number %s\n"), argv[1]); return 0; } set_cur_inode(ino); } else if (iocur_top->ino == NULLFSINO) dbprintf(_("no current inode\n")); else dbprintf(_("current inode number is %lld\n"), iocur_top->ino); return 0; } void inode_init(void) { add_command(&inode_cmd); } typnm_t inode_next_type(void) { switch (iocur_top->mode & S_IFMT) { case S_IFDIR: return TYP_DIR2; case S_IFLNK: return TYP_SYMLINK; case S_IFREG: if (iocur_top->ino == mp->m_sb.sb_rbmino) return TYP_RTBITMAP; else if (iocur_top->ino == mp->m_sb.sb_rsumino) return TYP_RTSUMMARY; else if (iocur_top->ino == mp->m_sb.sb_uquotino || iocur_top->ino == mp->m_sb.sb_gquotino || iocur_top->ino == mp->m_sb.sb_pquotino) return TYP_DQBLK; else return TYP_DATA; default: return TYP_NONE; } } int inode_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_inodesize); } static int inode_u_offset( void *obj, int startoff, int idx) { xfs_dinode_t *dip; ASSERT(startoff == 0); ASSERT(idx == 0); dip = obj; return bitize((int)((char *)XFS_DFORK_DPTR(dip) - (char *)dip)); } static int inode_u_bmbt_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_BTREE; } static int inode_u_bmx_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_EXTENTS ? be32_to_cpu(dip->di_nextents) : 0; } static int inode_u_c_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_LOCAL && (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG ? (int)be64_to_cpu(dip->di_size) : 0; } static int inode_u_dev_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_DEV; } static int inode_u_muuid_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_UUID; } static int inode_u_sfdir2_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_LOCAL && (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR && !xfs_sb_version_hasftype(&mp->m_sb); } static int inode_u_sfdir3_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_LOCAL && (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR && xfs_sb_version_hasftype(&mp->m_sb); } int inode_u_size( void *obj, int startoff, int idx) { xfs_dinode_t *dip; ASSERT(startoff == 0); ASSERT(idx == 0); dip = obj; switch (dip->di_format) { case XFS_DINODE_FMT_DEV: return bitsz(xfs_dev_t); case XFS_DINODE_FMT_LOCAL: return bitize((int)be64_to_cpu(dip->di_size)); case XFS_DINODE_FMT_EXTENTS: return (int)be32_to_cpu(dip->di_nextents) * bitsz(xfs_bmbt_rec_t); case XFS_DINODE_FMT_BTREE: return bitize((int)XFS_DFORK_DSIZE(dip, mp)); case XFS_DINODE_FMT_UUID: return bitsz(uuid_t); default: return 0; } } static int inode_u_symlink_count( void *obj, int startoff) { xfs_dinode_t *dip; ASSERT(bitoffs(startoff) == 0); ASSERT(obj == iocur_top->data); dip = obj; ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); return dip->di_format == XFS_DINODE_FMT_LOCAL && (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFLNK ? (int)be64_to_cpu(dip->di_size) : 0; } /* * We are now using libxfs for our IO backend, so we should always try to use * inode cluster buffers rather than filesystem block sized buffers for reading * inodes. This means that we always use the same buffers as libxfs operations * does, and that avoids buffer cache issues caused by overlapping buffers. This * can be seen clearly when trying to read the root inode. Much of this logic is * similar to libxfs_imap(). */ void set_cur_inode( xfs_ino_t ino) { xfs_agblock_t agbno; xfs_agino_t agino; xfs_agnumber_t agno; xfs_dinode_t *dip; int offset; int numblks = blkbb; xfs_agblock_t cluster_agbno; struct xfs_ino_geometry *igeo = M_IGEO(mp); agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); offset = XFS_AGINO_TO_OFFSET(mp, agino); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || offset >= mp->m_sb.sb_inopblock || XFS_AGINO_TO_INO(mp, agno, agino) != ino) { dbprintf(_("bad inode number %lld\n"), ino); return; } cur_agno = agno; if (igeo->inode_cluster_size > mp->m_sb.sb_blocksize && igeo->inoalign_mask) { xfs_agblock_t chunk_agbno; xfs_agblock_t offset_agbno; offset_agbno = agbno & igeo->inoalign_mask; chunk_agbno = agbno - offset_agbno; cluster_agbno = chunk_agbno + ((offset_agbno / M_IGEO(mp)->blocks_per_cluster) * M_IGEO(mp)->blocks_per_cluster); offset += ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock); numblks = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster); } else cluster_agbno = agbno; /* * First set_cur to the block with the inode * then use off_cur to get the right part of the buffer. */ ASSERT(typtab[TYP_INODE].typnm == TYP_INODE); /* ingore ring update here, do it explicitly below */ set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, cluster_agbno), numblks, DB_RING_IGN, NULL); off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize); if (!iocur_top->data) return; dip = iocur_top->data; iocur_top->ino_buf = 1; iocur_top->ino = ino; iocur_top->mode = be16_to_cpu(dip->di_mode); if ((iocur_top->mode & S_IFMT) == S_IFDIR) iocur_top->dirino = ino; if (xfs_sb_version_hascrc(&mp->m_sb)) { iocur_top->ino_crc_ok = libxfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF); if (!iocur_top->ino_crc_ok) dbprintf( _("Metadata CRC error detected for ino %lld\n"), ino); } /* track updated info in ring */ ring_add(); } void xfs_inode_set_crc( struct xfs_buf *bp) { ASSERT(iocur_top->ino_buf); ASSERT(iocur_top->bp == bp); libxfs_dinode_calc_crc(mp, iocur_top->data); iocur_top->ino_crc_ok = 1; } xfsprogs-5.3.0/db/inode.h0000644000175000017500000000167513435336036015117 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field inode_a_flds[]; extern const struct field inode_core_flds[]; extern const struct field inode_v3_flds[]; extern const struct field inode_flds[]; extern const struct field inode_crc_flds[]; extern const struct field inode_hfld[]; extern const struct field inode_crc_hfld[]; extern const struct field inode_u_flds[]; extern const struct field timestamp_flds[]; extern int fp_dinode_fmt(void *obj, int bit, int count, char *fmtstr, int size, int arg, int base, int array); extern int inode_a_size(void *obj, int startoff, int idx); extern void inode_init(void); extern typnm_t inode_next_type(void); extern int inode_size(void *obj, int startoff, int idx); extern int inode_u_size(void *obj, int startoff, int idx); extern void xfs_inode_set_crc(struct xfs_buf *); extern void set_cur_inode(xfs_ino_t ino); xfsprogs-5.3.0/db/input.c0000644000175000017500000001335113435336036015145 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "command.h" #include "input.h" #include "output.h" #include "sig.h" #include "malloc.h" #include "init.h" #if defined(ENABLE_READLINE) # include # include #elif defined(ENABLE_EDITLINE) # include #endif static int inputstacksize; static FILE **inputstack; static FILE *curinput; static void popfile(void); static int source_f(int argc, char **argv); static const cmdinfo_t source_cmd = { "source", NULL, source_f, 1, 1, 0, N_("source-file"), N_("get commands from source-file"), NULL }; /* our homegrown strtok that understands strings */ static char * tokenize( char *inp) { static char *last_place = NULL; char *start; char *walk; int in_string = 0; int in_escape = 0; if (inp) { start = inp; } else { if (last_place == NULL) return NULL; /* we're done */ if (*last_place != '\0') return NULL; start = last_place + 1; } last_place = NULL; /* eat whitespace */ while (*start == ' ' || *start == '\t') start++; walk = start; for (;*walk != '\0'; walk++) { if (in_escape) { in_escape = 0; continue; } if (*walk == '\\') in_escape = 1; else if (*walk == '\"') in_string ^= 1; if (!in_string && !in_escape && (*walk == ' ' || *walk == '\t')) { last_place = walk; *last_place = '\0'; break; } } if (walk == start) return NULL; return start; } char ** breakline( char *input, int *count) { int c; char *inp; char *p; char **rval; c = 0; inp = input; rval = xcalloc(sizeof(char *), 1); for (;;) { p = tokenize(inp); if (p == NULL) break; inp = NULL; c++; rval = xrealloc(rval, sizeof(*rval) * (c + 1)); rval[c - 1] = p; rval[c] = NULL; } *count = c; return rval; } void doneline( char *input, char **vec) { xfree(input); xfree(vec); } static char * get_prompt(void) { static char prompt[FILENAME_MAX + 1]; if (!prompt[0]) snprintf(prompt, sizeof(prompt), "%s> ", progname); return prompt; } static char * fetchline_internal(void) { char buf[1024]; int iscont; size_t len; size_t rlen; char *rval; rval = NULL; for (rlen = iscont = 0; ; ) { if (curinput == stdin) { if (iscont) dbprintf("... "); else dbprintf(get_prompt(), progname); fflush(stdin); } if (seenint() || (!fgets(buf, sizeof(buf), curinput) && ferror(curinput) && seenint())) { clearint(); dbprintf("^C\n"); clearerr(curinput); if (iscont) { iscont = 0; rlen = 0; if (rval) { xfree(rval); rval = NULL; } } continue; } if (ferror(curinput) || feof(curinput) || (len = strlen(buf)) == 0) { /* * No more input at this inputstack level; pop * our fd off and return so that a lower * level fetchline can handle us. If this was * an interactive session, print a newline * because ^D doesn't emit one. */ if (curinput == stdin) dbprintf("\n"); popfile(); iscont = 0; rlen = 0; if (rval) { xfree(rval); rval = NULL; } return NULL; } if (inputstacksize == 1) logprintf("%s", buf); rval = xrealloc(rval, rlen + len + 1); if (rlen == 0) rval[0] = '\0'; rlen += len; strcat(rval, buf); if (buf[len - 1] == '\n') { if (len > 1 && buf[len - 2] == '\\') { rval[rlen - 2] = ' '; rval[rlen - 1] = '\0'; rlen--; iscont = 1; } else { rval[rlen - 1] = '\0'; rlen--; break; } } } return rval; } #ifdef ENABLE_READLINE char * fetchline(void) { char *line; if (inputstacksize == 1) { line = readline(get_prompt()); if (!line) dbprintf("\n"); else if (line && *line) { add_history(line); logprintf("%s", line); } } else { line = fetchline_internal(); } return line; } #elif defined(ENABLE_EDITLINE) static char *el_get_prompt(EditLine *e) { return get_prompt(); } char * fetchline(void) { static EditLine *el; static History *hist; HistEvent hevent; char *line; int count; if (!el) { hist = history_init(); history(hist, &hevent, H_SETSIZE, 100); el = el_init(progname, stdin, stdout, stderr); el_source(el, NULL); el_set(el, EL_SIGNAL, 1); el_set(el, EL_PROMPT, el_get_prompt); el_set(el, EL_HIST, history, (const char *)hist); } if (inputstacksize == 1) { line = xstrdup(el_gets(el, &count)); if (line) { if (count > 0) line[count-1] = '\0'; if (*line) { history(hist, &hevent, H_ENTER, line); logprintf("%s", line); } } } else { line = fetchline_internal(); } return line; } #else char * fetchline(void) { return fetchline_internal(); } #endif static void popfile(void) { if (inputstacksize == 0) { curinput = NULL; return; } if (curinput != stdin) fclose(curinput); inputstacksize--; if (inputstacksize) { inputstack = xrealloc(inputstack, inputstacksize * sizeof(*inputstack)); curinput = inputstack[inputstacksize - 1]; } else { free(inputstack); curinput = NULL; inputstack = NULL; } } void pushfile( FILE *file) { inputstack = xrealloc(inputstack, (inputstacksize + 1) * sizeof(*inputstack)); inputstacksize++; curinput = inputstack[inputstacksize - 1] = file; } /* ARGSUSED */ static int source_f( int argc, char **argv) { FILE *f; int c, done = 0; char *input; char **v; f = fopen(argv[1], "r"); if (f == NULL) { dbprintf(_("can't open %s\n"), argv[0]); return 0; } /* Run the sourced commands now. */ pushfile(f); while (!done) { if ((input = fetchline_internal()) == NULL) break; v = breakline(input, &c); if (c) done = command(c, v); doneline(input, v); } return 0; } void input_init(void) { add_command(&source_cmd); } xfsprogs-5.3.0/db/input.h0000644000175000017500000000047213435336036015152 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern char **breakline(char *input, int *count); extern void doneline(char *input, char **vec); extern char *fetchline(void); extern void input_init(void); extern void pushfile(FILE *file); xfsprogs-5.3.0/db/io.c0000644000175000017500000003435013466663244014427 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "dquot.h" #include "inode.h" #include "io.h" #include "output.h" #include "init.h" #include "malloc.h" #include "crc.h" #include "bit.h" static int pop_f(int argc, char **argv); static void pop_help(void); static int push_f(int argc, char **argv); static void push_help(void); static int stack_f(int argc, char **argv); static void stack_help(void); static int forward_f(int argc, char **argv); static void forward_help(void); static int back_f(int argc, char **argv); static void back_help(void); static int ring_f(int argc, char **argv); static void ring_help(void); static const cmdinfo_t pop_cmd = { "pop", NULL, pop_f, 0, 0, 0, NULL, N_("pop location from the stack"), pop_help }; static const cmdinfo_t push_cmd = { "push", NULL, push_f, 0, 2, 0, N_("[command]"), N_("push location to the stack"), push_help }; static const cmdinfo_t stack_cmd = { "stack", NULL, stack_f, 0, 0, 0, NULL, N_("view the location stack"), stack_help }; static const cmdinfo_t forward_cmd = { "forward", "f", forward_f, 0, 0, 0, NULL, N_("move forward to next entry in the position ring"), forward_help }; static const cmdinfo_t back_cmd = { "back", "b", back_f, 0, 0, 0, NULL, N_("move to the previous location in the position ring"), back_help }; static const cmdinfo_t ring_cmd = { "ring", NULL, ring_f, 0, 1, 0, NULL, N_("show position ring or move to a specific entry"), ring_help }; iocur_t *iocur_base; iocur_t *iocur_top; int iocur_sp = -1; int iocur_len; #define RING_ENTRIES 20 static iocur_t iocur_ring[RING_ENTRIES]; static int ring_head = -1; static int ring_tail = -1; static int ring_current = -1; void io_init(void) { add_command(&pop_cmd); add_command(&push_cmd); add_command(&stack_cmd); add_command(&forward_cmd); add_command(&back_cmd); add_command(&ring_cmd); } void off_cur( int off, int len) { if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen)) dbprintf(_("can't set block offset to %d\n"), off); else { iocur_top->boff = off; iocur_top->off = ((xfs_off_t)iocur_top->bb << BBSHIFT) + off; iocur_top->len = len; iocur_top->data = (void *)((char *)iocur_top->buf + off); } } void pop_cur(void) { if (iocur_sp < 0) { dbprintf(_("can't pop anything from I/O stack\n")); return; } if (iocur_top->bp) { libxfs_putbuf(iocur_top->bp); iocur_top->bp = NULL; } if (iocur_top->bbmap) { free(iocur_top->bbmap); iocur_top->bbmap = NULL; } if (--iocur_sp >= 0) { iocur_top = iocur_base + iocur_sp; cur_typ = iocur_top->typ; } else { iocur_top = iocur_base; iocur_sp = 0; } } /*ARGSUSED*/ static int pop_f( int argc, char **argv) { pop_cur(); return 0; } static void pop_help(void) { dbprintf(_( "\n" " Changes the address and data type to the first entry on the stack.\n" "\n" )); } void print_iocur( char *tag, iocur_t *ioc) { int i; dbprintf("%s\n", tag); dbprintf(_("\tbyte offset %lld, length %d\n"), ioc->off, ioc->len); dbprintf(_("\tbuffer block %lld (fsbno %lld), %d bb%s\n"), ioc->bb, (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb), ioc->blen, ioc->blen == 1 ? "" : "s"); if (ioc->bbmap) { dbprintf(_("\tblock map")); for (i = 0; i < ioc->bbmap->nmaps; i++) dbprintf(" %lld:%d", ioc->bbmap->b[i].bm_bn, ioc->bbmap->b[i].bm_len); dbprintf("\n"); } dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc->ino, ioc->dirino, ioc->typ == NULL ? _("none") : ioc->typ->name); } static void print_ring(void) { int i; iocur_t *ioc; if (ring_current == -1) { dbprintf(_("no entries in location ring.\n")); return; } dbprintf(_(" type bblock bblen fsbno inode\n")); i = ring_head; for (;;) { ioc = &iocur_ring[i]; if (i == ring_current) printf("*%2d: ", i); else printf(" %2d: ", i); dbprintf("%-7.7s %8lld %5d %8lld %9lld\n", ioc->typ == NULL ? "none" : ioc->typ->name, ioc->bb, ioc->blen, (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb), ioc->ino ); if (i == ring_tail) break; i = (i+(RING_ENTRIES-1))%RING_ENTRIES; } } void push_cur(void) { if (iocur_sp + 1 >= iocur_len) { iocur_base = xrealloc(iocur_base, sizeof(*iocur_base) * (iocur_len + 1)); iocur_len++; } iocur_sp++; iocur_top = iocur_base + iocur_sp; memset(iocur_top, 0, sizeof(*iocur_base)); iocur_top->ino = iocur_sp > 0 ? iocur_top[-1].ino : NULLFSINO; iocur_top->dirino = iocur_sp > 0 ? iocur_top[-1].dirino : NULLFSINO; iocur_top->mode = iocur_sp > 0 ? iocur_top[-1].mode : 0; cur_typ = NULL; } void push_cur_and_set_type(void) { /* save current state */ push_cur(); if (iocur_top[-1].typ && iocur_top[-1].typ->typnm == TYP_INODE) set_cur_inode(iocur_top[-1].ino); else set_cur(iocur_top[-1].typ, iocur_top[-1].bb, iocur_top[-1].blen, DB_RING_IGN, iocur_top[-1].bbmap); } static int push_f( int argc, char **argv) { const cmdinfo_t *ct; if (argc > 1) { /* check we can execute command */ ct = find_command(argv[1]); if (ct == NULL) { dbprintf(_("no such command %s\n"), argv[1]); return 0; } if (!ct->canpush) { dbprintf(_("no push form allowed for %s\n"), argv[1]); return 0; } } push_cur_and_set_type(); /* run requested command */ if (argc>1) (void)command(argc-1, argv+1); return 0; } static void push_help(void) { dbprintf(_( "\n" " Allows you to push the current address and data type on the stack for\n" " later return. 'push' also accepts an additional command to execute after\n" " storing the current address (ex: 'push a rootino' from the superblock).\n" "\n" )); } /* move forward through the ring */ /* ARGSUSED */ static int forward_f( int argc, char **argv) { if (ring_current == -1) { dbprintf(_("ring is empty\n")); return 0; } if (ring_current == ring_head) { dbprintf(_("no further entries\n")); return 0; } ring_current = (ring_current+1)%RING_ENTRIES; set_cur(iocur_ring[ring_current].typ, iocur_ring[ring_current].bb, iocur_ring[ring_current].blen, DB_RING_IGN, iocur_ring[ring_current].bbmap); return 0; } static void forward_help(void) { dbprintf(_( "\n" " The 'forward' ('f') command moves to the next location in the position\n" " ring, updating the current position and data type. If the current location\n" " is the top entry in the ring, then the 'forward' command will have\n" " no effect.\n" "\n" )); } /* move backwards through the ring */ /* ARGSUSED */ static int back_f( int argc, char **argv) { if (ring_current == -1) { dbprintf(_("ring is empty\n")); return 0; } if (ring_current == ring_tail) { dbprintf(_("no previous entries\n")); return 0; } ring_current = (ring_current+(RING_ENTRIES-1))%RING_ENTRIES; set_cur(iocur_ring[ring_current].typ, iocur_ring[ring_current].bb, iocur_ring[ring_current].blen, DB_RING_IGN, iocur_ring[ring_current].bbmap); return 0; } static void back_help(void) { dbprintf(_( "\n" " The 'back' ('b') command moves to the previous location in the position\n" " ring, updating the current position and data type. If the current location\n" " is the last entry in the ring, then the 'back' command will have no effect.\n" "\n" )); } /* show or go to specific point in ring */ static int ring_f( int argc, char **argv) { int index; if (argc == 1) { print_ring(); return 0; } index = (int)strtoul(argv[1], NULL, 0); if (index < 0 || index >= RING_ENTRIES) { dbprintf(_("invalid entry: %d\n"), index); return 0; } ring_current = index; set_cur(iocur_ring[index].typ, iocur_ring[index].bb, iocur_ring[index].blen, DB_RING_IGN, iocur_ring[index].bbmap); return 0; } static void ring_help(void) { dbprintf(_( "\n" " The position ring automatically keeps track of each disk location and\n" " structure type for each change of position you make during your xfs_db\n" " session. The last %d most recent entries are kept in the ring.\n" "\n" " To display the current list of ring entries type 'ring' by itself on\n" " the command line. The entry highlighted by an asterisk ('*') is the\n" " current entry.\n" "\n" " To move to another entry in the ring type 'ring ' where is\n" " your desired entry from the ring position list.\n" "\n" " You may also use the 'forward' ('f') or 'back' ('b') commands to move\n" " to the previous or next entry in the ring, respectively.\n" "\n" " Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n" " location implicitly. Use the 'push' and 'pop' commands if you wish to\n" " store a specific location explicitly for later return.\n" "\n"), RING_ENTRIES); } void ring_add(void) { if (ring_head == -1) { /* only get here right after startup */ ring_head = 0; ring_tail = 0; ring_current = 0; iocur_ring[0] = *iocur_top; } else { if (ring_current == ring_head) { ring_head = (ring_head+1)%RING_ENTRIES; iocur_ring[ring_head] = *iocur_top; if (ring_head == ring_tail) ring_tail = (ring_tail+1)%RING_ENTRIES; ring_current = ring_head; } else { ring_current = (ring_current+1)%RING_ENTRIES; iocur_ring[ring_current] = *iocur_top; } } } static void write_cur_buf(void) { int ret; ret = -libxfs_writebufr(iocur_top->bp); if (ret != 0) dbprintf(_("write error: %s\n"), strerror(ret)); /* re-read buffer from disk */ ret = -libxfs_readbufr(mp->m_ddev_targp, iocur_top->bb, iocur_top->bp, iocur_top->blen, 0); if (ret != 0) dbprintf(_("read error: %s\n"), strerror(ret)); } static void write_cur_bbs(void) { int ret; ret = -libxfs_writebufr(iocur_top->bp); if (ret != 0) dbprintf(_("write error: %s\n"), strerror(ret)); /* re-read buffer from disk */ ret = -libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0); if (ret != 0) dbprintf(_("read error: %s\n"), strerror(ret)); } void xfs_dummy_verify( struct xfs_buf *bp) { return; } void xfs_verify_recalc_crc( struct xfs_buf *bp) { xfs_buf_update_cksum(bp, iocur_top->typ->crc_off); } void write_cur(void) { bool skip_crc = false; if (iocur_sp < 0) { dbprintf(_("nothing to write\n")); return; } if (!xfs_sb_version_hascrc(&mp->m_sb) || !iocur_top->bp->b_ops || iocur_top->bp->b_ops->verify_write == xfs_dummy_verify) skip_crc = true; if (!skip_crc) { if (iocur_top->ino_buf) xfs_inode_set_crc(iocur_top->bp); else if (iocur_top->dquot_buf) xfs_dquot_set_crc(iocur_top->bp); } if (iocur_top->bbmap) write_cur_bbs(); else write_cur_buf(); /* If we didn't write the crc automatically, re-check inode validity */ if (xfs_sb_version_hascrc(&mp->m_sb) && skip_crc && iocur_top->ino_buf) { iocur_top->ino_crc_ok = libxfs_verify_cksum(iocur_top->data, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF); } } void set_cur( const typ_t *type, xfs_daddr_t blknum, int len, int ring_flag, bbmap_t *bbmap) { struct xfs_buf *bp; xfs_ino_t dirino; xfs_ino_t ino; uint16_t mode; const struct xfs_buf_ops *ops = type ? type->bops : NULL; if (iocur_sp < 0) { dbprintf(_("set_cur no stack element to set\n")); return; } ino = iocur_top->ino; dirino = iocur_top->dirino; mode = iocur_top->mode; pop_cur(); push_cur(); if (bbmap) { #ifdef DEBUG_BBMAP int i; printf(_("xfs_db got a bbmap for %lld\n"), (long long)blknum); printf(_("\tblock map")); for (i = 0; i < bbmap->nmaps; i++) printf(" %lld:%d", (long long)bbmap->b[i].bm_bn, bbmap->b[i].bm_len); printf("\n"); #endif iocur_top->bbmap = malloc(sizeof(struct bbmap)); if (!iocur_top->bbmap) return; memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap)); bp = libxfs_readbuf_map(mp->m_ddev_targp, bbmap->b, bbmap->nmaps, 0, ops); } else { bp = libxfs_readbuf(mp->m_ddev_targp, blknum, len, 0, ops); iocur_top->bbmap = NULL; } /* * Keep the buffer even if the verifier says it is corrupted. * We're a diagnostic tool, after all. */ if (!bp || (bp->b_error && bp->b_error != -EFSCORRUPTED && bp->b_error != -EFSBADCRC)) return; iocur_top->buf = bp->b_addr; iocur_top->bp = bp; if (!ops) bp->b_flags |= LIBXFS_B_UNCHECKED; iocur_top->bb = blknum; iocur_top->blen = len; iocur_top->boff = 0; iocur_top->data = iocur_top->buf; iocur_top->len = BBTOB(len); iocur_top->off = blknum << BBSHIFT; iocur_top->typ = cur_typ = type; iocur_top->ino = ino; iocur_top->dirino = dirino; iocur_top->mode = mode; iocur_top->ino_buf = 0; iocur_top->dquot_buf = 0; /* store location in ring */ if (ring_flag) ring_add(); } void set_iocur_type( const typ_t *type) { struct xfs_buf *bp = iocur_top->bp; /* Inodes are special; verifier checks all inodes in the chunk */ if (type->typnm == TYP_INODE) { xfs_daddr_t b = iocur_top->bb; xfs_ino_t ino; /* * Note that this will back up to the beginning of the inode * which contains the current disk location; daddr may change. */ ino = XFS_AGINO_TO_INO(mp, xfs_daddr_to_agno(mp, b), ((b << BBSHIFT) >> mp->m_sb.sb_inodelog) % XFS_AGB_TO_AGINO(mp, mp->m_sb.sb_agblocks)); set_cur_inode(ino); return; } /* adjust buffer size for types with fields & hence fsize() */ if (type->fields) { int bb_count; /* type's size in basic blocks */ bb_count = BTOBB(byteize(fsize(type->fields, iocur_top->data, 0, 0))); set_cur(type, iocur_top->bb, bb_count, DB_RING_IGN, NULL); } iocur_top->typ = type; /* verify the buffer if the type has one. */ if (!bp) return; if (!type->bops) { bp->b_ops = NULL; bp->b_flags |= LIBXFS_B_UNCHECKED; return; } if (!(bp->b_flags & LIBXFS_B_UPTODATE)) return; bp->b_error = 0; bp->b_ops = type->bops; bp->b_ops->verify_read(bp); bp->b_flags &= ~LIBXFS_B_UNCHECKED; } static void stack_help(void) { dbprintf(_( "\n" " The stack is used to explicitly store your location and data type\n" " for later return. The 'push' operation stores the current address\n" " and type on the stack, the 'pop' operation returns you to the\n" " position and datatype of the top entry on the stack.\n" "\n" " The 'stack' allows explicit location saves, see 'ring' for implicit\n" " position tracking.\n" "\n" )); } /*ARGSUSED*/ static int stack_f( int argc, char **argv) { int i; char tagbuf[8]; for (i = iocur_sp; i > 0; i--) { snprintf(tagbuf, sizeof(tagbuf), "%d: ", i); print_iocur(tagbuf, &iocur_base[i]); } return 0; } xfsprogs-5.3.0/db/io.h0000644000175000017500000000416013466663244014430 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct typ; #define BBMAP_SIZE (XFS_MAX_BLOCKSIZE / BBSIZE) typedef struct bbmap { int nmaps; struct xfs_buf_map b[BBMAP_SIZE]; } bbmap_t; typedef struct iocur { int64_t bb; /* BB number in filesystem of buf */ int blen; /* length of "buf", bb's */ int boff; /* data - buf */ void *buf; /* base address of buffer */ void *data; /* current interesting data */ xfs_ino_t dirino; /* current directory inode number */ xfs_ino_t ino; /* current inode number */ int len; /* length of "data", bytes */ uint16_t mode; /* current inode's mode */ xfs_off_t off; /* fs offset of "data" in bytes */ const struct typ *typ; /* type of "data" */ bbmap_t *bbmap; /* map daddr if fragmented */ struct xfs_buf *bp; /* underlying buffer */ bool ino_crc_ok; bool ino_buf; bool dquot_buf; bool need_crc; } iocur_t; #define DB_RING_ADD 1 /* add to ring on set_cur */ #define DB_RING_IGN 0 /* do not add to ring on set_cur */ extern iocur_t *iocur_base; /* base of stack */ extern iocur_t *iocur_top; /* top element of stack */ extern int iocur_sp; /* current top of stack */ extern int iocur_len; /* length of stack array */ extern void io_init(void); extern void off_cur(int off, int len); extern void pop_cur(void); extern void print_iocur(char *tag, iocur_t *ioc); extern void push_cur(void); extern void push_cur_and_set_type(void); extern void write_cur(void); extern void set_cur(const struct typ *type, xfs_daddr_t blknum, int len, int ring_add, bbmap_t *bbmap); extern void ring_add(void); extern void set_iocur_type(const struct typ *type); extern void xfs_dummy_verify(struct xfs_buf *bp); extern void xfs_verify_recalc_crc(struct xfs_buf *bp); /* * returns -1 for unchecked, 0 for bad and 1 for good */ static inline int iocur_crc_valid(void) { if (!iocur_top->bp) return -1; if (iocur_top->bp->b_flags & LIBXFS_B_UNCHECKED) return -1; return (iocur_top->bp->b_error != -EFSBADCRC && (!iocur_top->ino_buf || iocur_top->ino_crc_ok)); } xfsprogs-5.3.0/db/logformat.c0000644000175000017500000001037313435336036016001 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "init.h" #include "output.h" #include "libxlog.h" #include "logformat.h" #define MAX_LSUNIT 256 * 1024 /* max log buf. size */ static int logformat_f(int argc, char **argv) { xfs_daddr_t head_blk; xfs_daddr_t tail_blk; int logversion; int lsunit = -1; int cycle = -1; int error; int c; logversion = xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1; while ((c = getopt(argc, argv, "c:s:")) != EOF) { switch (c) { case 'c': cycle = strtol(optarg, NULL, 0); if (cycle == 0) { dbprintf("invalid cycle\n"); return -1; } break; case 's': lsunit = strtol(optarg, NULL, 0); /* * The log stripe unit must be block aligned and no * larger than 256k. */ if (lsunit > 1 && (lsunit % mp->m_sb.sb_blocksize || (logversion == 2 && lsunit > MAX_LSUNIT))) { dbprintf("invalid log stripe unit\n"); return -1; } break; default: dbprintf("invalid option\n"); return -1; } } /* * Check whether the log is dirty. This also determines the current log * cycle if we have to use it by default below. */ memset(mp->m_log, 0, sizeof(struct xlog)); mp->m_log->l_mp = mp; mp->m_log->l_dev = mp->m_logdev_targp; mp->m_log->l_logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); mp->m_log->l_logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); mp->m_log->l_sectBBsize = BBSIZE; if (xfs_sb_version_hassector(&mp->m_sb)) mp->m_log->l_sectBBsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT); mp->m_log->l_sectBBsize = BTOBB(mp->m_log->l_sectBBsize); error = xlog_find_tail(mp->m_log, &head_blk, &tail_blk); if (error) { dbprintf("could not find log head/tail\n"); return -1; } if (head_blk != tail_blk) { dbprintf(_( "The log is dirty. Please mount to replay the log.\n")); return -1; } /* * Use the current cycle and/or log stripe unit if either is not * provided by the user. */ if (cycle < 0) cycle = mp->m_log->l_curr_cycle; if (lsunit < 0) lsunit = mp->m_sb.sb_logsunit; dbprintf("Formatting the log to cycle %d, stripe unit %d bytes.\n", cycle, lsunit); error = -libxfs_log_clear(mp->m_logdev_targp, NULL, mp->m_log->l_logBBstart, mp->m_log->l_logBBsize, &mp->m_sb.sb_uuid, logversion, lsunit, XLOG_FMT, cycle, false); if (error) { dbprintf("error formatting log - %d\n", error); return error; } return 0; } static void logformat_help(void) { dbprintf(_( "\n" " The 'logformat' command reformats (clears) the log to the specified log\n" " cycle and log stripe unit. If the log cycle is not specified, the log is\n" " reformatted to the current cycle. If the log stripe unit is not specified,\n" " the stripe unit from the filesystem superblock is used.\n" "\n" )); } static const struct cmdinfo logformat_cmd = { .name = "logformat", .altname = NULL, .cfunc = logformat_f, .argmin = 0, .argmax = 4, .canpush = 0, .args = N_("[-c cycle] [-s sunit]"), .oneline = N_("reformat the log"), .help = logformat_help, }; void logformat_init(void) { if (!expert_mode) return; add_command(&logformat_cmd); } static void print_logres( int i, struct xfs_trans_res *res) { dbprintf(_("type %d logres %u logcount %d flags 0x%x\n"), i, res->tr_logres, res->tr_logcount, res->tr_logflags); } static int logres_f( int argc, char **argv) { struct xfs_trans_res resv; struct xfs_trans_res *res; struct xfs_trans_res *end_res; int i; res = (struct xfs_trans_res *)M_RES(mp); end_res = (struct xfs_trans_res *)(M_RES(mp) + 1); for (i = 0; res < end_res; i++, res++) print_logres(i, res); libxfs_log_get_max_trans_res(mp, &resv); print_logres(-1, &resv); return 0; } static void logres_help(void) { dbprintf(_( "\n" " The 'logres' command prints information about all log reservation types.\n" " This includes the reservation space, the intended transaction roll count,\n" " and the reservation flags, if any.\n" "\n" )); } static const struct cmdinfo logres_cmd = { .name = "logres", .altname = NULL, .cfunc = logres_f, .argmin = 0, .argmax = 0, .canpush = 0, .args = NULL, .oneline = N_("dump log reservations"), .help = logres_help, }; void logres_init(void) { add_command(&logres_cmd); } xfsprogs-5.3.0/db/logformat.h0000644000175000017500000000023313435336036016000 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 Red Hat, Inc. * All Rights Reserved. */ void logformat_init(void); void logres_init(void); xfsprogs-5.3.0/db/malloc.c0000644000175000017500000000163313435336036015255 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "init.h" #include "malloc.h" #include "output.h" static void badmalloc(void) { dbprintf(_("%s: out of memory\n"), progname); exit(4); } void * xcalloc( size_t nelem, size_t elsize) { void *ptr; ptr = calloc(nelem, elsize); if (ptr) return ptr; badmalloc(); /* NOTREACHED */ return NULL; } void xfree( void *ptr) { free(ptr); } void * xmalloc( size_t size) { void *ptr; ptr = valloc(size); if (ptr) return ptr; badmalloc(); /* NOTREACHED */ return NULL; } void * xrealloc( void *ptr, size_t size) { ptr = realloc(ptr, size); if (ptr || !size) return ptr; badmalloc(); /* NOTREACHED */ return NULL; } char * xstrdup( const char *s1) { char *s; s = strdup(s1); if (s) return s; badmalloc(); /* NOTREACHED */ return NULL; } xfsprogs-5.3.0/db/malloc.h0000644000175000017500000000050413435336036015256 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void *xcalloc(size_t nelem, size_t elsize); extern void xfree(void *ptr); extern void *xmalloc(size_t size); extern void *xrealloc(void *ptr, size_t size); extern char *xstrdup(const char *s1); xfsprogs-5.3.0/db/metadump.c0000644000175000017500000023156413570057155015634 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2007, 2011 SGI * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "bmap.h" #include "command.h" #include "metadump.h" #include "io.h" #include "output.h" #include "type.h" #include "init.h" #include "sig.h" #include "xfs_metadump.h" #include "fprint.h" #include "faddr.h" #include "field.h" #include "dir2.h" #define DEFAULT_MAX_EXT_SIZE MAXEXTLEN /* copy all metadata structures to/from a file */ static int metadump_f(int argc, char **argv); static void metadump_help(void); /* * metadump commands issue info/wornings/errors to standard error as * metadump supports stdout as a destination. * * All static functions return zero on failure, while the public functions * return zero on success. */ static const cmdinfo_t metadump_cmd = { "metadump", NULL, metadump_f, 0, -1, 0, N_("[-a] [-e] [-g] [-m max_extent] [-w] [-o] filename"), N_("dump metadata to a file"), metadump_help }; static FILE *outf; /* metadump file */ static xfs_metablock_t *metablock; /* header + index + buffers */ static __be64 *block_index; static char *block_buffer; static int num_indices; static int cur_index; static xfs_ino_t cur_ino; static int show_progress = 0; static int stop_on_read_error = 0; static int max_extent_size = DEFAULT_MAX_EXT_SIZE; static int obfuscate = 1; static int zero_stale_data = 1; static int show_warnings = 0; static int progress_since_warning = 0; static bool stdout_metadump; void metadump_init(void) { add_command(&metadump_cmd); } static void metadump_help(void) { dbprintf(_( "\n" " The 'metadump' command dumps the known metadata to a compact file suitable\n" " for compressing and sending to an XFS maintainer for corruption analysis \n" " or xfs_repair failures.\n\n" " Options:\n" " -a -- Copy full metadata blocks without zeroing unused space\n" " -e -- Ignore read errors and keep going\n" " -g -- Display dump progress\n" " -m -- Specify max extent size in blocks to copy (default = %d blocks)\n" " -o -- Don't obfuscate names and extended attributes\n" " -w -- Show warnings of bad metadata information\n" "\n"), DEFAULT_MAX_EXT_SIZE); } static void print_warning(const char *fmt, ...) { char buf[200]; va_list ap; if (seenint()) return; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); buf[sizeof(buf)-1] = '\0'; fprintf(stderr, "%s%s: %s\n", progress_since_warning ? "\n" : "", progname, buf); progress_since_warning = 0; } static void print_progress(const char *fmt, ...) { char buf[60]; va_list ap; FILE *f; if (seenint()) return; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); buf[sizeof(buf)-1] = '\0'; f = stdout_metadump ? stderr : stdout; fprintf(f, "\r%-59s", buf); fflush(f); progress_since_warning = 1; } /* * A complete dump file will have a "zero" entry in the last index block, * even if the dump is exactly aligned, the last index will be full of * zeros. If the last index entry is non-zero, the dump is incomplete. * Correspondingly, the last chunk will have a count < num_indices. * * Return 0 for success, -1 for failure. */ static int write_index(void) { /* * write index block and following data blocks (streaming) */ metablock->mb_count = cpu_to_be16(cur_index); if (fwrite(metablock, (cur_index + 1) << BBSHIFT, 1, outf) != 1) { print_warning("error writing to target file"); return -1; } memset(block_index, 0, num_indices * sizeof(__be64)); cur_index = 0; return 0; } /* * Return 0 for success, -errno for failure. */ static int write_buf_segment( char *data, int64_t off, int len) { int i; int ret; for (i = 0; i < len; i++, off++, data += BBSIZE) { block_index[cur_index] = cpu_to_be64(off); memcpy(&block_buffer[cur_index << BBSHIFT], data, BBSIZE); if (++cur_index == num_indices) { ret = write_index(); if (ret) return -EIO; } } return 0; } /* * we want to preserve the state of the metadata in the dump - whether it is * intact or corrupt, so even if the buffer has a verifier attached to it we * don't want to run it prior to writing the buffer to the metadump image. * * The only reason for running the verifier is to recalculate the CRCs on a * buffer that has been obfuscated. i.e. a buffer than metadump modified itself. * In this case, we only run the verifier if the buffer was not corrupt to begin * with so that we don't accidentally correct buffers with CRC or errors in them * when we are obfuscating them. */ static int write_buf( iocur_t *buf) { struct xfs_buf *bp = buf->bp; int i; int ret; /* * Run the write verifier to recalculate the buffer CRCs and check * metadump didn't introduce a new corruption. Warn if the verifier * failed, but still continue to dump it into the output file. */ if (buf->need_crc && bp && bp->b_ops && !bp->b_error) { bp->b_ops->verify_write(bp); if (bp->b_error) { print_warning( "obfuscation corrupted block at %s bno 0x%llx/0x%x", bp->b_ops->name, (long long)bp->b_bn, bp->b_bcount); } } /* handle discontiguous buffers */ if (!buf->bbmap) { ret = write_buf_segment(buf->data, buf->bb, buf->blen); if (ret) return ret; } else { int len = 0; for (i = 0; i < buf->bbmap->nmaps; i++) { ret = write_buf_segment(buf->data + BBTOB(len), buf->bbmap->b[i].bm_bn, buf->bbmap->b[i].bm_len); if (ret) return ret; len += buf->bbmap->b[i].bm_len; } } return seenint() ? -EINTR : 0; } /* * We could be processing a corrupt block, so we can't trust any of * the offsets or lengths to be within the buffer range. Hence check * carefully! */ static void zero_btree_node( struct xfs_btree_block *block, typnm_t btype) { int nrecs; xfs_bmbt_ptr_t *bpp; xfs_bmbt_key_t *bkp; xfs_inobt_ptr_t *ipp; xfs_inobt_key_t *ikp; xfs_alloc_ptr_t *app; xfs_alloc_key_t *akp; char *zp1, *zp2; char *key_end; struct xfs_ino_geometry *igeo = M_IGEO(mp); nrecs = be16_to_cpu(block->bb_numrecs); if (nrecs < 0) return; switch (btype) { case TYP_BMAPBTA: case TYP_BMAPBTD: if (nrecs > mp->m_bmap_dmxr[1]) return; bkp = XFS_BMBT_KEY_ADDR(mp, block, 1); bpp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); zp1 = (char *)&bkp[nrecs]; zp2 = (char *)&bpp[nrecs]; key_end = (char *)bpp; break; case TYP_INOBT: case TYP_FINOBT: if (nrecs > igeo->inobt_mxr[1]) return; ikp = XFS_INOBT_KEY_ADDR(mp, block, 1); ipp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); zp1 = (char *)&ikp[nrecs]; zp2 = (char *)&ipp[nrecs]; key_end = (char *)ipp; break; case TYP_BNOBT: case TYP_CNTBT: if (nrecs > mp->m_alloc_mxr[1]) return; akp = XFS_ALLOC_KEY_ADDR(mp, block, 1); app = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); zp1 = (char *)&akp[nrecs]; zp2 = (char *)&app[nrecs]; key_end = (char *)app; break; default: return; } /* Zero from end of keys to beginning of pointers */ memset(zp1, 0, key_end - zp1); /* Zero from end of pointers to end of block */ memset(zp2, 0, (char *)block + mp->m_sb.sb_blocksize - zp2); } /* * We could be processing a corrupt block, so we can't trust any of * the offsets or lengths to be within the buffer range. Hence check * carefully! */ static void zero_btree_leaf( struct xfs_btree_block *block, typnm_t btype) { int nrecs; struct xfs_bmbt_rec *brp; struct xfs_inobt_rec *irp; struct xfs_alloc_rec *arp; char *zp; nrecs = be16_to_cpu(block->bb_numrecs); if (nrecs < 0) return; switch (btype) { case TYP_BMAPBTA: case TYP_BMAPBTD: if (nrecs > mp->m_bmap_dmxr[0]) return; brp = XFS_BMBT_REC_ADDR(mp, block, 1); zp = (char *)&brp[nrecs]; break; case TYP_INOBT: case TYP_FINOBT: if (nrecs > M_IGEO(mp)->inobt_mxr[0]) return; irp = XFS_INOBT_REC_ADDR(mp, block, 1); zp = (char *)&irp[nrecs]; break; case TYP_BNOBT: case TYP_CNTBT: if (nrecs > mp->m_alloc_mxr[0]) return; arp = XFS_ALLOC_REC_ADDR(mp, block, 1); zp = (char *)&arp[nrecs]; break; default: return; } /* Zero from end of records to end of block */ memset(zp, 0, (char *)block + mp->m_sb.sb_blocksize - zp); } static void zero_btree_block( struct xfs_btree_block *block, typnm_t btype) { int level; level = be16_to_cpu(block->bb_level); if (level > 0) zero_btree_node(block, btype); else zero_btree_leaf(block, btype); } static int scan_btree( xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg, int (*func)(struct xfs_btree_block *block, xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg)) { int rval = 0; push_cur(); set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { print_warning("cannot read %s block %u/%u", typtab[btype].name, agno, agbno); rval = !stop_on_read_error; goto pop_out; } if (zero_stale_data) { zero_btree_block(iocur_top->data, btype); iocur_top->need_crc = 1; } if (write_buf(iocur_top)) goto pop_out; if (!(*func)(iocur_top->data, agno, agbno, level - 1, btype, arg)) goto pop_out; rval = 1; pop_out: pop_cur(); return rval; } /* free space tree copy routines */ static int valid_bno( xfs_agnumber_t agno, xfs_agblock_t agbno) { if (agno < (mp->m_sb.sb_agcount - 1) && agbno > 0 && agbno <= mp->m_sb.sb_agblocks) return 1; if (agno == (mp->m_sb.sb_agcount - 1) && agbno > 0 && agbno <= (mp->m_sb.sb_dblocks - (xfs_rfsblock_t)(mp->m_sb.sb_agcount - 1) * mp->m_sb.sb_agblocks)) return 1; return 0; } static int scanfunc_freesp( struct xfs_btree_block *block, xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg) { xfs_alloc_ptr_t *pp; int i; int numrecs; if (level == 0) return 1; numrecs = be16_to_cpu(block->bb_numrecs); if (numrecs > mp->m_alloc_mxr[1]) { if (show_warnings) print_warning("invalid numrecs (%u) in %s block %u/%u", numrecs, typtab[btype].name, agno, agbno); return 1; } pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); for (i = 0; i < numrecs; i++) { if (!valid_bno(agno, be32_to_cpu(pp[i]))) { if (show_warnings) print_warning("invalid block number (%u/%u) " "in %s block %u/%u", agno, be32_to_cpu(pp[i]), typtab[btype].name, agno, agbno); continue; } if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg, scanfunc_freesp)) return 0; } return 1; } static int copy_free_bno_btree( xfs_agnumber_t agno, xfs_agf_t *agf) { xfs_agblock_t root; int levels; root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]); levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); /* validate root and levels before processing the tree */ if (root == 0 || root > mp->m_sb.sb_agblocks) { if (show_warnings) print_warning("invalid block number (%u) in bnobt " "root in agf %u", root, agno); return 1; } if (levels >= XFS_BTREE_MAXLEVELS) { if (show_warnings) print_warning("invalid level (%u) in bnobt root " "in agf %u", levels, agno); return 1; } return scan_btree(agno, root, levels, TYP_BNOBT, agf, scanfunc_freesp); } static int copy_free_cnt_btree( xfs_agnumber_t agno, xfs_agf_t *agf) { xfs_agblock_t root; int levels; root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]); levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); /* validate root and levels before processing the tree */ if (root == 0 || root > mp->m_sb.sb_agblocks) { if (show_warnings) print_warning("invalid block number (%u) in cntbt " "root in agf %u", root, agno); return 1; } if (levels >= XFS_BTREE_MAXLEVELS) { if (show_warnings) print_warning("invalid level (%u) in cntbt root " "in agf %u", levels, agno); return 1; } return scan_btree(agno, root, levels, TYP_CNTBT, agf, scanfunc_freesp); } static int scanfunc_rmapbt( struct xfs_btree_block *block, xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg) { xfs_rmap_ptr_t *pp; int i; int numrecs; if (level == 0) return 1; numrecs = be16_to_cpu(block->bb_numrecs); if (numrecs > mp->m_rmap_mxr[1]) { if (show_warnings) print_warning("invalid numrecs (%u) in %s block %u/%u", numrecs, typtab[btype].name, agno, agbno); return 1; } pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]); for (i = 0; i < numrecs; i++) { if (!valid_bno(agno, be32_to_cpu(pp[i]))) { if (show_warnings) print_warning("invalid block number (%u/%u) " "in %s block %u/%u", agno, be32_to_cpu(pp[i]), typtab[btype].name, agno, agbno); continue; } if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg, scanfunc_rmapbt)) return 0; } return 1; } static int copy_rmap_btree( xfs_agnumber_t agno, struct xfs_agf *agf) { xfs_agblock_t root; int levels; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 1; root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]); levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); /* validate root and levels before processing the tree */ if (root == 0 || root > mp->m_sb.sb_agblocks) { if (show_warnings) print_warning("invalid block number (%u) in rmapbt " "root in agf %u", root, agno); return 1; } if (levels >= XFS_BTREE_MAXLEVELS) { if (show_warnings) print_warning("invalid level (%u) in rmapbt root " "in agf %u", levels, agno); return 1; } return scan_btree(agno, root, levels, TYP_RMAPBT, agf, scanfunc_rmapbt); } static int scanfunc_refcntbt( struct xfs_btree_block *block, xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg) { xfs_refcount_ptr_t *pp; int i; int numrecs; if (level == 0) return 1; numrecs = be16_to_cpu(block->bb_numrecs); if (numrecs > mp->m_refc_mxr[1]) { if (show_warnings) print_warning("invalid numrecs (%u) in %s block %u/%u", numrecs, typtab[btype].name, agno, agbno); return 1; } pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]); for (i = 0; i < numrecs; i++) { if (!valid_bno(agno, be32_to_cpu(pp[i]))) { if (show_warnings) print_warning("invalid block number (%u/%u) " "in %s block %u/%u", agno, be32_to_cpu(pp[i]), typtab[btype].name, agno, agbno); continue; } if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg, scanfunc_refcntbt)) return 0; } return 1; } static int copy_refcount_btree( xfs_agnumber_t agno, struct xfs_agf *agf) { xfs_agblock_t root; int levels; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return 1; root = be32_to_cpu(agf->agf_refcount_root); levels = be32_to_cpu(agf->agf_refcount_level); /* validate root and levels before processing the tree */ if (root == 0 || root > mp->m_sb.sb_agblocks) { if (show_warnings) print_warning("invalid block number (%u) in refcntbt " "root in agf %u", root, agno); return 1; } if (levels >= XFS_BTREE_MAXLEVELS) { if (show_warnings) print_warning("invalid level (%u) in refcntbt root " "in agf %u", levels, agno); return 1; } return scan_btree(agno, root, levels, TYP_REFCBT, agf, scanfunc_refcntbt); } /* filename and extended attribute obfuscation routines */ struct name_ent { struct name_ent *next; xfs_dahash_t hash; int namelen; unsigned char name[1]; }; #define NAME_TABLE_SIZE 4096 static struct name_ent *nametable[NAME_TABLE_SIZE]; static void nametable_clear(void) { int i; struct name_ent *ent; for (i = 0; i < NAME_TABLE_SIZE; i++) { while ((ent = nametable[i])) { nametable[i] = ent->next; free(ent); } } } /* * See if the given name is already in the name table. If so, * return a pointer to its entry, otherwise return a null pointer. */ static struct name_ent * nametable_find(xfs_dahash_t hash, int namelen, unsigned char *name) { struct name_ent *ent; for (ent = nametable[hash % NAME_TABLE_SIZE]; ent; ent = ent->next) { if (ent->hash == hash && ent->namelen == namelen && !memcmp(ent->name, name, namelen)) return ent; } return NULL; } /* * Add the given name to the name table. Returns a pointer to the * name's new entry, or a null pointer if an error occurs. */ static struct name_ent * nametable_add(xfs_dahash_t hash, int namelen, unsigned char *name) { struct name_ent *ent; ent = malloc(sizeof *ent + namelen); if (!ent) return NULL; ent->namelen = namelen; memcpy(ent->name, name, namelen); ent->hash = hash; ent->next = nametable[hash % NAME_TABLE_SIZE]; nametable[hash % NAME_TABLE_SIZE] = ent; return ent; } #define is_invalid_char(c) ((c) == '/' || (c) == '\0') #define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) static inline unsigned char random_filename_char(void) { static unsigned char filename_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; return filename_alphabet[random() % (sizeof filename_alphabet - 1)]; } #define ORPHANAGE "lost+found" #define ORPHANAGE_LEN (sizeof (ORPHANAGE) - 1) static inline int is_orphanage_dir( struct xfs_mount *mp, xfs_ino_t dir_ino, size_t name_len, unsigned char *name) { return dir_ino == mp->m_sb.sb_rootino && name_len == ORPHANAGE_LEN && !memcmp(name, ORPHANAGE, ORPHANAGE_LEN); } /* * Determine whether a name is one we shouldn't obfuscate because * it's an orphan (or the "lost+found" directory itself). Note * "cur_ino" is the inode for the directory currently being * processed. * * Returns 1 if the name should NOT be obfuscated or 0 otherwise. */ static int in_lost_found( xfs_ino_t ino, int namelen, unsigned char *name) { static xfs_ino_t orphanage_ino = 0; char s[24]; /* 21 is enough (64 bits in decimal) */ int slen; /* Record the "lost+found" inode if we haven't done so already */ ASSERT(ino != 0); if (!orphanage_ino && is_orphanage_dir(mp, cur_ino, namelen, name)) orphanage_ino = ino; /* We don't obfuscate the "lost+found" directory itself */ if (ino == orphanage_ino) return 1; /* Most files aren't in "lost+found" at all */ if (cur_ino != orphanage_ino) return 0; /* * Within "lost+found", we don't obfuscate any file whose * name is the same as its inode number. Any others are * stray files and can be obfuscated. */ slen = snprintf(s, sizeof (s), "%llu", (unsigned long long) ino); return slen == namelen && !memcmp(name, s, namelen); } /* * Given a name and its hash value, massage the name in such a way * that the result is another name of equal length which shares the * same hash value. */ static void obfuscate_name( xfs_dahash_t hash, size_t name_len, unsigned char *name) { unsigned char *newp = name; int i; xfs_dahash_t new_hash = 0; unsigned char *first; unsigned char high_bit; int shift; /* * Our obfuscation algorithm requires at least 5-character * names, so don't bother if the name is too short. We * work backward from a hash value to determine the last * five bytes in a name required to produce a new name * with the same hash. */ if (name_len < 5) return; /* * The beginning of the obfuscated name can be pretty much * anything, so fill it in with random characters. * Accumulate its new hash value as we go. */ for (i = 0; i < name_len - 5; i++) { *newp = random_filename_char(); new_hash = *newp ^ rol32(new_hash, 7); newp++; } /* * Compute which five bytes need to be used at the end of * the name so the hash of the obfuscated name is the same * as the hash of the original. If any result in an invalid * character, flip a bit and arrange for a corresponding bit * in a neighboring byte to be flipped as well. For the * last byte, the "neighbor" to change is the first byte * we're computing here. */ new_hash = rol32(new_hash, 3) ^ hash; first = newp; high_bit = 0; for (shift = 28; shift >= 0; shift -= 7) { *newp = (new_hash >> shift & 0x7f) ^ high_bit; if (is_invalid_char(*newp)) { *newp ^= 1; high_bit = 0x80; } else high_bit = 0; ASSERT(!is_invalid_char(*newp)); newp++; } /* * If we flipped a bit on the last byte, we need to fix up * the matching bit in the first byte. The result will * be a valid character, because we know that first byte * has 0's in its upper four bits (it was produced by a * 28-bit right-shift of a 32-bit unsigned value). */ if (high_bit) { *first ^= 0x10; ASSERT(!is_invalid_char(*first)); } ASSERT(libxfs_da_hashname(name, name_len) == hash); } /* * Flip a bit in each of two bytes at the end of the given name. * This is used in generating a series of alternate names to be used * in the event a duplicate is found. * * The bits flipped are selected such that they both affect the same * bit in the name's computed hash value, so flipping them both will * preserve the hash. * * The following diagram aims to show the portion of a computed * hash that a given byte of a name affects. * * 31 28 24 21 14 8 7 3 0 * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * hash: | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ * last-4 ->| |<-- last-2 --->| |<--- last ---->| * |<-- last-3 --->| |<-- last-1 --->| |<- last-4 * |<-- last-7 --->| |<-- last-5 --->| * |<-- last-8 --->| |<-- last-6 --->| * . . . and so on * * The last byte of the name directly affects the low-order byte of * the hash. The next-to-last affects bits 7-14, the next one back * affects bits 14-21, and so on. The effect wraps around when it * goes beyond the top of the hash (as happens for byte last-4). * * Bits that are flipped together "overlap" on the hash value. As * an example of overlap, the last two bytes both affect bit 7 in * the hash. That pair of bytes (and their overlapping bits) can be * used for this "flip bit" operation (it's the first pair tried, * actually). * * A table defines overlapping pairs--the bytes involved and bits * within them--that can be used this way. The byte offset is * relative to a starting point within the name, which will be set * to affect the bytes at the end of the name. The function is * called with a "bitseq" value which indicates which bit flip is * desired, and this translates directly into selecting which entry * in the bit_to_flip[] table to apply. * * The function returns 1 if the operation was successful. It * returns 0 if the result produced a character that's not valid in * a name (either '/' or a '\0'). Finally, it returns -1 if the bit * sequence number is beyond what is supported for a name of this * length. * * Discussion * ---------- * (Also see the discussion above find_alternate(), below.) * * In order to make this function work for any length name, the * table is ordered by increasing byte offset, so that the earliest * entries can apply to the shortest strings. This way all names * are done consistently. * * When bit flips occur, they can convert printable characters * into non-printable ones. In an effort to reduce the impact of * this, the first bit flips are chosen to affect bytes the end of * the name (and furthermore, toward the low bits of a byte). Those * bytes are often non-printable anyway because of the way they are * initially selected by obfuscate_name()). This is accomplished, * using later table entries first. * * Each row in the table doubles the number of alternates that * can be generated. A two-byte name is limited to using only * the first row, so it's possible to generate two alternates * (the original name, plus the alternate produced by flipping * the one pair of bits). In a 5-byte name, the effect of the * first byte overlaps the last by 4 its, and there are 8 bits * to flip, allowing for 256 possible alternates. * * Short names (less than 5 bytes) are never even obfuscated, so for * such names the relatively small number of alternates should never * really be a problem. * * Long names (more than 6 bytes, say) are not likely to exhaust * the number of available alternates. In fact, the table could * probably have stopped at 8 entries, on the assumption that 256 * alternates should be enough for most any situation. The entries * beyond those are present mostly for demonstration of how it could * be populated with more entries, should it ever be necessary to do * so. */ static int flip_bit( size_t name_len, unsigned char *name, uint32_t bitseq) { int index; size_t offset; unsigned char *p0, *p1; unsigned char m0, m1; struct { int byte; /* Offset from start within name */ unsigned char bit; /* Bit within that byte */ } bit_to_flip[][2] = { /* Sorted by second entry's byte */ { { 0, 0 }, { 1, 7 } }, /* Each row defines a pair */ { { 1, 0 }, { 2, 7 } }, /* of bytes and a bit within */ { { 2, 0 }, { 3, 7 } }, /* each byte. Each bit in */ { { 0, 4 }, { 4, 0 } }, /* a pair affects the same */ { { 0, 5 }, { 4, 1 } }, /* bit in the hash, so flipping */ { { 0, 6 }, { 4, 2 } }, /* both will change the name */ { { 0, 7 }, { 4, 3 } }, /* while preserving the hash. */ { { 3, 0 }, { 4, 7 } }, { { 0, 0 }, { 5, 3 } }, /* The first entry's byte offset */ { { 0, 1 }, { 5, 4 } }, /* must be less than the second. */ { { 0, 2 }, { 5, 5 } }, { { 0, 3 }, { 5, 6 } }, /* The table can be extended to */ { { 0, 4 }, { 5, 7 } }, /* an arbitrary number of entries */ { { 4, 0 }, { 5, 7 } }, /* but there's not much point. */ /* . . . */ }; /* Find the first entry *not* usable for name of this length */ for (index = 0; index < ARRAY_SIZE(bit_to_flip); index++) if (bit_to_flip[index][1].byte >= name_len) break; /* * Back up to the last usable entry. If that number is * smaller than the bit sequence number, inform the caller * that nothing this large (or larger) will work. */ if (bitseq > --index) return -1; /* * We will be switching bits at the end of name, with a * preference for affecting the last bytes first. Compute * where in the name we'll start applying the changes. */ offset = name_len - (bit_to_flip[index][1].byte + 1); index -= bitseq; /* Use later table entries first */ p0 = name + offset + bit_to_flip[index][0].byte; p1 = name + offset + bit_to_flip[index][1].byte; m0 = 1 << bit_to_flip[index][0].bit; m1 = 1 << bit_to_flip[index][1].bit; /* Only change the bytes if it produces valid characters */ if (is_invalid_char(*p0 ^ m0) || is_invalid_char(*p1 ^ m1)) return 0; *p0 ^= m0; *p1 ^= m1; return 1; } /* * This function generates a well-defined sequence of "alternate" * names for a given name. An alternate is a name having the same * length and same hash value as the original name. This is needed * because the algorithm produces only one obfuscated name to use * for a given original name, and it's possible that result matches * a name already seen. This function checks for this, and if it * occurs, finds another suitable obfuscated name to use. * * Each bit in the binary representation of the sequence number is * used to select one possible "bit flip" operation to perform on * the name. So for example: * seq = 0: selects no bits to flip * seq = 1: selects the 0th bit to flip * seq = 2: selects the 1st bit to flip * seq = 3: selects the 0th and 1st bit to flip * ... and so on. * * The flip_bit() function takes care of the details of the bit * flipping within the name. Note that the "1st bit" in this * context is a bit sequence number; i.e. it doesn't necessarily * mean bit 0x02 will be changed. * * If a valid name (one that contains no '/' or '\0' characters) is * produced by this process for the given sequence number, this * function returns 1. If the result is not valid, it returns 0. * Returns -1 if the sequence number is beyond the the maximum for * names of the given length. * * * Discussion * ---------- * The number of alternates available for a given name is dependent * on its length. A "bit flip" involves inverting two bits in * a name--the two bits being selected such that their values * affect the name's hash value in the same way. Alternates are * thus generated by inverting the value of pairs of such * "overlapping" bits in the original name. Each byte after the * first in a name adds at least one bit of overlap to work with. * (See comments above flip_bit() for more discussion on this.) * * So the number of alternates is dependent on the number of such * overlapping bits in a name. If there are N bit overlaps, there * 2^N alternates for that hash value. * * Here are the number of overlapping bits available for generating * alternates for names of specific lengths: * 1 0 (must have 2 bytes to have any overlap) * 2 1 One bit overlaps--so 2 possible alternates * 3 2 Two bits overlap--so 4 possible alternates * 4 4 Three bits overlap, so 2^3 alternates * 5 8 8 bits overlap (due to wrapping), 256 alternates * 6 18 2^18 alternates * 7 28 2^28 alternates * ... * It's clear that the number of alternates grows very quickly with * the length of the name. But note that the set of alternates * includes invalid names. And for certain (contrived) names, the * number of valid names is a fairly small fraction of the total * number of alternates. * * The main driver for this infrastructure for coming up with * alternate names is really related to names 5 (or possibly 6) * bytes in length. 5-byte obfuscated names contain no randomly- * generated bytes in them, and the chance of an obfuscated name * matching an already-seen name is too high to just ignore. This * methodical selection of alternates ensures we don't produce * duplicate names unless we have exhausted our options. */ static int find_alternate( size_t name_len, unsigned char *name, uint32_t seq) { uint32_t bitseq = 0; uint32_t bits = seq; if (!seq) return 1; /* alternate 0 is the original name */ if (name_len < 2) /* Must have 2 bytes to flip */ return -1; for (bitseq = 0; bits; bitseq++) { uint32_t mask = 1 << bitseq; int fb; if (!(bits & mask)) continue; fb = flip_bit(name_len, name, bitseq); if (fb < 1) return fb ? -1 : 0; bits ^= mask; } return 1; } /* * Look up the given name in the name table. If it is already * present, iterate through a well-defined sequence of alternate * names and attempt to use an alternate name instead. * * Returns 1 if the (possibly modified) name is not present in the * name table. Returns 0 if the name and all possible alternates * are already in the table. */ static int handle_duplicate_name(xfs_dahash_t hash, size_t name_len, unsigned char *name) { unsigned char new_name[name_len + 1]; uint32_t seq = 1; if (!nametable_find(hash, name_len, name)) return 1; /* No duplicate */ /* Name is already in use. Need to find an alternate. */ do { int found; /* Only change incoming name if we find an alternate */ do { memcpy(new_name, name, name_len); found = find_alternate(name_len, new_name, seq++); if (found < 0) return 0; /* No more to check */ } while (!found); } while (nametable_find(hash, name_len, new_name)); /* * The alternate wasn't in the table already. Pass it back * to the caller. */ memcpy(name, new_name, name_len); return 1; } static void generate_obfuscated_name( xfs_ino_t ino, int namelen, unsigned char *name) { xfs_dahash_t hash; /* * We don't obfuscate "lost+found" or any orphan files * therein. When the name table is used for extended * attributes, the inode number provided is 0, in which * case we don't need to make this check. */ if (ino && in_lost_found(ino, namelen, name)) return; /* * If the name starts with a slash, just skip over it. It * isn't included in the hash and we don't record it in the * name table. Note that the namelen value passed in does * not count the leading slash (if one is present). */ if (*name == '/') name++; /* Obfuscate the name (if possible) */ hash = libxfs_da_hashname(name, namelen); obfuscate_name(hash, namelen, name); /* * Make sure the name is not something already seen. If we * fail to find a suitable alternate, we're dealing with a * very pathological situation, and we may end up creating * a duplicate name in the metadump, so issue a warning. */ if (!handle_duplicate_name(hash, namelen, name)) { print_warning("duplicate name for inode %llu " "in dir inode %llu\n", (unsigned long long) ino, (unsigned long long) cur_ino); return; } /* Create an entry for the new name in the name table. */ if (!nametable_add(hash, namelen, name)) print_warning("unable to record name for inode %llu " "in dir inode %llu\n", (unsigned long long) ino, (unsigned long long) cur_ino); } static void process_sf_dir( xfs_dinode_t *dip) { struct xfs_dir2_sf_hdr *sfp; xfs_dir2_sf_entry_t *sfep; uint64_t ino_dir_size; int i; sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); ino_dir_size = be64_to_cpu(dip->di_size); if (ino_dir_size > XFS_DFORK_DSIZE(dip, mp)) { ino_dir_size = XFS_DFORK_DSIZE(dip, mp); if (show_warnings) print_warning("invalid size in dir inode %llu", (long long)cur_ino); } sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0; (i < sfp->count) && ((char *)sfep - (char *)sfp < ino_dir_size); i++) { /* * first check for bad name lengths. If they are bad, we * have limitations to how much can be obfuscated. */ int namelen = sfep->namelen; if (namelen == 0) { if (show_warnings) print_warning("zero length entry in dir inode " "%llu", (long long)cur_ino); if (i != sfp->count - 1) break; namelen = ino_dir_size - ((char *)&sfep->name[0] - (char *)sfp); } else if ((char *)sfep - (char *)sfp + M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen) > ino_dir_size) { if (show_warnings) print_warning("entry length in dir inode %llu " "overflows space", (long long)cur_ino); if (i != sfp->count - 1) break; namelen = ino_dir_size - ((char *)&sfep->name[0] - (char *)sfp); } if (obfuscate) generate_obfuscated_name( M_DIROPS(mp)->sf_get_ino(sfp, sfep), namelen, &sfep->name[0]); sfep = (xfs_dir2_sf_entry_t *)((char *)sfep + M_DIROPS(mp)->sf_entsize(sfp, namelen)); } /* zero stale data in rest of space in data fork, if any */ if (zero_stale_data && (ino_dir_size < XFS_DFORK_DSIZE(dip, mp))) memset(sfep, 0, XFS_DFORK_DSIZE(dip, mp) - ino_dir_size); } /* * The pathname may not be null terminated. It may be terminated by the end of * a buffer or inode literal area, and the start of the next region contains * unknown data. Therefore, when we get to the last component of the symlink, we * cannot assume that strlen() will give us the right result. Hence we need to * track the remaining pathname length and use that instead. */ static void obfuscate_path_components( char *buf, uint64_t len) { unsigned char *comp = (unsigned char *)buf; unsigned char *end = comp + len; xfs_dahash_t hash; while (comp < end) { char *slash; int namelen; /* find slash at end of this component */ slash = strchr((char *)comp, '/'); if (!slash) { /* last (or single) component */ namelen = strnlen((char *)comp, len); hash = libxfs_da_hashname(comp, namelen); obfuscate_name(hash, namelen, comp); break; } namelen = slash - (char *)comp; /* handle leading or consecutive slashes */ if (!namelen) { comp++; len--; continue; } hash = libxfs_da_hashname(comp, namelen); obfuscate_name(hash, namelen, comp); comp += namelen + 1; len -= namelen + 1; } } static void process_sf_symlink( xfs_dinode_t *dip) { uint64_t len; char *buf; len = be64_to_cpu(dip->di_size); if (len > XFS_DFORK_DSIZE(dip, mp)) { if (show_warnings) print_warning("invalid size (%d) in symlink inode %llu", len, (long long)cur_ino); len = XFS_DFORK_DSIZE(dip, mp); } buf = (char *)XFS_DFORK_DPTR(dip); if (obfuscate) obfuscate_path_components(buf, len); /* zero stale data in rest of space in data fork, if any */ if (zero_stale_data && len < XFS_DFORK_DSIZE(dip, mp)) memset(&buf[len], 0, XFS_DFORK_DSIZE(dip, mp) - len); } static void process_sf_attr( xfs_dinode_t *dip) { /* * with extended attributes, obfuscate the names and fill the actual * values with 'v' (to see a valid string length, as opposed to NULLs) */ xfs_attr_shortform_t *asfp; xfs_attr_sf_entry_t *asfep; int ino_attr_size; int i; asfp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); if (asfp->hdr.count == 0) return; ino_attr_size = be16_to_cpu(asfp->hdr.totsize); if (ino_attr_size > XFS_DFORK_ASIZE(dip, mp)) { ino_attr_size = XFS_DFORK_ASIZE(dip, mp); if (show_warnings) print_warning("invalid attr size in inode %llu", (long long)cur_ino); } asfep = &asfp->list[0]; for (i = 0; (i < asfp->hdr.count) && ((char *)asfep - (char *)asfp < ino_attr_size); i++) { int namelen = asfep->namelen; if (namelen == 0) { if (show_warnings) print_warning("zero length attr entry in inode " "%llu", (long long)cur_ino); break; } else if ((char *)asfep - (char *)asfp + XFS_ATTR_SF_ENTSIZE(asfep) > ino_attr_size) { if (show_warnings) print_warning("attr entry length in inode %llu " "overflows space", (long long)cur_ino); break; } if (obfuscate) { generate_obfuscated_name(0, asfep->namelen, &asfep->nameval[0]); memset(&asfep->nameval[asfep->namelen], 'v', asfep->valuelen); } asfep = (xfs_attr_sf_entry_t *)((char *)asfep + XFS_ATTR_SF_ENTSIZE(asfep)); } /* zero stale data in rest of space in attr fork, if any */ if (zero_stale_data && (ino_attr_size < XFS_DFORK_ASIZE(dip, mp))) memset(asfep, 0, XFS_DFORK_ASIZE(dip, mp) - ino_attr_size); } static void process_dir_free_block( char *block) { struct xfs_dir2_free *free; struct xfs_dir3_icfree_hdr freehdr; if (!zero_stale_data) return; free = (struct xfs_dir2_free *)block; M_DIROPS(mp)->free_hdr_from_disk(&freehdr, free); switch (freehdr.magic) { case XFS_DIR2_FREE_MAGIC: case XFS_DIR3_FREE_MAGIC: { __be16 *bests; char *high; int used; /* Zero out space from end of bests[] to end of block */ bests = M_DIROPS(mp)->free_bests_p(free); high = (char *)&bests[freehdr.nvalid]; used = high - (char*)free; memset(high, 0, mp->m_dir_geo->blksize - used); iocur_top->need_crc = 1; break; } default: if (show_warnings) print_warning("invalid magic in dir inode %llu " "free block", (unsigned long long)cur_ino); break; } } static void process_dir_leaf_block( char *block) { struct xfs_dir2_leaf *leaf; struct xfs_dir3_icleaf_hdr leafhdr; if (!zero_stale_data) return; /* Yes, this works for dir2 & dir3. Difference is padding. */ leaf = (struct xfs_dir2_leaf *)block; M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf); switch (leafhdr.magic) { case XFS_DIR2_LEAF1_MAGIC: case XFS_DIR3_LEAF1_MAGIC: { struct xfs_dir2_leaf_tail *ltp; __be16 *lbp; struct xfs_dir2_leaf_entry *ents; char *free; /* end of ents */ /* Zero out space from end of ents[] to bests */ ents = M_DIROPS(mp)->leaf_ents_p(leaf); free = (char *)&ents[leafhdr.count]; ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); lbp = xfs_dir2_leaf_bests_p(ltp); memset(free, 0, (char *)lbp - free); iocur_top->need_crc = 1; break; } case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: { struct xfs_dir2_leaf_entry *ents; char *free; int used; /* Zero out space from end of ents[] to end of block */ ents = M_DIROPS(mp)->leaf_ents_p(leaf); free = (char *)&ents[leafhdr.count]; used = free - (char*)leaf; memset(free, 0, mp->m_dir_geo->blksize - used); iocur_top->need_crc = 1; break; } default: break; } } static void process_dir_data_block( char *block, xfs_fileoff_t offset, int is_block_format) { /* * we have to rely on the fileoffset and signature of the block to * handle it's contents. If it's invalid, leave it alone. * for multi-fsblock dir blocks, if a name crosses an extent boundary, * ignore it and continue. */ int dir_offset; char *ptr; char *endptr; int end_of_data; int wantmagic; struct xfs_dir2_data_hdr *datahdr; datahdr = (struct xfs_dir2_data_hdr *)block; if (is_block_format) { xfs_dir2_leaf_entry_t *blp; xfs_dir2_block_tail_t *btp; btp = xfs_dir2_block_tail_p(mp->m_dir_geo, datahdr); blp = xfs_dir2_block_leaf_p(btp); if ((char *)blp > (char *)btp) blp = (xfs_dir2_leaf_entry_t *)btp; end_of_data = (char *)blp - block; if (xfs_sb_version_hascrc(&mp->m_sb)) wantmagic = XFS_DIR3_BLOCK_MAGIC; else wantmagic = XFS_DIR2_BLOCK_MAGIC; } else { /* leaf/node format */ end_of_data = mp->m_dir_geo->fsbcount << mp->m_sb.sb_blocklog; if (xfs_sb_version_hascrc(&mp->m_sb)) wantmagic = XFS_DIR3_DATA_MAGIC; else wantmagic = XFS_DIR2_DATA_MAGIC; } if (be32_to_cpu(datahdr->magic) != wantmagic) { if (show_warnings) print_warning( "invalid magic in dir inode %llu block %ld", (unsigned long long)cur_ino, (long)offset); return; } dir_offset = M_DIROPS(mp)->data_entry_offset; ptr = block + dir_offset; endptr = block + mp->m_dir_geo->blksize; while (ptr < endptr && dir_offset < end_of_data) { xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; int length; dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { int free_length = be16_to_cpu(dup->length); if (dir_offset + free_length > end_of_data || !free_length || (free_length & (XFS_DIR2_DATA_ALIGN - 1))) { if (show_warnings) print_warning( "invalid length for dir free space in inode %llu", (long long)cur_ino); return; } if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) != dir_offset) return; dir_offset += free_length; ptr += free_length; /* * Zero the unused space up to the tag - the tag is * actually at a variable offset, so zeroing &dup->tag * is zeroing the free space in between */ if (zero_stale_data) { int zlen = free_length - sizeof(xfs_dir2_data_unused_t); if (zlen > 0) { memset(&dup->tag, 0, zlen); iocur_top->need_crc = 1; } } if (dir_offset >= end_of_data || ptr >= endptr) return; } dep = (xfs_dir2_data_entry_t *)ptr; length = M_DIROPS(mp)->data_entsize(dep->namelen); if (dir_offset + length > end_of_data || ptr + length > endptr) { if (show_warnings) print_warning( "invalid length for dir entry name in inode %llu", (long long)cur_ino); return; } if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) != dir_offset) return; if (obfuscate) generate_obfuscated_name(be64_to_cpu(dep->inumber), dep->namelen, &dep->name[0]); dir_offset += length; ptr += length; /* Zero the unused space after name, up to the tag */ if (zero_stale_data) { /* 1 byte for ftype; don't bother with conditional */ int zlen = (char *)M_DIROPS(mp)->data_entry_tag_p(dep) - (char *)&dep->name[dep->namelen] - 1; if (zlen > 0) { memset(&dep->name[dep->namelen] + 1, 0, zlen); iocur_top->need_crc = 1; } } } } static int process_symlink_block( xfs_fileoff_t o, xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, xfs_fileoff_t last) { struct bbmap map; char *link; int ret = 0; push_cur(); map.nmaps = 1; map.b[0].bm_bn = XFS_FSB_TO_DADDR(mp, s); map.b[0].bm_len = XFS_FSB_TO_BB(mp, c); set_cur(&typtab[btype], 0, 0, DB_RING_IGN, &map); if (!iocur_top->data) { xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, s); xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, s); print_warning("cannot read %s block %u/%u (%llu)", typtab[btype].name, agno, agbno, s); if (stop_on_read_error) ret = -1; goto out_pop; } link = iocur_top->data; if (xfs_sb_version_hascrc(&(mp)->m_sb)) link += sizeof(struct xfs_dsymlink_hdr); if (obfuscate) obfuscate_path_components(link, XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize)); if (zero_stale_data) { size_t linklen, zlen; linklen = strlen(link); zlen = mp->m_sb.sb_blocksize - linklen; if (xfs_sb_version_hascrc(&mp->m_sb)) zlen -= sizeof(struct xfs_dsymlink_hdr); if (zlen < mp->m_sb.sb_blocksize) memset(link + linklen, 0, zlen); } iocur_top->need_crc = 1; ret = write_buf(iocur_top); out_pop: pop_cur(); return ret; } #define MAX_REMOTE_VALS 4095 static struct attr_data_s { int remote_val_count; xfs_dablk_t remote_vals[MAX_REMOTE_VALS]; } attr_data; static inline void add_remote_vals( xfs_dablk_t blockidx, int length) { while (length > 0 && attr_data.remote_val_count < MAX_REMOTE_VALS) { attr_data.remote_vals[attr_data.remote_val_count] = blockidx; attr_data.remote_val_count++; blockidx++; length -= XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); } if (attr_data.remote_val_count >= MAX_REMOTE_VALS) { print_warning( "Overflowed attr obfuscation array. No longer obfuscating remote attrs."); } } /* Handle remote and leaf attributes */ static void process_attr_block( char *block, xfs_fileoff_t offset) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr hdr; int i; int nentries; xfs_attr_leaf_entry_t *entry; xfs_attr_leaf_name_local_t *local; xfs_attr_leaf_name_remote_t *remote; uint32_t bs = mp->m_sb.sb_blocksize; char *first_name; leaf = (xfs_attr_leafblock_t *)block; /* Remote attributes - attr3 has XFS_ATTR3_RMT_MAGIC, attr has none */ if ((be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) && (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR3_LEAF_MAGIC)) { for (i = 0; i < attr_data.remote_val_count; i++) { if (obfuscate && attr_data.remote_vals[i] == offset) /* Macros to handle both attr and attr3 */ memset(block + (bs - XFS_ATTR3_RMT_BUF_SPACE(mp, bs)), 'v', XFS_ATTR3_RMT_BUF_SPACE(mp, bs)); } return; } /* Ok, it's a leaf - get header; accounts for crc & non-crc */ xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &hdr, leaf); nentries = hdr.count; if (nentries == 0 || nentries * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf) > XFS_ATTR3_RMT_BUF_SPACE(mp, bs)) { if (show_warnings) print_warning("invalid attr count in inode %llu", (long long)cur_ino); return; } entry = xfs_attr3_leaf_entryp(leaf); /* We will move this as we parse */ first_name = NULL; for (i = 0; i < nentries; i++, entry++) { int nlen, vlen, zlen; /* Grows up; if this name is topmost, move first_name */ if (!first_name || xfs_attr3_leaf_name(leaf, i) < first_name) first_name = xfs_attr3_leaf_name(leaf, i); if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) { if (show_warnings) print_warning( "invalid attr nameidx in inode %llu", (long long)cur_ino); break; } if (entry->flags & XFS_ATTR_LOCAL) { local = xfs_attr3_leaf_name_local(leaf, i); if (local->namelen == 0) { if (show_warnings) print_warning( "zero length for attr name in inode %llu", (long long)cur_ino); break; } if (obfuscate) { generate_obfuscated_name(0, local->namelen, &local->nameval[0]); memset(&local->nameval[local->namelen], 'v', be16_to_cpu(local->valuelen)); } /* zero from end of nameval[] to next name start */ nlen = local->namelen; vlen = be16_to_cpu(local->valuelen); zlen = xfs_attr_leaf_entsize_local(nlen, vlen) - (sizeof(xfs_attr_leaf_name_local_t) - 1 + nlen + vlen); if (zero_stale_data) memset(&local->nameval[nlen + vlen], 0, zlen); } else { remote = xfs_attr3_leaf_name_remote(leaf, i); if (remote->namelen == 0 || remote->valueblk == 0) { if (show_warnings) print_warning( "invalid attr entry in inode %llu", (long long)cur_ino); break; } if (obfuscate) { generate_obfuscated_name(0, remote->namelen, &remote->name[0]); add_remote_vals(be32_to_cpu(remote->valueblk), be32_to_cpu(remote->valuelen)); } /* zero from end of name[] to next name start */ nlen = remote->namelen; zlen = xfs_attr_leaf_entsize_remote(nlen) - (sizeof(xfs_attr_leaf_name_remote_t) - 1 + nlen); if (zero_stale_data) memset(&remote->name[nlen], 0, zlen); } } /* Zero from end of entries array to the first name/val */ if (zero_stale_data) { struct xfs_attr_leaf_entry *entries; entries = xfs_attr3_leaf_entryp(leaf); memset(&entries[nentries], 0, first_name - (char *)&entries[nentries]); } } /* Processes symlinks, attrs, directories ... */ static int process_single_fsb_objects( xfs_fileoff_t o, xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, xfs_fileoff_t last) { char *dp; int ret = 0; int i; for (i = 0; i < c; i++) { push_cur(); set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), blkbb, DB_RING_IGN, NULL); if (!iocur_top->data) { xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, s); xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, s); print_warning("cannot read %s block %u/%u (%llu)", typtab[btype].name, agno, agbno, s); if (stop_on_read_error) ret = -EIO; goto out_pop; } if (!obfuscate && !zero_stale_data) goto write; /* Zero unused part of interior nodes */ if (zero_stale_data) { xfs_da_intnode_t *node = iocur_top->data; int magic = be16_to_cpu(node->hdr.info.magic); if (magic == XFS_DA_NODE_MAGIC || magic == XFS_DA3_NODE_MAGIC) { struct xfs_da3_icnode_hdr hdr; int used; M_DIROPS(mp)->node_hdr_from_disk(&hdr, node); used = M_DIROPS(mp)->node_hdr_size; used += hdr.count * sizeof(struct xfs_da_node_entry); if (used < mp->m_sb.sb_blocksize) { memset((char *)node + used, 0, mp->m_sb.sb_blocksize - used); iocur_top->need_crc = 1; } } } /* Handle leaf nodes */ dp = iocur_top->data; switch (btype) { case TYP_DIR2: if (o >= mp->m_dir_geo->freeblk) { process_dir_free_block(dp); } else if (o >= mp->m_dir_geo->leafblk) { process_dir_leaf_block(dp); } else { process_dir_data_block(dp, o, last == mp->m_dir_geo->fsbcount); } iocur_top->need_crc = 1; break; case TYP_ATTR: process_attr_block(dp, o); iocur_top->need_crc = 1; break; default: break; } write: ret = write_buf(iocur_top); out_pop: pop_cur(); if (ret) break; o++; s++; } return ret; } /* * Static map to aggregate multiple extents into a single directory block. */ static struct bbmap mfsb_map; static int mfsb_length; static int process_multi_fsb_dir( xfs_fileoff_t o, xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, xfs_fileoff_t last) { char *dp; int ret = 0; while (c > 0) { unsigned int bm_len; if (mfsb_length + c >= mp->m_dir_geo->fsbcount) { bm_len = mp->m_dir_geo->fsbcount - mfsb_length; mfsb_length = 0; } else { mfsb_length += c; bm_len = c; } mfsb_map.b[mfsb_map.nmaps].bm_bn = XFS_FSB_TO_DADDR(mp, s); mfsb_map.b[mfsb_map.nmaps].bm_len = XFS_FSB_TO_BB(mp, bm_len); mfsb_map.nmaps++; if (mfsb_length == 0) { push_cur(); set_cur(&typtab[btype], 0, 0, DB_RING_IGN, &mfsb_map); if (!iocur_top->data) { xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, s); xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, s); print_warning("cannot read %s block %u/%u (%llu)", typtab[btype].name, agno, agbno, s); if (stop_on_read_error) ret = -1; goto out_pop; } if (!obfuscate && !zero_stale_data) goto write; dp = iocur_top->data; if (o >= mp->m_dir_geo->freeblk) { process_dir_free_block(dp); } else if (o >= mp->m_dir_geo->leafblk) { process_dir_leaf_block(dp); } else { process_dir_data_block(dp, o, last == mp->m_dir_geo->fsbcount); } iocur_top->need_crc = 1; write: ret = write_buf(iocur_top); out_pop: pop_cur(); mfsb_map.nmaps = 0; if (ret) break; } c -= bm_len; s += bm_len; } return ret; } static bool is_multi_fsb_object( struct xfs_mount *mp, typnm_t btype) { if (btype == TYP_DIR2 && mp->m_dir_geo->fsbcount > 1) return true; if (btype == TYP_SYMLINK) return true; return false; } static int process_multi_fsb_objects( xfs_fileoff_t o, xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, xfs_fileoff_t last) { switch (btype) { case TYP_DIR2: return process_multi_fsb_dir(o, s, c, btype, last); case TYP_SYMLINK: return process_symlink_block(o, s, c, btype, last); default: print_warning("bad type for multi-fsb object %d", btype); return -EINVAL; } } /* inode copy routines */ static int process_bmbt_reclist( xfs_bmbt_rec_t *rp, int numrecs, typnm_t btype) { int i; xfs_fileoff_t o, op = NULLFILEOFF; xfs_fsblock_t s; xfs_filblks_t c, cp = NULLFILEOFF; int f; xfs_fileoff_t last; xfs_agnumber_t agno; xfs_agblock_t agbno; bool is_multi_fsb = is_multi_fsb_object(mp, btype); int error; if (btype == TYP_DATA) return 1; convert_extent(&rp[numrecs - 1], &o, &s, &c, &f); last = o + c; for (i = 0; i < numrecs; i++, rp++) { convert_extent(rp, &o, &s, &c, &f); /* * ignore extents that are clearly bogus, and if a bogus * one is found, stop processing remaining extents */ if (i > 0 && op + cp > o) { if (show_warnings) print_warning("bmap extent %d in %s ino %llu " "starts at %llu, previous extent " "ended at %llu", i, typtab[btype].name, (long long)cur_ino, o, op + cp - 1); break; } if (c > max_extent_size) { /* * since we are only processing non-data extents, * large numbers of blocks in a metadata extent is * extremely rare and more than likely to be corrupt. */ if (show_warnings) print_warning("suspicious count %u in bmap " "extent %d in %s ino %llu", c, i, typtab[btype].name, (long long)cur_ino); break; } op = o; cp = c; agno = XFS_FSB_TO_AGNO(mp, s); agbno = XFS_FSB_TO_AGBNO(mp, s); if (!valid_bno(agno, agbno)) { if (show_warnings) print_warning("invalid block number %u/%u " "(%llu) in bmap extent %d in %s ino " "%llu", agno, agbno, s, i, typtab[btype].name, (long long)cur_ino); break; } if (!valid_bno(agno, agbno + c - 1)) { if (show_warnings) print_warning("bmap extent %i in %s inode %llu " "overflows AG (end is %u/%u)", i, typtab[btype].name, (long long)cur_ino, agno, agbno + c - 1); break; } /* multi-extent blocks require special handling */ if (is_multi_fsb) error = process_multi_fsb_objects(o, s, c, btype, last); else error = process_single_fsb_objects(o, s, c, btype, last); if (error) return 0; } return 1; } static int scanfunc_bmap( struct xfs_btree_block *block, xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg) /* ptr to itype */ { int i; xfs_bmbt_ptr_t *pp; int nrecs; nrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (nrecs > mp->m_bmap_dmxr[0]) { if (show_warnings) print_warning("invalid numrecs (%u) in %s " "block %u/%u", nrecs, typtab[btype].name, agno, agbno); return 1; } return process_bmbt_reclist(XFS_BMBT_REC_ADDR(mp, block, 1), nrecs, *(typnm_t*)arg); } if (nrecs > mp->m_bmap_dmxr[1]) { if (show_warnings) print_warning("invalid numrecs (%u) in %s block %u/%u", nrecs, typtab[btype].name, agno, agbno); return 1; } pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); for (i = 0; i < nrecs; i++) { xfs_agnumber_t ag; xfs_agblock_t bno; ag = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i])); bno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i])); if (bno == 0 || bno > mp->m_sb.sb_agblocks || ag > mp->m_sb.sb_agcount) { if (show_warnings) print_warning("invalid block number (%u/%u) " "in %s block %u/%u", ag, bno, typtab[btype].name, agno, agbno); continue; } if (!scan_btree(ag, bno, level, btype, arg, scanfunc_bmap)) return 0; } return 1; } static int process_btinode( xfs_dinode_t *dip, typnm_t itype) { xfs_bmdr_block_t *dib; int i; xfs_bmbt_ptr_t *pp; int level; int nrecs; int maxrecs; int whichfork; typnm_t btype; whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK; btype = (itype == TYP_ATTR) ? TYP_BMAPBTA : TYP_BMAPBTD; dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); level = be16_to_cpu(dib->bb_level); nrecs = be16_to_cpu(dib->bb_numrecs); if (level > XFS_BM_MAXLEVELS(mp, whichfork)) { if (show_warnings) print_warning("invalid level (%u) in inode %lld %s " "root", level, (long long)cur_ino, typtab[btype].name); return 1; } if (level == 0) { return process_bmbt_reclist(XFS_BMDR_REC_ADDR(dib, 1), nrecs, itype); } maxrecs = libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0); if (nrecs > maxrecs) { if (show_warnings) print_warning("invalid numrecs (%u) in inode %lld %s " "root", nrecs, (long long)cur_ino, typtab[btype].name); return 1; } pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs); if (zero_stale_data) { char *top; /* Unused btree key space */ top = (char*)XFS_BMDR_KEY_ADDR(dib, nrecs + 1); memset(top, 0, (char*)pp - top); /* Unused btree ptr space */ top = (char*)&pp[nrecs]; memset(top, 0, (char*)dib + XFS_DFORK_SIZE(dip, mp, whichfork) - top); } for (i = 0; i < nrecs; i++) { xfs_agnumber_t ag; xfs_agblock_t bno; ag = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i])); bno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i])); if (bno == 0 || bno > mp->m_sb.sb_agblocks || ag > mp->m_sb.sb_agcount) { if (show_warnings) print_warning("invalid block number (%u/%u) " "in inode %llu %s root", ag, bno, (long long)cur_ino, typtab[btype].name); continue; } if (!scan_btree(ag, bno, level, btype, &itype, scanfunc_bmap)) return 0; } return 1; } static int process_exinode( xfs_dinode_t *dip, typnm_t itype) { int whichfork; int used; xfs_extnum_t nex; whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK; nex = XFS_DFORK_NEXTENTS(dip, whichfork); used = nex * sizeof(xfs_bmbt_rec_t); if (nex < 0 || used > XFS_DFORK_SIZE(dip, mp, whichfork)) { if (show_warnings) print_warning("bad number of extents %d in inode %lld", nex, (long long)cur_ino); return 1; } /* Zero unused data fork past used extents */ if (zero_stale_data && (used < XFS_DFORK_SIZE(dip, mp, whichfork))) memset(XFS_DFORK_PTR(dip, whichfork) + used, 0, XFS_DFORK_SIZE(dip, mp, whichfork) - used); return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork), nex, itype); } static int process_inode_data( xfs_dinode_t *dip, typnm_t itype) { switch (dip->di_format) { case XFS_DINODE_FMT_LOCAL: if (obfuscate || zero_stale_data) switch (itype) { case TYP_DIR2: process_sf_dir(dip); break; case TYP_SYMLINK: process_sf_symlink(dip); break; default: ; } break; case XFS_DINODE_FMT_EXTENTS: return process_exinode(dip, itype); case XFS_DINODE_FMT_BTREE: return process_btinode(dip, itype); } return 1; } static int process_dev_inode( xfs_dinode_t *dip) { if (XFS_DFORK_NEXTENTS(dip, XFS_DATA_FORK)) { if (show_warnings) print_warning("inode %llu has unexpected extents", (unsigned long long)cur_ino); return 0; } else { if (zero_stale_data) { unsigned int size = sizeof(xfs_dev_t); memset(XFS_DFORK_DPTR(dip) + size, 0, XFS_DFORK_DSIZE(dip, mp) - size); } return 1; } } /* * when we process the inode, we may change the data in the data and/or * attribute fork if they are in short form and we are obfuscating names. * In this case we need to recalculate the CRC of the inode, but we should * only do that if the CRC in the inode is good to begin with. If the crc * is not ok, we just leave it alone. */ static int process_inode( xfs_agnumber_t agno, xfs_agino_t agino, xfs_dinode_t *dip, bool free_inode) { int success; bool crc_was_ok = false; /* no recalc by default */ bool need_new_crc = false; success = 1; cur_ino = XFS_AGINO_TO_INO(mp, agno, agino); /* we only care about crc recalculation if we will modify the inode. */ if (obfuscate || zero_stale_data) { crc_was_ok = libxfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, offsetof(struct xfs_dinode, di_crc)); } if (free_inode) { if (zero_stale_data) { /* Zero all of the inode literal area */ memset(XFS_DFORK_DPTR(dip), 0, XFS_LITINO(mp, dip->di_version)); } goto done; } /* copy appropriate data fork metadata */ switch (be16_to_cpu(dip->di_mode) & S_IFMT) { case S_IFDIR: success = process_inode_data(dip, TYP_DIR2); if (dip->di_format == XFS_DINODE_FMT_LOCAL) need_new_crc = 1; break; case S_IFLNK: success = process_inode_data(dip, TYP_SYMLINK); if (dip->di_format == XFS_DINODE_FMT_LOCAL) need_new_crc = 1; break; case S_IFREG: success = process_inode_data(dip, TYP_DATA); break; case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: success = process_dev_inode(dip); need_new_crc = 1; break; default: break; } nametable_clear(); /* copy extended attributes if they exist and forkoff is valid */ if (success && XFS_DFORK_DSIZE(dip, mp) < XFS_LITINO(mp, dip->di_version)) { attr_data.remote_val_count = 0; switch (dip->di_aformat) { case XFS_DINODE_FMT_LOCAL: need_new_crc = 1; if (obfuscate || zero_stale_data) process_sf_attr(dip); break; case XFS_DINODE_FMT_EXTENTS: success = process_exinode(dip, TYP_ATTR); break; case XFS_DINODE_FMT_BTREE: success = process_btinode(dip, TYP_ATTR); break; } nametable_clear(); } done: /* Heavy handed but low cost; just do it as a catch-all. */ if (zero_stale_data) need_new_crc = 1; if (crc_was_ok && need_new_crc) libxfs_dinode_calc_crc(mp, dip); return success; } static uint32_t inodes_copied; static int copy_inode_chunk( xfs_agnumber_t agno, xfs_inobt_rec_t *rp) { xfs_agino_t agino; int off; xfs_agblock_t agbno; xfs_agblock_t end_agbno; int i; int rval = 0; int blks_per_buf; int inodes_per_buf; int ioff; struct xfs_ino_geometry *igeo = M_IGEO(mp); agino = be32_to_cpu(rp->ir_startino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); end_agbno = agbno + igeo->ialloc_blks; off = XFS_INO_TO_OFFSET(mp, agino); /* * If the fs supports sparse inode records, we must process inodes a * cluster at a time because that is the sparse allocation granularity. * Otherwise, we risk CRC corruption errors on reads of inode chunks. * * Also make sure that that we don't process more than the single record * we've been passed (large block sizes can hold multiple inode chunks). */ if (xfs_sb_version_hassparseinodes(&mp->m_sb)) blks_per_buf = igeo->blocks_per_cluster; else blks_per_buf = igeo->ialloc_blks; inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf), XFS_INODES_PER_CHUNK); /* * Sanity check that we only process a single buffer if ir_startino has * a buffer offset. A non-zero offset implies that the entire chunk lies * within a block. */ if (off && inodes_per_buf != XFS_INODES_PER_CHUNK) { print_warning("bad starting inode offset %d", off); return 0; } if (agino == 0 || agino == NULLAGINO || !valid_bno(agno, agbno) || !valid_bno(agno, XFS_AGINO_TO_AGBNO(mp, agino + XFS_INODES_PER_CHUNK - 1))) { if (show_warnings) print_warning("bad inode number %llu (%u/%u)", XFS_AGINO_TO_INO(mp, agno, agino), agno, agino); return 1; } /* * check for basic assumptions about inode chunks, and if any * assumptions fail, don't process the inode chunk. */ if ((mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && off != 0) || (mp->m_sb.sb_inopblock > XFS_INODES_PER_CHUNK && off % XFS_INODES_PER_CHUNK != 0) || (xfs_sb_version_hasalign(&mp->m_sb) && mp->m_sb.sb_inoalignmt != 0 && agbno % mp->m_sb.sb_inoalignmt != 0)) { if (show_warnings) print_warning("badly aligned inode (start = %llu)", XFS_AGINO_TO_INO(mp, agno, agino)); return 1; } push_cur(); ioff = 0; while (agbno < end_agbno && ioff < XFS_INODES_PER_CHUNK) { if (xfs_inobt_is_sparse_disk(rp, ioff)) goto next_bp; set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, blks_per_buf), DB_RING_IGN, NULL); if (iocur_top->data == NULL) { print_warning("cannot read inode block %u/%u", agno, agbno); rval = !stop_on_read_error; goto pop_out; } for (i = 0; i < inodes_per_buf; i++) { xfs_dinode_t *dip; dip = (xfs_dinode_t *)((char *)iocur_top->data + ((off + i) << mp->m_sb.sb_inodelog)); /* process_inode handles free inodes, too */ if (!process_inode(agno, agino + ioff + i, dip, XFS_INOBT_IS_FREE_DISK(rp, ioff + i))) goto pop_out; inodes_copied++; } if (write_buf(iocur_top)) goto pop_out; next_bp: agbno += blks_per_buf; ioff += inodes_per_buf; } if (show_progress) print_progress("Copied %u of %u inodes (%u of %u AGs)", inodes_copied, mp->m_sb.sb_icount, agno, mp->m_sb.sb_agcount); rval = 1; pop_out: pop_cur(); return rval; } static int scanfunc_ino( struct xfs_btree_block *block, xfs_agnumber_t agno, xfs_agblock_t agbno, int level, typnm_t btype, void *arg) { xfs_inobt_rec_t *rp; xfs_inobt_ptr_t *pp; int i; int numrecs; int finobt = *(int *) arg; struct xfs_ino_geometry *igeo = M_IGEO(mp); numrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (numrecs > igeo->inobt_mxr[0]) { if (show_warnings) print_warning("invalid numrecs %d in %s " "block %u/%u", numrecs, typtab[btype].name, agno, agbno); numrecs = igeo->inobt_mxr[0]; } /* * Only copy the btree blocks for the finobt. The inobt scan * copies the inode chunks. */ if (finobt) return 1; rp = XFS_INOBT_REC_ADDR(mp, block, 1); for (i = 0; i < numrecs; i++, rp++) { if (!copy_inode_chunk(agno, rp)) return 0; } return 1; } if (numrecs > igeo->inobt_mxr[1]) { if (show_warnings) print_warning("invalid numrecs %d in %s block %u/%u", numrecs, typtab[btype].name, agno, agbno); numrecs = igeo->inobt_mxr[1]; } pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); for (i = 0; i < numrecs; i++) { if (!valid_bno(agno, be32_to_cpu(pp[i]))) { if (show_warnings) print_warning("invalid block number (%u/%u) " "in %s block %u/%u", agno, be32_to_cpu(pp[i]), typtab[btype].name, agno, agbno); continue; } if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg, scanfunc_ino)) return 0; } return 1; } static int copy_inodes( xfs_agnumber_t agno, xfs_agi_t *agi) { xfs_agblock_t root; int levels; int finobt = 0; root = be32_to_cpu(agi->agi_root); levels = be32_to_cpu(agi->agi_level); /* validate root and levels before processing the tree */ if (root == 0 || root > mp->m_sb.sb_agblocks) { if (show_warnings) print_warning("invalid block number (%u) in inobt " "root in agi %u", root, agno); return 1; } if (levels >= XFS_BTREE_MAXLEVELS) { if (show_warnings) print_warning("invalid level (%u) in inobt root " "in agi %u", levels, agno); return 1; } if (!scan_btree(agno, root, levels, TYP_INOBT, &finobt, scanfunc_ino)) return 0; if (xfs_sb_version_hasfinobt(&mp->m_sb)) { root = be32_to_cpu(agi->agi_free_root); levels = be32_to_cpu(agi->agi_free_level); finobt = 1; if (!scan_btree(agno, root, levels, TYP_FINOBT, &finobt, scanfunc_ino)) return 0; } return 1; } static int scan_ag( xfs_agnumber_t agno) { xfs_agf_t *agf; xfs_agi_t *agi; int stack_count = 0; int rval = 0; /* copy the superblock of the AG */ push_cur(); stack_count++; set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if (!iocur_top->data) { print_warning("cannot read superblock for ag %u", agno); if (stop_on_read_error) goto pop_out; } else { /* Replace any filesystem label with "L's" */ if (obfuscate) { struct xfs_sb *sb = iocur_top->data; memset(sb->sb_fname, 'L', min(strlen(sb->sb_fname), sizeof(sb->sb_fname))); iocur_top->need_crc = 1; } if (write_buf(iocur_top)) goto pop_out; } /* copy the AG free space btree root */ push_cur(); stack_count++; set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); agf = iocur_top->data; if (iocur_top->data == NULL) { print_warning("cannot read agf block for ag %u", agno); if (stop_on_read_error) goto pop_out; } else { if (write_buf(iocur_top)) goto pop_out; } /* copy the AG inode btree root */ push_cur(); stack_count++; set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); agi = iocur_top->data; if (iocur_top->data == NULL) { print_warning("cannot read agi block for ag %u", agno); if (stop_on_read_error) goto pop_out; } else { if (write_buf(iocur_top)) goto pop_out; } /* copy the AG free list header */ push_cur(); stack_count++; set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if (iocur_top->data == NULL) { print_warning("cannot read agfl block for ag %u", agno); if (stop_on_read_error) goto pop_out; } else { if (agf && zero_stale_data) { /* Zero out unused bits of agfl */ int i; __be32 *agfl_bno; agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, iocur_top->bp); i = be32_to_cpu(agf->agf_fllast); for (;;) { if (++i == libxfs_agfl_size(mp)) i = 0; if (i == be32_to_cpu(agf->agf_flfirst)) break; agfl_bno[i] = cpu_to_be32(NULLAGBLOCK); } iocur_top->need_crc = 1; } if (write_buf(iocur_top)) goto pop_out; } /* copy AG free space btrees */ if (agf) { if (show_progress) print_progress("Copying free space trees of AG %u", agno); if (!copy_free_bno_btree(agno, agf)) goto pop_out; if (!copy_free_cnt_btree(agno, agf)) goto pop_out; if (!copy_rmap_btree(agno, agf)) goto pop_out; if (!copy_refcount_btree(agno, agf)) goto pop_out; } /* copy inode btrees and the inodes and their associated metadata */ if (agi) { if (!copy_inodes(agno, agi)) goto pop_out; } rval = 1; pop_out: while (stack_count--) pop_cur(); return rval; } static int copy_ino( xfs_ino_t ino, typnm_t itype) { xfs_agnumber_t agno; xfs_agblock_t agbno; xfs_agino_t agino; int offset; int rval = 0; if (ino == 0 || ino == NULLFSINO) return 1; agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); offset = XFS_AGINO_TO_OFFSET(mp, agino); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || offset >= mp->m_sb.sb_inopblock) { if (show_warnings) print_warning("invalid %s inode number (%lld)", typtab[itype].name, (long long)ino); return 1; } push_cur(); set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { print_warning("cannot read %s inode %lld", typtab[itype].name, (long long)ino); rval = !stop_on_read_error; goto pop_out; } off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize); cur_ino = ino; rval = process_inode_data(iocur_top->data, itype); pop_out: pop_cur(); return rval; } static int copy_sb_inodes(void) { if (!copy_ino(mp->m_sb.sb_rbmino, TYP_RTBITMAP)) return 0; if (!copy_ino(mp->m_sb.sb_rsumino, TYP_RTSUMMARY)) return 0; if (!copy_ino(mp->m_sb.sb_uquotino, TYP_DQBLK)) return 0; if (!copy_ino(mp->m_sb.sb_gquotino, TYP_DQBLK)) return 0; return copy_ino(mp->m_sb.sb_pquotino, TYP_DQBLK); } static int copy_log(void) { struct xlog log; int dirty; xfs_daddr_t logstart; int logblocks; int logversion; int cycle = XLOG_INIT_CYCLE; if (show_progress) print_progress("Copying log"); push_cur(); set_cur(&typtab[TYP_LOG], XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL); if (iocur_top->data == NULL) { pop_cur(); print_warning("cannot read log"); return !stop_on_read_error; } /* If not obfuscating or zeroing, just copy the log as it is */ if (!obfuscate && !zero_stale_data) goto done; dirty = xlog_is_dirty(mp, &log, &x, 0); switch (dirty) { case 0: /* clear out a clean log */ if (show_progress) print_progress("Zeroing clean log"); logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); logblocks = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); logversion = xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1; if (xfs_sb_version_hascrc(&mp->m_sb)) cycle = log.l_curr_cycle + 1; libxfs_log_clear(NULL, iocur_top->data, logstart, logblocks, &mp->m_sb.sb_uuid, logversion, mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true); break; case 1: /* keep the dirty log */ if (obfuscate) print_warning( _("Warning: log recovery of an obfuscated metadata image can leak " "unobfuscated metadata and/or cause image corruption. If possible, " "please mount the filesystem to clean the log, or disable obfuscation.")); break; case -1: /* log detection error */ if (obfuscate) print_warning( _("Could not discern log; image will contain unobfuscated metadata in log.")); break; } done: return !write_buf(iocur_top); } static int metadump_f( int argc, char **argv) { xfs_agnumber_t agno; int c; int start_iocur_sp; int outfd = -1; int ret; char *p; exitcode = 1; show_progress = 0; show_warnings = 0; stop_on_read_error = 0; if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) { print_warning("bad superblock magic number %x, giving up", mp->m_sb.sb_magicnum); return 0; } /* * on load, we sanity-checked agcount and possibly set to 1 * if it was corrupted and large. */ if (mp->m_sb.sb_agcount == 1 && XFS_MAX_DBLOCKS(&mp->m_sb) < mp->m_sb.sb_dblocks) { print_warning("truncated agcount, giving up"); return 0; } while ((c = getopt(argc, argv, "aegm:ow")) != EOF) { switch (c) { case 'a': zero_stale_data = 0; break; case 'e': stop_on_read_error = 1; break; case 'g': show_progress = 1; break; case 'm': max_extent_size = (int)strtol(optarg, &p, 0); if (*p != '\0' || max_extent_size <= 0) { print_warning("bad max extent size %s", optarg); return 0; } break; case 'o': obfuscate = 0; break; case 'w': show_warnings = 1; break; default: print_warning("bad option for metadump command"); return 0; } } if (optind != argc - 1) { print_warning("too few options for metadump (no filename given)"); return 0; } metablock = (xfs_metablock_t *)calloc(BBSIZE + 1, BBSIZE); if (metablock == NULL) { print_warning("memory allocation failure"); return 0; } metablock->mb_blocklog = BBSHIFT; metablock->mb_magic = cpu_to_be32(XFS_MD_MAGIC); /* Set flags about state of metadump */ metablock->mb_info = XFS_METADUMP_INFO_FLAGS; if (obfuscate) metablock->mb_info |= XFS_METADUMP_OBFUSCATED; if (!zero_stale_data) metablock->mb_info |= XFS_METADUMP_FULLBLOCKS; /* If we'll copy the log, see if the log is dirty */ if (mp->m_sb.sb_logstart) { push_cur(); set_cur(&typtab[TYP_LOG], XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL); if (iocur_top->data) { /* best effort */ struct xlog log; if (xlog_is_dirty(mp, &log, &x, 0)) metablock->mb_info |= XFS_METADUMP_DIRTYLOG; } pop_cur(); } block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t)); block_buffer = (char *)metablock + BBSIZE; num_indices = (BBSIZE - sizeof(xfs_metablock_t)) / sizeof(__be64); /* * A metadump block can hold at most num_indices of BBSIZE sectors; * do not try to dump a filesystem with a sector size which does not * fit within num_indices (i.e. within a single metablock). */ if (mp->m_sb.sb_sectsize > num_indices * BBSIZE) { print_warning("Cannot dump filesystem with sector size %u", mp->m_sb.sb_sectsize); free(metablock); return 0; } cur_index = 0; start_iocur_sp = iocur_sp; if (strcmp(argv[optind], "-") == 0) { if (isatty(fileno(stdout))) { print_warning("cannot write to a terminal"); free(metablock); return 0; } /* * Redirect stdout to stderr for the duration of the * metadump operation so that dbprintf and other messages * are sent to the console instead of polluting the * metadump stream. * * We get to do this the hard way because musl doesn't * allow reassignment of stdout. */ fflush(stdout); outfd = dup(STDOUT_FILENO); if (outfd < 0) { perror("opening dump stream"); goto out; } ret = dup2(STDERR_FILENO, STDOUT_FILENO); if (ret < 0) { perror("redirecting stdout"); close(outfd); goto out; } outf = fdopen(outfd, "a"); if (outf == NULL) { fprintf(stderr, "cannot create dump stream\n"); dup2(outfd, STDOUT_FILENO); close(outfd); goto out; } stdout_metadump = true; } else { outf = fopen(argv[optind], "wb"); if (outf == NULL) { print_warning("cannot create dump file"); goto out; } } exitcode = 0; for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { if (!scan_ag(agno)) { exitcode = 1; break; } } /* copy realtime and quota inode contents */ if (!exitcode) exitcode = !copy_sb_inodes(); /* copy log if it's internal */ if ((mp->m_sb.sb_logstart != 0) && !exitcode) exitcode = !copy_log(); /* write the remaining index */ if (!exitcode) exitcode = write_index() < 0; if (progress_since_warning) fputc('\n', stdout_metadump ? stderr : stdout); if (stdout_metadump) { fflush(outf); fflush(stdout); ret = dup2(outfd, STDOUT_FILENO); if (ret < 0) perror("un-redirecting stdout"); stdout_metadump = false; } fclose(outf); /* cleanup iocur stack */ while (iocur_sp > start_iocur_sp) pop_cur(); out: free(metablock); return 0; } xfsprogs-5.3.0/db/metadump.h0000644000175000017500000000022213435336036015620 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2007 Silicon Graphics, Inc. * All Rights Reserved. */ extern void metadump_init(void); xfsprogs-5.3.0/db/output.c0000644000175000017500000000336113435336036015346 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "command.h" #include "output.h" #include "sig.h" #include "malloc.h" #include "init.h" static int log_f(int argc, char **argv); static const cmdinfo_t log_cmd = { "log", NULL, log_f, 0, 2, 0, N_("[stop|start ]"), N_("start or stop logging to a file"), NULL }; int dbprefix; static FILE *log_file; static char *log_file_name; int dbprintf(const char *fmt, ...) { va_list ap; int i; if (seenint()) return 0; va_start(ap, fmt); blockint(); i = 0; if (dbprefix) i += printf("%s: ", fsdevice); i += vprintf(fmt, ap); unblockint(); va_end(ap); if (log_file) { va_start(ap, fmt); vfprintf(log_file, fmt, ap); va_end(ap); } return i; } static int log_f( int argc, char **argv) { if (argc == 1) { if (log_file) dbprintf(_("logging to %s\n"), log_file_name); else dbprintf(_("no log file\n")); } else if (argc == 2 && strcmp(argv[1], "stop") == 0) { if (log_file) { xfree(log_file_name); fclose(log_file); log_file = NULL; } else dbprintf(_("no log file\n")); } else if (argc == 3 && strcmp(argv[1], "start") == 0) { if (log_file) dbprintf(_("already logging to %s\n"), log_file_name); else { log_file = fopen(argv[2], "a"); if (log_file == NULL) dbprintf(_("can't open %s for writing\n"), argv[2]); else log_file_name = xstrdup(argv[1]); } } else dbprintf(_("bad log command, ignored\n")); return 0; } void logprintf(const char *fmt, ...) { va_list ap; if (log_file) { va_start(ap, fmt); (void)vfprintf(log_file, fmt, ap); va_end(ap); } } void output_init(void) { add_command(&log_cmd); } xfsprogs-5.3.0/db/output.h0000644000175000017500000000040213435336036015344 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern int dbprefix; extern int dbprintf(const char *, ...); extern void logprintf(const char *, ...); extern void output_init(void); xfsprogs-5.3.0/db/print.c0000644000175000017500000001307713435336036015147 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "io.h" #include "print.h" #include "bit.h" #include "flist.h" #include "strvec.h" #include "output.h" #include "sig.h" #include "write.h" static void print_allfields(const struct field *fields); static int print_f(int argc, char **argv); static void print_flist_1(struct flist *flist, char **pfx, int parentoff); static void print_somefields(const struct field *fields, int argc, char **argv); static const cmdinfo_t print_cmd = { "print", "p", print_f, 0, -1, 0, N_("[value]..."), N_("print field values"), NULL }; static void print_allfields( const field_t *fields) { flist_t *flist; #ifdef DEBUG int i; #endif flist = flist_make(""); flist->fld = fields; #ifndef DEBUG (void)flist_parse(fields, flist, iocur_top->data, 0); #else i = flist_parse(fields, flist, iocur_top->data, 0); ASSERT(i == 1); #endif flist_print(flist); print_flist(flist); flist_free(flist); } static int print_f( int argc, char **argv) { pfunc_t pf; if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } pf = cur_typ->pfunc; if (pf == NULL) { dbprintf(_("no print function for type %s\n"), cur_typ->name); return 0; } argc--; argv++; (*pf)(DB_READ, cur_typ->fields, argc, argv); return 0; } void print_flist( flist_t *flist) { char **pfx; pfx = new_strvec(0); print_flist_1(flist, pfx, 0); free_strvec(pfx); } static void print_flist_1( flist_t *flist, char **ppfx, int parentoff) { char buf[16]; const field_t *f; const ftattr_t *fa; flist_t *fl; int low; int count; int neednl; char **pfx; for (fl = flist; fl && !seenint(); fl = fl->sibling) { pfx = copy_strvec(ppfx); if (fl->name[0]) add_strvec(&pfx, fl->name); if (fl->flags & FL_OKLOW) { add_strvec(&pfx, "["); snprintf(buf, sizeof(buf), "%d", fl->low); add_strvec(&pfx, buf); if (fl->low != fl->high) { add_strvec(&pfx, "-"); snprintf(buf, sizeof(buf), "%d", fl->high); add_strvec(&pfx, buf); } add_strvec(&pfx, "]"); } if (fl->child) { if (fl->name[0]) add_strvec(&pfx, "."); print_flist_1(fl->child, pfx, fl->offset); } else { f = fl->fld; fa = &ftattrtab[f->ftyp]; ASSERT(fa->ftyp == f->ftyp); print_strvec(pfx); dbprintf(" = "); if (fl->flags & FL_OKLOW) low = fl->low; else low = 0; count = fcount(f, iocur_top->data, parentoff); if (fl->flags & FL_OKHIGH) count = min(count, fl->high - low + 1); if (fa->prfunc) { int fsz; int bitlen; /* Don't read an array off the end of the buffer */ fsz = fsize(f, iocur_top->data, parentoff, 0); bitlen = iocur_top->len * NBBY; if ((f->flags & FLD_ARRAY) && fl->offset + (count * fsz) > bitlen) { count = (bitlen - fl->offset) / fsz; } neednl = fa->prfunc(iocur_top->data, fl->offset, count, fa->fmtstr, fsz, fa->arg, low, (f->flags & FLD_ARRAY) != 0); if (neednl) dbprintf("\n"); } else if (fa->arg & FTARG_OKEMPTY) { dbprintf(_("(empty)\n")); } else { dbprintf(_("Unrecognized metadata or type mismatch\n")); } } free_strvec(pfx); } } void print_init(void) { add_command(&print_cmd); } void print_sarray( void *obj, int bit, int count, int size, int base, int array, const field_t *flds, int skipnms) { int bitoff; const field_t *f; const ftattr_t *fa; int first; int i; ASSERT(bitoffs(bit) == 0); if (skipnms == 0) { for (f = flds, first = 1; f->name; f++) { if (f->flags & FLD_SKIPALL) continue; dbprintf("%c%s", first ? '[' : ',', f->name); first = 0; } dbprintf("] "); } for (i = 0, bitoff = bit; i < count && !seenint(); i++, bitoff += size) { if (array) dbprintf("\n%d:", i + base); for (f = flds, first = 1; f->name; f++) { if (f->flags & FLD_SKIPALL) continue; fa = &ftattrtab[f->ftyp]; ASSERT(fa->ftyp == f->ftyp); dbprintf("%c", first ? '[' : ','); first = 0; if (fa->prfunc) fa->prfunc(obj, bitoff + bitoffset(f, obj, bitoff, i + base), fcount(f, obj, bitoff), fa->fmtstr, fsize(f, obj, bitoff, i + base), fa->arg, (f->flags & FLD_ABASE1) != 0, f->flags & FLD_ARRAY); else { ASSERT(fa->arg & FTARG_OKEMPTY); dbprintf(_("(empty)")); } } dbprintf("]"); if (i < count - 1) dbprintf(" "); } } static void print_somefields( const field_t *fields, int argc, char **argv) { const ftattr_t *fa; flist_t *fl; flist_t *lfl; flist_t *nfl; fl = lfl = NULL; while (argc > 0) { nfl = flist_scan(*argv); if (!nfl) { if (fl) flist_free(fl); return; } if (lfl) lfl->sibling = nfl; else fl = nfl; lfl = nfl; argc--; argv++; } if (fields->name[0] == '\0') { fa = &ftattrtab[fields->ftyp]; ASSERT(fa->ftyp == fields->ftyp); fields = fa->subfld; } if (!flist_parse(fields, fl, iocur_top->data, 0)) { flist_free(fl); return; } flist_print(fl); print_flist(fl); flist_free(fl); } /*ARGSUSED*/ void print_string( const field_t *fields, int argc, char **argv) { char *cp; if (argc != 0) dbprintf(_("no arguments allowed\n")); dbprintf("\""); for (cp = iocur_top->data; cp < (char *)iocur_top->data + iocur_top->len && *cp && !seenint(); cp++) dbprintf("%c", *cp); dbprintf("\"\n"); } void print_struct( const field_t *fields, int argc, char **argv) { if (argc == 0) print_allfields(fields); else print_somefields(fields, argc, argv); } xfsprogs-5.3.0/db/print.h0000644000175000017500000000100013435336036015133 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct field; struct flist; extern void print_flist(struct flist *flist); extern void print_init(void); extern void print_sarray(void *obj, int bit, int count, int size, int base, int array, const field_t *flds, int skipnms); extern void print_struct(const struct field *fields, int argc, char **argv); extern void print_string(const struct field *fields, int argc, char **argv); xfsprogs-5.3.0/db/quit.c0000644000175000017500000000067013435336036014770 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "command.h" #include "quit.h" static int quit_f(int argc, char **argv); static const cmdinfo_t quit_cmd = { "quit", "q", quit_f, 0, 0, 0, NULL, N_("exit xfs_db"), NULL }; static int quit_f( int argc, char **argv) { return 1; } void quit_init(void) { add_command(&quit_cmd); } xfsprogs-5.3.0/db/quit.h0000644000175000017500000000023013435336036014765 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void quit_init(void); xfsprogs-5.3.0/db/sb.c0000644000175000017500000005567613435336036014432 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "io.h" #include "sb.h" #include "bit.h" #include "output.h" #include "init.h" #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) static int sb_f(int argc, char **argv); static void sb_help(void); static int uuid_f(int argc, char **argv); static void uuid_help(void); static int label_f(int argc, char **argv); static void label_help(void); static int version_f(int argc, char **argv); static void version_help(void); static const cmdinfo_t sb_cmd = { "sb", NULL, sb_f, 0, 1, 1, N_("[agno]"), N_("set current address to sb header"), sb_help }; static const cmdinfo_t uuid_cmd = { "uuid", NULL, uuid_f, 0, 1, 1, N_("[uuid]"), N_("write/print FS uuid"), uuid_help }; static const cmdinfo_t label_cmd = { "label", NULL, label_f, 0, 1, 1, N_("[label]"), N_("write/print FS label"), label_help }; static const cmdinfo_t version_cmd = { "version", NULL, version_f, 0, -1, 1, N_("[feature | [vnum fnum]]"), N_("set feature bit(s) in the sb version field"), version_help }; void sb_init(void) { add_command(&sb_cmd); add_command(&uuid_cmd); add_command(&label_cmd); add_command(&version_cmd); } #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f)) #define SZC(f) szcount(xfs_sb_t, sb_ ## f) const field_t sb_flds[] = { { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE }, { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE }, { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE }, { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG }, { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE }, { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE }, { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE }, { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE }, { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE }, { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE }, { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE }, { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE }, { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE }, { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE }, { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE }, { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE }, { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE }, { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE }, { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE }, { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE }, { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE }, { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE }, { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE }, { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE }, { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE }, { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE }, { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE }, { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE }, { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE }, { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE }, { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE }, { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE }, { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE }, { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE }, { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE }, { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE }, { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE }, { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE }, { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE }, { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE }, { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE }, { "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE }, { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)), C1, 0, TYP_NONE }, { "features_compat", FLDT_UINT32X, OI(OFF(features_compat)), C1, 0, TYP_NONE }, { "features_ro_compat", FLDT_UINT32X, OI(OFF(features_ro_compat)), C1, 0, TYP_NONE }, { "features_incompat", FLDT_UINT32X, OI(OFF(features_incompat)), C1, 0, TYP_NONE }, { "features_log_incompat", FLDT_UINT32X, OI(OFF(features_log_incompat)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, { "spino_align", FLDT_EXTLEN, OI(OFF(spino_align)), C1, 0, TYP_NONE }, { "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE }, { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, { "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE }, { NULL } }; const field_t sb_hfld[] = { { "", FLDT_SB, OI(0), C1, 0, TYP_NONE }, { NULL } }; static void sb_help(void) { dbprintf(_( "\n" " set allocation group superblock\n" "\n" " Example:\n" "\n" " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" "\n" " Located in the first sector of each allocation group, the superblock\n" " contains the base information for the filesystem.\n" " The superblock in allocation group 0 is the primary. The copies in the\n" " remaining allocation groups only serve as backup for filesystem recovery.\n" " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" "\n" )); } static int sb_f( int argc, char **argv) { xfs_agnumber_t agno; char *p; if (argc > 1) { agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { dbprintf(_("bad allocation group number %s\n"), argv[1]); return 0; } cur_agno = agno; } else if (cur_agno == NULLAGNUMBER) cur_agno = 0; ASSERT(typtab[TYP_SB].typnm == TYP_SB); set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL); return 0; } /*ARGSUSED*/ int sb_size( void *obj, int startoff, int idx) { return bitize(mp->m_sb.sb_sectsize); } static int get_sb(xfs_agnumber_t agno, xfs_sb_t *sb) { push_cur(); set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); if (!iocur_top->data) { dbprintf(_("can't read superblock for AG %u\n"), agno); pop_cur(); return 0; } libxfs_sb_from_disk(sb, iocur_top->data); if (sb->sb_magicnum != XFS_SB_MAGIC) { dbprintf(_("bad sb magic # %#x in AG %u\n"), sb->sb_magicnum, agno); return 0; } if (!xfs_sb_good_version(sb)) { dbprintf(_("bad sb version # %#x in AG %u\n"), sb->sb_versionnum, agno); return 0; } if (agno == 0 && sb->sb_inprogress != 0) { dbprintf(_("mkfs not completed successfully\n")); return 0; } return 1; } /* workaround craziness in the xlog routines */ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p) { return 0; } int sb_logcheck(void) { int dirty; if (mp->m_sb.sb_logstart) { if (x.logdev && x.logdev != x.ddev) { dbprintf(_("aborting - external log specified for FS " "with an internal log\n")); return 0; } } else { if (!x.logdev || (x.logdev == x.ddev)) { dbprintf(_("aborting - no external log specified for FS " "with an external log\n")); return 0; } } libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev); dirty = xlog_is_dirty(mp, mp->m_log, &x, 0); if (dirty == -1) { dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n")); return 0; } else if (dirty == 1) { dbprintf(_( "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running %s. If you are unable to mount the filesystem, then use\n" "the xfs_repair -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n"), progname); return 0; } /* Log is clean */ return 1; } static int sb_logzero(uuid_t *uuidp) { int cycle = XLOG_INIT_CYCLE; int error; if (!sb_logcheck()) return 0; /* * The log must always move forward on v5 superblocks. Bump it to the * next cycle. */ if (xfs_sb_version_hascrc(&mp->m_sb)) cycle = mp->m_log->l_curr_cycle + 1; dbprintf(_("Clearing log and setting UUID\n")); error = libxfs_log_clear(mp->m_logdev_targp, NULL, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), uuidp, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true); if (error) { dbprintf(_("ERROR: cannot clear the log\n")); return 0; } return 1; } static void uuid_help(void) { dbprintf(_( "\n" " write/print FS uuid\n" "\n" " Example:\n" "\n" " 'uuid' - print UUID\n" " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" " 'uuid generate' - generate and write\n" " 'uuid rewrite' - copy UUID from SB 0\n" "\n" "The print function checks the UUID in each SB and will warn if the UUIDs\n" "differ between AGs (the log is not checked). The write commands will\n" "set the uuid in all AGs to either a specified value, a newly generated\n" "value or the value found in the first superblock (SB 0) respectively.\n" "As a side effect of writing the UUID, the log is cleared (which is fine\n" "on a CLEANLY unmounted FS).\n" "\n" )); } static uuid_t * do_uuid(xfs_agnumber_t agno, uuid_t *uuid) { xfs_sb_t tsb; static uuid_t uu; if (!get_sb(agno, &tsb)) return NULL; if (!uuid) { /* get uuid */ memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); pop_cur(); return &uu; } /* set uuid */ if (!xfs_sb_version_hascrc(&tsb)) goto write; /* * If we have CRCs, and this UUID differs from that stamped in the * metadata, set the incompat flag and copy the old one to the * metadata-specific location. * * If we are setting the user-visible UUID back to match the metadata * UUID, clear the metadata-specific location and the incompat flag. */ if (!xfs_sb_version_hasmetauuid(&tsb) && !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) { mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID; tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID; memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t)); } else if (xfs_sb_version_hasmetauuid(&tsb) && uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) { memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t)); /* Write those zeros now; it's ignored once we clear the flag */ libxfs_sb_to_disk(iocur_top->data, &tsb); mp->m_sb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID; tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID; } write: memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); libxfs_sb_to_disk(iocur_top->data, &tsb); write_cur(); return uuid; } static int uuid_f( int argc, char **argv) { char bp[40]; xfs_agnumber_t agno; uuid_t uu; uuid_t *uup = NULL; if (argc != 1 && argc != 2) { dbprintf(_("invalid parameters\n")); return 0; } if (argc == 2) { /* WRITE UUID */ if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { dbprintf(_("%s: not in expert mode, writing disabled\n"), progname); return 0; } if (!strcasecmp(argv[1], "generate")) { platform_uuid_generate(&uu); } else if (!strcasecmp(argv[1], "nil")) { platform_uuid_clear(&uu); } else if (!strcasecmp(argv[1], "rewrite")) { uup = do_uuid(0, NULL); if (!uup) { dbprintf(_("failed to read UUID from AG 0\n")); return 0; } memcpy(&uu, uup, sizeof(uuid_t)); platform_uuid_unparse(&uu, bp); dbprintf(_("old UUID = %s\n"), bp); } else if (!strcasecmp(argv[1], "restore")) { xfs_sb_t tsb; if (!get_sb(0, &tsb)) return 0; /* Not set; nothing to do. Success! */ if (!xfs_sb_version_hasmetauuid(&tsb)) return 0; memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t)); } else { if (platform_uuid_parse(argv[1], &uu)) { dbprintf(_("invalid UUID\n")); return 0; } } /* clear the log (setting uuid) if it's not dirty */ if (!sb_logzero(&uu)) return 0; dbprintf(_("writing all SBs\n")); for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) if (!do_uuid(agno, &uu)) { dbprintf(_("failed to set UUID in AG %d\n"), agno); break; } platform_uuid_unparse(&uu, bp); dbprintf(_("new UUID = %s\n"), bp); return 0; } else { /* READ+CHECK UUID */ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { uup = do_uuid(agno, NULL); if (!uup) { dbprintf(_("failed to read UUID from AG %d\n"), agno); return 0; } if (agno) { if (memcmp(&uu, uup, sizeof(uuid_t))) { dbprintf(_("warning: UUID in AG %d " "differs to the primary SB\n"), agno); break; } } else { memcpy(&uu, uup, sizeof(uuid_t)); } } if (mp->m_sb.sb_logstart) { if (x.logdev && x.logdev != x.ddev) dbprintf(_("warning - external log specified " "for FS with an internal log\n")); } else if (!x.logdev || (x.logdev == x.ddev)) { dbprintf(_("warning - no external log specified " "for FS with an external log\n")); } platform_uuid_unparse(&uu, bp); dbprintf(_("UUID = %s\n"), bp); } return 0; } static void label_help(void) { dbprintf(_( "\n" " write/print FS label\n" "\n" " Example:\n" "\n" " 'label' - print label\n" " 'label 123456789012' - write label\n" " 'label --' - write an empty label\n" "\n" "The print function checks the label in each SB and will warn if the labels\n" "differ between AGs. The write commands will set the label in all AGs to the\n" "specified value. The maximum length of a label is 12 characters - use of a\n" "longer label will result in truncation and a warning will be issued.\n" "\n" )); } static char * do_label(xfs_agnumber_t agno, char *label) { size_t len; xfs_sb_t tsb; static char lbl[sizeof(tsb.sb_fname) + 1]; if (!get_sb(agno, &tsb)) return NULL; memset(&lbl[0], 0, sizeof(lbl)); if (!label) { /* get label */ pop_cur(); memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); return &lbl[0]; } /* set label */ if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { if (agno == 0) dbprintf(_("%s: truncating label length from %d to %d\n"), progname, (int)len, (int)sizeof(tsb.sb_fname)); len = sizeof(tsb.sb_fname); } if ( len == 2 && (strcmp(label, "\"\"") == 0 || strcmp(label, "''") == 0 || strcmp(label, "--") == 0) ) label[0] = label[1] = '\0'; memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); memcpy(&tsb.sb_fname, label, len); memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); libxfs_sb_to_disk(iocur_top->data, &tsb); write_cur(); return &lbl[0]; } static int label_f( int argc, char **argv) { char *p = NULL; xfs_sb_t sb; xfs_agnumber_t ag; if (argc != 1 && argc != 2) { dbprintf(_("invalid parameters\n")); return 0; } if (argc == 2) { /* WRITE LABEL */ if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { dbprintf(_("%s: not in expert mode, writing disabled\n"), progname); return 0; } dbprintf(_("writing all SBs\n")); for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) if ((p = do_label(ag, argv[1])) == NULL) { dbprintf(_("failed to set label in AG %d\n"), ag); break; } dbprintf(_("new label = \"%s\"\n"), p); } else { /* READ LABEL */ for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { p = do_label(ag, NULL); if (!p) { dbprintf(_("failed to read label in AG %d\n"), ag); return 0; } if (!ag) memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname)); else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname))) dbprintf(_("warning: AG %d label differs\n"), ag); } dbprintf(_("label = \"%s\"\n"), p); } return 0; } static void version_help(void) { dbprintf(_( "\n" " set/print feature bits in sb version\n" "\n" " Example:\n" "\n" " 'version' - print current feature bits\n" " 'version extflg' - enable unwritten extents\n" " 'version attr1' - enable v1 inline extended attributes\n" " 'version attr2' - enable v2 inline extended attributes\n" " 'version log2' - enable v2 log format\n" "\n" "The version function prints currently enabled features for a filesystem\n" "according to the version field of its primary superblock.\n" "It can also be used to enable selected features, such as support for\n" "unwritten extents. The updated version is written into all AGs.\n" "\n" )); } static int do_version(xfs_agnumber_t agno, uint16_t version, uint32_t features) { xfs_sb_t tsb; if (!get_sb(agno, &tsb)) return 0; if (xfs_sb_has_mismatched_features2(&tsb)) { dbprintf(_("Superblock has mismatched features2 fields, " "skipping modification\n")); return 0; } if ((version & XFS_SB_VERSION_LOGV2BIT) && !xfs_sb_version_haslogv2(&tsb)) { tsb.sb_logsunit = 1; } tsb.sb_versionnum = version; tsb.sb_features2 = features; tsb.sb_bad_features2 = features; libxfs_sb_to_disk(iocur_top->data, &tsb); write_cur(); return 1; } static char * version_string( xfs_sb_t *sbp) { static char s[1024]; if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1) strcpy(s, "V1"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2) strcpy(s, "V2"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3) strcpy(s, "V3"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) strcpy(s, "V4"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) strcpy(s, "V5"); /* * We assume the state of these features now, so macros don't exist for * them any more. */ if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) strcat(s, ",NLINK"); if (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) strcat(s, ",SHARED"); if (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT) strcat(s, ",DIRV2"); if (xfs_sb_version_hasattr(sbp)) strcat(s, ",ATTR"); if (xfs_sb_version_hasquota(sbp)) strcat(s, ",QUOTA"); if (xfs_sb_version_hasalign(sbp)) strcat(s, ",ALIGN"); if (xfs_sb_version_hasdalign(sbp)) strcat(s, ",DALIGN"); if (xfs_sb_version_haslogv2(sbp)) strcat(s, ",LOGV2"); /* This feature is required now as well */ if (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT) strcat(s, ",EXTFLG"); if (xfs_sb_version_hassector(sbp)) strcat(s, ",SECTOR"); if (xfs_sb_version_hasasciici(sbp)) strcat(s, ",ASCII_CI"); if (xfs_sb_version_hasmorebits(sbp)) strcat(s, ",MOREBITS"); if (xfs_sb_version_hasattr2(sbp)) strcat(s, ",ATTR2"); if (xfs_sb_version_haslazysbcount(sbp)) strcat(s, ",LAZYSBCOUNT"); if (xfs_sb_version_hasprojid32bit(sbp)) strcat(s, ",PROJID32BIT"); if (xfs_sb_version_hascrc(sbp)) strcat(s, ",CRC"); if (xfs_sb_version_hasftype(sbp)) strcat(s, ",FTYPE"); if (xfs_sb_version_hasfinobt(sbp)) strcat(s, ",FINOBT"); if (xfs_sb_version_hassparseinodes(sbp)) strcat(s, ",SPARSE_INODES"); if (xfs_sb_version_hasmetauuid(sbp)) strcat(s, ",META_UUID"); if (xfs_sb_version_hasrmapbt(sbp)) strcat(s, ",RMAPBT"); if (xfs_sb_version_hasreflink(sbp)) strcat(s, ",REFLINK"); return s; } /* * XXX: this only supports reading and writing to version 4 superblock fields. * V5 superblocks always define certain V4 feature bits - they are blocked from * being changed if a V5 sb is detected, but otherwise v5 superblock features * are not handled here. */ static int version_f( int argc, char **argv) { uint16_t version = 0; uint32_t features = 0; xfs_agnumber_t ag; if (argc == 2) { /* WRITE VERSION */ if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { dbprintf(_("%s: not in expert mode, writing disabled\n"), progname); return 0; } /* Logic here derived from the IRIX xfs_chver(1M) script. */ if (!strcasecmp(argv[1], "extflg")) { switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { case XFS_SB_VERSION_1: version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT; break; case XFS_SB_VERSION_2: version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT; break; case XFS_SB_VERSION_3: version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT; break; case XFS_SB_VERSION_4: if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_EXTFLGBIT) dbprintf( _("unwritten extents flag is already enabled\n")); else version = mp->m_sb.sb_versionnum | XFS_SB_VERSION_EXTFLGBIT; break; case XFS_SB_VERSION_5: dbprintf( _("unwritten extents always enabled for v5 superblocks.\n")); break; } } else if (!strcasecmp(argv[1], "log2")) { switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { case XFS_SB_VERSION_1: version = 0x0004 | XFS_SB_VERSION_LOGV2BIT; break; case XFS_SB_VERSION_2: version = 0x0014 | XFS_SB_VERSION_LOGV2BIT; break; case XFS_SB_VERSION_3: version = 0x0034 | XFS_SB_VERSION_LOGV2BIT; break; case XFS_SB_VERSION_4: if (xfs_sb_version_haslogv2(&mp->m_sb)) dbprintf( _("version 2 log format is already in use\n")); else version = mp->m_sb.sb_versionnum | XFS_SB_VERSION_LOGV2BIT; break; case XFS_SB_VERSION_5: dbprintf( _("Version 2 logs always enabled for v5 superblocks.\n")); break; } } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) { dbprintf( _("%s: Cannot change %s on v5 superblocks.\n"), progname, argv[1]); return 0; } else if (!strcasecmp(argv[1], "attr1")) { if (xfs_sb_version_hasattr2(&mp->m_sb)) { if (!(mp->m_sb.sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT)) mp->m_sb.sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT; } xfs_sb_version_addattr(&mp->m_sb); version = mp->m_sb.sb_versionnum; features = mp->m_sb.sb_features2; } else if (!strcasecmp(argv[1], "attr2")) { xfs_sb_version_addattr(&mp->m_sb); xfs_sb_version_addattr2(&mp->m_sb); version = mp->m_sb.sb_versionnum; features = mp->m_sb.sb_features2; } else if (!strcasecmp(argv[1], "projid32bit")) { xfs_sb_version_addprojid32bit(&mp->m_sb); version = mp->m_sb.sb_versionnum; features = mp->m_sb.sb_features2; } else { dbprintf(_("%s: invalid version change command \"%s\"\n"), progname, argv[1]); return 0; } if (version) { dbprintf(_("writing all SBs\n")); for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) if (!do_version(ag, version, features)) { dbprintf(_("failed to set versionnum " "in AG %d\n"), ag); break; } mp->m_sb.sb_versionnum = version; mp->m_sb.sb_features2 = features; } } if (argc == 3) { /* VERSIONNUM + FEATURES2 */ char *sp; version = mp->m_sb.sb_versionnum; features = mp->m_sb.sb_features2; mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0); mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0); } dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum, mp->m_sb.sb_features2, version_string(&mp->m_sb)); if (argc == 3) { /* now reset... */ mp->m_sb.sb_versionnum = version; mp->m_sb.sb_features2 = features; return 0; } return 0; } xfsprogs-5.3.0/db/sb.h0000644000175000017500000000046513435336036014421 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern const struct field sb_flds[]; extern const struct field sb_hfld[]; extern void sb_init(void); extern int sb_logcheck(void); extern int sb_size(void *obj, int startoff, int idx); xfsprogs-5.3.0/db/sig.c0000644000175000017500000000130613435336036014565 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "sig.h" static int gotintr; static sigset_t intrset; static void interrupt(int sig, siginfo_t *info, void *uc) { gotintr = 1; } void blockint(void) { sigprocmask(SIG_BLOCK, &intrset, NULL); } void clearint(void) { gotintr = 0; } void init_sig(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = interrupt; sigaction(SIGINT, &sa, NULL); sigemptyset(&intrset); sigaddset(&intrset, SIGINT); } int seenint(void) { return gotintr; } void unblockint(void) { sigprocmask(SIG_UNBLOCK, &intrset, NULL); } xfsprogs-5.3.0/db/sig.h0000644000175000017500000000040713435336036014573 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void blockint(void); extern void clearint(void); extern void init_sig(void); extern int seenint(void); extern void unblockint(void); xfsprogs-5.3.0/db/strvec.c0000644000175000017500000000214113435336036015307 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "strvec.h" #include "output.h" #include "malloc.h" static int count_strvec(char **vec); void add_strvec( char ***vecp, char *str) { char *dup; int i; char **vec; dup = xstrdup(str); vec = *vecp; i = count_strvec(vec); vec = xrealloc(vec, sizeof(*vec) * (i + 2)); vec[i] = dup; vec[i + 1] = NULL; *vecp = vec; } char ** copy_strvec( char **vec) { int i; char **rval; i = count_strvec(vec); rval = new_strvec(i); for (i = 0; vec[i] != NULL; i++) rval[i] = xstrdup(vec[i]); return rval; } static int count_strvec( char **vec) { int i; for (i = 0; vec[i] != NULL; i++) continue; return i; } void free_strvec( char **vec) { int i; for (i = 0; vec[i] != NULL; i++) xfree(vec[i]); xfree(vec); } char ** new_strvec( int count) { char **rval; rval = xmalloc(sizeof(*rval) * (count + 1)); rval[count] = NULL; return rval; } void print_strvec( char **vec) { int i; for (i = 0; vec[i] != NULL; i++) dbprintf("%s", vec[i]); } xfsprogs-5.3.0/db/strvec.h0000644000175000017500000000050313435336036015314 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void add_strvec(char ***vecp, char *str); extern char **copy_strvec(char **vec); extern void free_strvec(char **vec); extern char **new_strvec(int count); extern void print_strvec(char **vec); xfsprogs-5.3.0/db/symlink.c0000644000175000017500000000327513435336036015500 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "bit.h" #include "init.h" #include "symlink.h" /* * XXX: no idea how to handle multiple contiguous block symlinks here. */ static int symlink_count( void *obj, int startoff) { struct xfs_dsymlink_hdr *hdr = obj; ASSERT(startoff == 0); if (hdr->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) return 0; if (be32_to_cpu(hdr->sl_bytes) + sizeof(*hdr) > mp->m_sb.sb_blocksize) return mp->m_sb.sb_blocksize - sizeof(*hdr); return be32_to_cpu(hdr->sl_bytes); } int symlink_size( void *obj, int startoff, int idx) { struct xfs_dsymlink_hdr *hdr = obj; ASSERT(startoff == 0); if (hdr->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) return 0; return be32_to_cpu(hdr->sl_bytes) + sizeof(*hdr); } const struct field symlink_crc_hfld[] = { { "", FLDT_SYMLINK_CRC, OI(0), C1, 0, TYP_NONE }, { NULL } }; #define OFF(f) bitize(offsetof(struct xfs_dsymlink_hdr, sl_ ## f)) const struct field symlink_crc_flds[] = { { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, { "offset", FLDT_UINT32D, OI(OFF(offset)), C1, 0, TYP_NONE }, { "bytes", FLDT_UINT32D, OI(OFF(bytes)), C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, { "owner", FLDT_INO, OI(OFF(owner)), C1, 0, TYP_NONE }, { "bno", FLDT_DFSBNO, OI(OFF(blkno)), C1, 0, TYP_BMAPBTD }, { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, { "data", FLDT_CHARNS, OI(bitize(sizeof(struct xfs_dsymlink_hdr))), symlink_count, FLD_COUNT, TYP_NONE }, { NULL } }; xfsprogs-5.3.0/db/symlink.h0000644000175000017500000000052713435336036015502 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_DB_SYMLINK_H #define __XFS_DB_SYMLINK_H extern const struct field symlink_crc_hfld[]; extern const struct field symlink_crc_flds[]; extern int symlink_size(void *obj, int startoff, int idx); #endif /* __XFS_DB_SYMLINK_H */ xfsprogs-5.3.0/db/text.c0000644000175000017500000000240213435336036014765 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "block.h" #include "bmap.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "inode.h" #include "io.h" #include "output.h" #include "init.h" #include "text.h" static void print_rawtext(void *data, int len); void print_text( const field_t *fields, int argc, char **argv) { print_rawtext(iocur_top->data, iocur_top->len); } static void print_rawtext( void *data, int len) { int i; int j; int lastaddr; int offchars; unsigned char *p; lastaddr = (len - 1) & ~(16 - 1); if (lastaddr < 0x10) offchars = 1; else if (lastaddr < 0x100) offchars = 2; else if (lastaddr < 0x1000) offchars = 3; else offchars = 4; for (i = 0, p = data; i < len; i += 16) { unsigned char *s = p; dbprintf("%-0*.*x: ", offchars, offchars, i); for (j = 0; j < 16 && i + j < len; j++, p++) { dbprintf("%02x ", *p); } dbprintf(" "); for (j = 0; j < 16 && i + j < len; j++, s++) { if (isalnum(*s)) dbprintf("%c", *s); else dbprintf(".", *s); } dbprintf("\n"); } } xfsprogs-5.3.0/db/text.h0000644000175000017500000000031213435336036014770 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern void print_text(const struct field *fields, int argc, char **argv); xfsprogs-5.3.0/db/type.c0000644000175000017500000002245213570057155014773 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "block.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "print.h" #include "sb.h" #include "inode.h" #include "btblock.h" #include "bmroot.h" #include "agf.h" #include "agfl.h" #include "agi.h" #include "io.h" #include "output.h" #include "write.h" #include "attr.h" #include "dquot.h" #include "dir2.h" #include "text.h" #include "symlink.h" #include "fuzz.h" static const typ_t *findtyp(char *name); static int type_f(int argc, char **argv); const typ_t *cur_typ; static const cmdinfo_t type_cmd = { "type", NULL, type_f, 0, 1, 1, N_("[newtype]"), N_("set/show current data type"), NULL }; static const typ_t __typtab[] = { { TYP_AGF, "agf", handle_struct, agf_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_AGFL, "agfl", handle_struct, agfl_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_AGI, "agi", handle_struct, agi_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_ATTR, "attr", handle_struct, attr_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_RMAPBT, NULL }, { TYP_REFCBT, NULL }, { TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_DIR2, "dir2", handle_struct, dir2_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_INOBT, "inobt", handle_struct, inobt_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_INODATA, "inodata", NULL, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_INODE, "inode", handle_struct, inode_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_LOG, "log", NULL, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_RTBITMAP, "rtbitmap", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_RTSUMMARY, "rtsummary", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_SB, "sb", handle_struct, sb_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_SYMLINK, "symlink", handle_string, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_TEXT, "text", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_FINOBT, "finobt", handle_struct, inobt_hfld, NULL, TYP_F_NO_CRC_OFF }, { TYP_NONE, NULL } }; static const typ_t __typtab_crc[] = { { TYP_AGF, "agf", handle_struct, agf_hfld, &xfs_agf_buf_ops, XFS_AGF_CRC_OFF }, { TYP_AGFL, "agfl", handle_struct, agfl_crc_hfld, &xfs_agfl_buf_ops, XFS_AGFL_CRC_OFF }, { TYP_AGI, "agi", handle_struct, agi_hfld, &xfs_agi_buf_ops, XFS_AGI_CRC_OFF }, { TYP_ATTR, "attr3", handle_struct, attr3_hfld, &xfs_attr3_db_buf_ops, TYP_F_CRC_FUNC, xfs_attr3_set_crc }, { TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_crc_hfld, &xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF }, { TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_crc_hfld, &xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF }, { TYP_BNOBT, "bnobt", handle_struct, bnobt_crc_hfld, &xfs_bnobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_CNTBT, "cntbt", handle_struct, cntbt_crc_hfld, &xfs_cntbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_RMAPBT, "rmapbt", handle_struct, rmapbt_crc_hfld, &xfs_rmapbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_REFCBT, "refcntbt", handle_struct, refcbt_crc_hfld, &xfs_refcountbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_DIR2, "dir3", handle_struct, dir3_hfld, &xfs_dir3_db_buf_ops, TYP_F_CRC_FUNC, xfs_dir3_set_crc }, { TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld, &xfs_dquot_buf_ops, TYP_F_CRC_FUNC, xfs_dquot_set_crc }, { TYP_INOBT, "inobt", handle_struct, inobt_crc_hfld, &xfs_inobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_INODATA, "inodata", NULL, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_INODE, "inode", handle_struct, inode_crc_hfld, &xfs_inode_buf_ops, TYP_F_CRC_FUNC, xfs_inode_set_crc }, { TYP_LOG, "log", NULL, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_RTBITMAP, "rtbitmap", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_RTSUMMARY, "rtsummary", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_SB, "sb", handle_struct, sb_hfld, &xfs_sb_buf_ops, XFS_SB_CRC_OFF }, { TYP_SYMLINK, "symlink", handle_struct, symlink_crc_hfld, &xfs_symlink_buf_ops, XFS_SYMLINK_CRC_OFF }, { TYP_TEXT, "text", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_FINOBT, "finobt", handle_struct, inobt_crc_hfld, &xfs_finobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_NONE, NULL } }; static const typ_t __typtab_spcrc[] = { { TYP_AGF, "agf", handle_struct, agf_hfld, &xfs_agf_buf_ops, XFS_AGF_CRC_OFF }, { TYP_AGFL, "agfl", handle_struct, agfl_crc_hfld, &xfs_agfl_buf_ops , XFS_AGFL_CRC_OFF }, { TYP_AGI, "agi", handle_struct, agi_hfld, &xfs_agi_buf_ops , XFS_AGI_CRC_OFF }, { TYP_ATTR, "attr3", handle_struct, attr3_hfld, &xfs_attr3_db_buf_ops, TYP_F_CRC_FUNC, xfs_attr3_set_crc }, { TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_crc_hfld, &xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF }, { TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_crc_hfld, &xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF }, { TYP_BNOBT, "bnobt", handle_struct, bnobt_crc_hfld, &xfs_bnobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_CNTBT, "cntbt", handle_struct, cntbt_crc_hfld, &xfs_cntbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_RMAPBT, "rmapbt", handle_struct, rmapbt_crc_hfld, &xfs_rmapbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_REFCBT, "refcntbt", handle_struct, refcbt_crc_hfld, &xfs_refcountbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_DIR2, "dir3", handle_struct, dir3_hfld, &xfs_dir3_db_buf_ops, TYP_F_CRC_FUNC, xfs_dir3_set_crc }, { TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld, &xfs_dquot_buf_ops, TYP_F_CRC_FUNC, xfs_dquot_set_crc }, { TYP_INOBT, "inobt", handle_struct, inobt_spcrc_hfld, &xfs_inobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_INODATA, "inodata", NULL, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_INODE, "inode", handle_struct, inode_crc_hfld, &xfs_inode_buf_ops, TYP_F_CRC_FUNC, xfs_inode_set_crc }, { TYP_LOG, "log", NULL, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_RTBITMAP, "rtbitmap", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_RTSUMMARY, "rtsummary", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_SB, "sb", handle_struct, sb_hfld, &xfs_sb_buf_ops, XFS_SB_CRC_OFF }, { TYP_SYMLINK, "symlink", handle_struct, symlink_crc_hfld, &xfs_symlink_buf_ops, XFS_SYMLINK_CRC_OFF }, { TYP_TEXT, "text", handle_text, NULL, NULL, TYP_F_NO_CRC_OFF }, { TYP_FINOBT, "finobt", handle_struct, inobt_spcrc_hfld, &xfs_finobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF }, { TYP_NONE, NULL } }; const typ_t *typtab = __typtab; void type_set_tab_crc(void) { typtab = __typtab_crc; } void type_set_tab_spcrc(void) { typtab = __typtab_spcrc; } static const typ_t * findtyp( char *name) { const typ_t *tt; for (tt = typtab; tt->typnm != TYP_NONE; tt++) { ASSERT(tt->typnm == (typnm_t)(tt - typtab)); if (tt->name && strcmp(tt->name, name) == 0) return tt; } return NULL; } static int type_f( int argc, char **argv) { const typ_t *tt; int count = 0; if (argc == 1) { if (cur_typ == NULL) dbprintf(_("no current type\n")); else dbprintf(_("current type is \"%s\"\n"), cur_typ->name); dbprintf(_("\n supported types are:\n ")); for (tt = typtab, count = 0; tt->typnm != TYP_NONE; tt++) { if (tt->name == NULL) continue; if ((tt+1)->name != NULL) { dbprintf("%s, ", tt->name); if ((++count % 8) == 0) dbprintf("\n "); } else if ((tt+1)->typnm == TYP_NONE) { dbprintf("%s\n", tt->name); } } } else { tt = findtyp(argv[1]); if (tt == NULL) { dbprintf(_("no such type %s\n"), argv[1]); } else { if (iocur_top->typ == NULL) dbprintf(_("no current object\n")); else { cur_typ = tt; set_iocur_type(tt); } } } return 0; } void type_init(void) { add_command(&type_cmd); } /* read/write selectors for each major data type */ void handle_struct( int action, const field_t *fields, int argc, char **argv) { switch (action) { case DB_FUZZ: fuzz_struct(fields, argc, argv); break; case DB_WRITE: write_struct(fields, argc, argv); break; case DB_READ: print_struct(fields, argc, argv); break; } } void handle_string( int action, const field_t *fields, int argc, char **argv) { switch (action) { case DB_WRITE: write_string(fields, argc, argv); break; case DB_READ: print_string(fields, argc, argv); break; case DB_FUZZ: dbprintf(_("string fuzzing not supported.\n")); break; } } void handle_block( int action, const field_t *fields, int argc, char **argv) { switch (action) { case DB_WRITE: write_block(fields, argc, argv); break; case DB_READ: print_block(fields, argc, argv); break; case DB_FUZZ: dbprintf(_("use 'blocktrash' or 'write' to fuzz a block.\n")); break; } } void handle_text( int action, const field_t *fields, int argc, char **argv) { switch (action) { case DB_FUZZ: /* fall through */ case DB_WRITE: dbprintf(_("text writing/fuzzing not supported.\n")); break; case DB_READ: print_text(fields, argc, argv); break; } } xfsprogs-5.3.0/db/type.h0000644000175000017500000000301413435336036014767 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct field; #define szof(x,y) sizeof(((x *)0)->y) #define szcount(x,y) (szof(x,y) / szof(x,y[0])) typedef enum typnm { TYP_AGF, TYP_AGFL, TYP_AGI, TYP_ATTR, TYP_BMAPBTA, TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_RMAPBT, TYP_REFCBT, TYP_DATA, TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE, TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK, TYP_TEXT, TYP_FINOBT, TYP_NONE } typnm_t; #define DB_FUZZ 2 #define DB_WRITE 1 #define DB_READ 0 typedef void (*opfunc_t)(const struct field *fld, int argc, char **argv); typedef void (*pfunc_t)(int action, const struct field *fld, int argc, char **argv); typedef struct typ { typnm_t typnm; char *name; pfunc_t pfunc; const struct field *fields; const struct xfs_buf_ops *bops; unsigned long crc_off; #define TYP_F_NO_CRC_OFF (-1UL) #define TYP_F_CRC_FUNC (-2UL) void (*set_crc)(struct xfs_buf *); } typ_t; extern const typ_t *typtab, *cur_typ; extern void type_init(void); extern void type_set_tab_crc(void); extern void type_set_tab_spcrc(void); extern void handle_block(int action, const struct field *fields, int argc, char **argv); extern void handle_string(int action, const struct field *fields, int argc, char **argv); extern void handle_struct(int action, const struct field *fields, int argc, char **argv); extern void handle_text(int action, const struct field *fields, int argc, char **argv); xfsprogs-5.3.0/db/write.c0000644000175000017500000004301113435336036015134 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include #include "bit.h" #include "block.h" #include "command.h" #include "type.h" #include "faddr.h" #include "fprint.h" #include "field.h" #include "flist.h" #include "io.h" #include "init.h" #include "output.h" #include "print.h" #include "write.h" #include "malloc.h" static int write_f(int argc, char **argv); static void write_help(void); static const cmdinfo_t write_cmd = { "write", NULL, write_f, 0, -1, 0, N_("[-c|-d] [field or value]..."), N_("write value to disk"), write_help }; void write_init(void) { if (!expert_mode) return; add_command(&write_cmd); srand48(clock()); } static void write_help(void) { dbprintf(_( "\n" " The 'write' command takes on different personalities depending on the\n" " type of object being worked with.\n\n" " Write has 3 modes:\n" " 'struct mode' - is active anytime you're looking at a filesystem object\n" " which contains individual fields (ex: an inode).\n" " 'data mode' - is active anytime you set a disk address directly or set\n" " the type to 'data'.\n" " 'string mode' - only used for writing symlink blocks.\n" "\n" " Examples:\n" " Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n" " 'write fname \"hello\\000\"' - write superblock fname.\n" " (note: in struct mode strings are not null terminated)\n" " 'write fname #6669736800' - write superblock fname with hex.\n" " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n" " - write superblock uuid.\n" " Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n" " 'write lshift 3' - shift the block 3 bytes to the left\n" " 'write sequence 1 5' - write a cycle of number [1-5] through\n" " the entire block.\n" " String mode: 'write \"This_is_a_filename\" - write null terminated string.\n" "\n" " In data mode type 'write' by itself for a list of specific commands.\n\n" " Specifying the -c option will allow writes of invalid (corrupt) data with\n" " an invalid CRC. Specifying the -d option will allow writes of invalid data,\n" " but still recalculate the CRC so we are forced to check and detect the\n" " invalid data appropriately.\n\n" )); } static int write_f( int argc, char **argv) { pfunc_t pf; extern char *progname; int c; bool corrupt = false; /* Allow write of bad data w/ invalid CRC */ bool invalid_data = false; /* Allow write of bad data w/ valid CRC */ struct xfs_buf_ops local_ops; const struct xfs_buf_ops *stashed_ops = NULL; if (x.isreadonly & LIBXFS_ISREADONLY) { dbprintf(_("%s started in read only mode, writing disabled\n"), progname); return 0; } if (cur_typ == NULL) { dbprintf(_("no current type\n")); return 0; } pf = cur_typ->pfunc; if (pf == NULL) { dbprintf(_("no handler function for type %s, write unsupported.\n"), cur_typ->name); return 0; } while ((c = getopt(argc, argv, "cd")) != EOF) { switch (c) { case 'c': corrupt = true; break; case 'd': invalid_data = true; break; default: dbprintf(_("bad option for write command\n")); return 0; } } if (corrupt && invalid_data) { dbprintf(_("Cannot specify both -c and -d options\n")); return 0; } if (invalid_data && iocur_top->typ->crc_off == TYP_F_NO_CRC_OFF && xfs_sb_version_hascrc(&mp->m_sb)) { dbprintf(_("Cannot recalculate CRCs on this type of object\n")); return 0; } argc -= optind; argv += optind; /* * If the buffer has no verifier or we are using standard verifier * paths, then just write it out and return */ if (!iocur_top->bp->b_ops || !(corrupt || invalid_data)) { (*pf)(DB_WRITE, cur_typ->fields, argc, argv); return 0; } /* Temporarily remove write verifier to write bad data */ stashed_ops = iocur_top->bp->b_ops; local_ops.verify_read = stashed_ops->verify_read; iocur_top->bp->b_ops = &local_ops; if (!xfs_sb_version_hascrc(&mp->m_sb)) { local_ops.verify_write = xfs_dummy_verify; } else if (corrupt) { local_ops.verify_write = xfs_dummy_verify; dbprintf(_("Allowing write of corrupted data and bad CRC\n")); } else if (iocur_top->typ->crc_off == TYP_F_CRC_FUNC) { local_ops.verify_write = iocur_top->typ->set_crc; dbprintf(_("Allowing write of corrupted data with good CRC\n")); } else { /* invalid data */ local_ops.verify_write = xfs_verify_recalc_crc; dbprintf(_("Allowing write of corrupted data with good CRC\n")); } (*pf)(DB_WRITE, cur_typ->fields, argc, argv); iocur_top->bp->b_ops = stashed_ops; return 0; } /* compare significant portions of commands */ static int sigcmp( char *s1, char *s2, int sig) { int sigcnt; if (!s1 || !s2) return 0; for (sigcnt = 0; *s1 == *s2; s1++, s2++) { sigcnt++; if (*s1 == '\0') return 1; } if (*s1 && *s2) return 0; if (sig && (sigcnt >= sig)) return 1; return 0; } /* ARGSUSED */ static void bwrite_lshift( int start, int len, int shift, int from, int to) { char *base; if (shift == -1) shift = 1; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } base = (char *)iocur_top->data + start; memcpy(base, base+shift, len-shift); memset(base+(len-shift), 0, shift); } /* ARGSUSED */ static void bwrite_rshift( int start, int len, int shift, int from, int to) { char *base; if (shift == -1) shift = 1; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } base = (char *)iocur_top->data + start; memcpy(base+shift, base, len-shift); memset(base, 0, shift); } /* ARGSUSED */ static void bwrite_lrot( int start, int len, int shift, int from, int to) { char *base; char *hold_region; if (shift == -1) shift = 1; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } base = (char *)iocur_top->data + start; hold_region = xmalloc(shift); memcpy(hold_region, base, shift); memcpy(base, base+shift, len-shift); memcpy(base+(len-shift), hold_region, shift); free(hold_region); } /* ARGSUSED */ static void bwrite_rrot( int start, int len, int shift, int from, int to) { char *base; char *hold_region; if (shift == -1) shift = 1; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } base = (char *)iocur_top->data + start; hold_region = xmalloc(shift); memcpy(hold_region, base+(len-shift), shift); memmove(base+shift, base, len-shift); memcpy(base, hold_region, shift); free(hold_region); } /* ARGSUSED */ static void bwrite_seq( int start, int len, int step, int from, int to) { int i; int tmp; int base; int range; int top; char *buf; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } if (from == -1 || from > 255) from = 0; if (to == -1 || to > 255) to = 255; if (step == -1) step = 1; base = from; top = to; if (from > to) { base = to; top = from; if (step > 0) step = -step; } range = top - base; buf = (char *)iocur_top->data + start; tmp = 0; for (i = start; i < start+len; i++) { *buf++ = tmp + base; tmp = (tmp + step)%(range+1); } } /* ARGSUSED */ static void bwrite_random( int start, int len, int shift, int from, int to) { int i; char *buf; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } buf = (char *)iocur_top->data + start; for (i = start; i < start+len; i++) *buf++ = (char)lrand48(); } /* ARGSUSED */ static void bwrite_fill( int start, int len, int value, int from, int to) { char *base; if (value == -1) value = 0; if (start == -1) start = 0; if (len == -1) len = iocur_top->len - start; if (len+start > iocur_top->len) { dbprintf(_("length (%d) too large for data block size (%d)"), len, iocur_top->len); } base = (char *)iocur_top->data + start; memset(base, value, len); } static struct bw_cmd { void (*cmdfunc)(int,int,int,int,int); char *cmdstr; int sig_chars; int argmin; int argmax; int shiftcount_arg; int from_arg; int to_arg; int start_arg; int len_arg; char *usage; } bw_cmdtab[] = { /* cmd sig min max sh frm to start len */ { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3, "[shiftcount] [start] [len]", }, { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3, "[shiftcount] [start] [len]", }, { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3, "[shiftcount] [start] [len]", }, { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3, "[shiftcount] [start] [len]", }, { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4, "[from] [to] [start] [len]", }, { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2, "[start] [len]", }, { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3, "num [start] [len]" } }; #define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0])) static int convert_oct( char *arg, int *ret) { int count; int i; int val = 0; /* only allow 1 case, '\' and 3 octal digits (or less) */ for (count = 0; count < 3; count++) { if (arg[count] == '\0') break; if ((arg[count] < '0') && (arg[count] > '7')) break; } for (i = 0; i < count; i++) { val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3); } *ret = val&0xff; return(count); } #define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa)) /* * convert_arg allows input in the following forms: * * - A string ("ABTB") whose ASCII value is placed in an array in the order * matching the input. * * - An even number of hex numbers. If the length is greater than 64 bits, * then the output is an array of bytes whose top nibble is the first hex * digit in the input, the lower nibble is the second hex digit in the * input. UUID entries are entered in this manner. * * - A decimal or hexadecimal integer to be used with setbitval(). * * Numbers that are passed to setbitval() need to be in big endian format and * are adjusted in the buffer so that the first input bit is to be be written to * the first bit in the output. */ static char * convert_arg( char *arg, int bit_length) { int i; int alloc_size; int octval; int offset; int ret; static char *buf = NULL; char *endp; char *rbuf; char *ostr; __be64 *value; __u64 val = 0; if (bit_length <= 64) alloc_size = 8; else alloc_size = (bit_length + 7) / 8; buf = xrealloc(buf, alloc_size); memset(buf, 0, alloc_size); value = (__be64 *)buf; rbuf = buf; if (*arg == '\"') { /* input a string and output ASCII array of characters */ /* zap closing quote if there is one */ ostr = strrchr(arg + 1, '\"'); if (ostr) *ostr = '\0'; ostr = arg + 1; for (i = 0; i < alloc_size; i++) { if (!*ostr) break; /* do octal conversion */ if (*ostr == '\\') { if (*(ostr + 1) >= '0' || *(ostr + 1) <= '7') { ret = convert_oct(ostr + 1, &octval); *rbuf++ = octval; ostr += ret + 1; continue; } } *rbuf++ = *ostr++; } return buf; } if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) { /* * handle hex blocks ie * #00112233445566778899aabbccddeeff * and uuids ie * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899 * * (but if it starts with "-" assume it's just an integer) */ int bytes = bit_length / NBBY; /* is this an array of hec numbers? */ if (bit_length % NBBY) return NULL; /* skip leading hash */ if (*arg == '#') arg++; while (*arg && bytes--) { /* skip hypens */ while (*arg == '-') arg++; /* get first nybble */ if (!isxdigit((int)*arg)) return NULL; *rbuf = NYBBLE((int)*arg) << 4; arg++; /* skip more hyphens */ while (*arg == '-') arg++; /* get second nybble */ if (!isxdigit((int)*arg)) return NULL; *rbuf++ |= NYBBLE((int)*arg); arg++; } if (bytes < 0 && *arg) return NULL; return buf; } /* handle decimal / hexadecimal integers */ val = strtoll(arg, &endp, 0); /* return if not a clean number */ if (*endp != '\0') return NULL; /* Does the value fit into the range of the destination bitfield? */ if (bit_length < 64 && (val >> bit_length) > 0) return NULL; /* * If the length of the field is not a multiple of a byte, push * the bits up in the field, so the most signicant field bit is * the most significant bit in the byte: * * before: * val |----|----|----|----|----|--MM|mmmm|llll| * after * val |----|----|----|----|----|MMmm|mmll|ll00| */ offset = bit_length % NBBY; if (offset) val <<= (NBBY - offset); /* * convert to big endian and copy into the array * rbuf |----|----|----|----|----|MMmm|mmll|ll00| */ *value = cpu_to_be64(val); /* * Align the array to point to the field in the array. * rbuf = |MMmm|mmll|ll00| */ offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64)); rbuf += offset; return rbuf; } /* ARGSUSED */ void write_struct( const field_t *fields, int argc, char **argv) { const ftattr_t *fa; flist_t *fl; flist_t *sfl; int bit_length; char *buf; int parentoffset; if (argc != 2) { dbprintf(_("usage: write fieldname value\n")); return; } fl = flist_scan(argv[0]); if (!fl) { dbprintf(_("unable to parse '%s'.\n"), argv[0]); return; } /* if we're a root field type, go down 1 layer to get field list */ if (fields->name[0] == '\0') { fa = &ftattrtab[fields->ftyp]; ASSERT(fa->ftyp == fields->ftyp); fields = fa->subfld; } /* run down the field list and set offsets into the data */ if (!flist_parse(fields, fl, iocur_top->data, 0)) { flist_free(fl); dbprintf(_("parsing error\n")); return; } sfl = fl; parentoffset = 0; while (sfl->child) { parentoffset = sfl->offset; sfl = sfl->child; } /* * For structures, fsize * fcount tells us the size of the region we are * modifying, which is usually a single structure member and is pointed * to by the last child in the list. * * However, if the base structure is an array and we have a direct index * into the array (e.g. write bno[5]) then we are returned a single * flist object with the offset pointing directly at the location we * need to modify. The length of the object we are modifying is then * determined by the size of the individual array entry (fsize) and the * indexes defined in the object, not the overall size of the array * (which is what fcount returns). */ bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0); if (sfl->fld->flags & FLD_ARRAY) bit_length *= sfl->high - sfl->low + 1; else bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset); /* convert this to a generic conversion routine */ /* should be able to handle str, num, or even labels */ buf = convert_arg(argv[1], bit_length); if (!buf) { dbprintf(_("unable to convert value '%s'.\n"), argv[1]); flist_free(fl); return; } setbitval(iocur_top->data, sfl->offset, bit_length, buf); write_cur(); flist_print(fl); print_flist(fl); flist_free(fl); } /* ARGSUSED */ void write_string( const field_t *fields, int argc, char **argv) { char *buf; int i; if (argc != 1) { dbprintf(_("usage (in string mode): write \"string...\"\n")); return; } buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8)); for (i = 0; i < iocur_top->len; i++) { ((char *)iocur_top->data)[i] = *buf; if (*buf++ == '\0') break; } /* write back to disk */ write_cur(); } /* ARGSUSED */ void write_block( const field_t *fields, int argc, char **argv) { int i; int shiftcount = -1; int start = -1; int len = -1; int from = -1; int to = -1; struct bw_cmd *cmd = NULL; if (argc <= 1 || argc > 5) goto block_usage; for (i = 0; i < BWRITE_CMD_MAX; i++) { if (sigcmp(argv[0], bw_cmdtab[i].cmdstr, bw_cmdtab[i].sig_chars)) { cmd = &bw_cmdtab[i]; break; } } if (!cmd) { dbprintf(_("write: invalid subcommand\n")); goto block_usage; } if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) { dbprintf(_("write %s: invalid number of arguments\n"), cmd->cmdstr); goto block_usage; } if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc)) shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0); if (cmd->start_arg && (cmd->start_arg < argc)) start = (int)strtoul(argv[cmd->start_arg], NULL, 0); if (cmd->len_arg && (cmd->len_arg < argc)) len = (int)strtoul(argv[cmd->len_arg], NULL, 0); if (cmd->from_arg && (cmd->len_arg < argc)) from = (int)strtoul(argv[cmd->from_arg], NULL, 0); if (cmd->to_arg && (cmd->len_arg < argc)) to = (int)strtoul(argv[cmd->to_arg], NULL, 0); cmd->cmdfunc(start, len, shiftcount, from, to); /* write back to disk */ write_cur(); return; block_usage: dbprintf(_("usage: write (in data mode)\n")); for (i = 0; i < BWRITE_CMD_MAX; i++) { dbprintf(" %-9.9s %s\n", bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage); } dbprintf("\n"); return; } xfsprogs-5.3.0/db/write.h0000644000175000017500000000057713435336036015153 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct field; extern void write_init(void); extern void write_block(const field_t *fields, int argc, char **argv); extern void write_struct(const field_t *fields, int argc, char **argv); extern void write_string(const field_t *fields, int argc, char **argv); xfsprogs-5.3.0/db/xfs_admin.sh0000755000175000017500000000260713435336036016153 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # status=0 DB_OPTS="" REPAIR_OPTS="" USAGE="Usage: xfs_admin [-efjlpuV] [-c 0|1] [-L label] [-U uuid] device" while getopts "efjlpuc:L:U:V" c do case $c in c) REPAIR_OPTS=$REPAIR_OPTS" -c lazycount="$OPTARG;; e) DB_OPTS=$DB_OPTS" -c 'version extflg'";; f) DB_OPTS=$DB_OPTS" -f";; j) DB_OPTS=$DB_OPTS" -c 'version log2'";; l) DB_OPTS=$DB_OPTS" -r -c label";; L) DB_OPTS=$DB_OPTS" -c 'label "$OPTARG"'";; p) DB_OPTS=$DB_OPTS" -c 'version projid32bit'";; u) DB_OPTS=$DB_OPTS" -r -c uuid";; U) DB_OPTS=$DB_OPTS" -c 'uuid "$OPTARG"'";; V) xfs_db -p xfs_admin -V status=$? exit $status ;; \?) echo $USAGE 1>&2 exit 2 ;; esac done set -- extra $@ shift $OPTIND case $# in 1) if [ -n "$DB_OPTS" ] then eval xfs_db -x -p xfs_admin $DB_OPTS $1 status=$? fi if [ -n "$REPAIR_OPTS" ] then # Hide normal repair output which is sent to stderr # assuming the filesystem is fine when a user is # running xfs_admin. # Ideally, we need to improve the output behaviour # of repair for this purpose (say a "quiet" mode). eval xfs_repair $REPAIR_OPTS $1 2> /dev/null status=`expr $? + $status` if [ $status -ne 0 ] then echo "Conversion failed, is the filesystem unmounted?" fi fi ;; *) echo $USAGE 1>&2 exit 2 ;; esac exit $status xfsprogs-5.3.0/db/xfs_metadump.sh0000755000175000017500000000141613435336036016674 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved. # OPTS=" " DBOPTS=" " USAGE="Usage: xfs_metadump [-aefFogwV] [-m max_extents] [-l logdev] source target" while getopts "aefgl:m:owFV" c do case $c in a) OPTS=$OPTS"-a ";; e) OPTS=$OPTS"-e ";; g) OPTS=$OPTS"-g ";; m) OPTS=$OPTS"-m "$OPTARG" ";; o) OPTS=$OPTS"-o ";; w) OPTS=$OPTS"-w ";; f) DBOPTS=$DBOPTS" -f";; l) DBOPTS=$DBOPTS" -l "$OPTARG" ";; F) DBOPTS=$DBOPTS" -F";; V) xfs_db -p xfs_metadump -V status=$? exit $status ;; \?) echo $USAGE 1>&2 exit 2 ;; esac done set -- extra $@ shift $OPTIND case $# in 2) xfs_db$DBOPTS -i -p xfs_metadump -c "metadump$OPTS $2" $1 status=$? ;; *) echo $USAGE 1>&2 exit 2 ;; esac exit $status xfsprogs-5.3.0/db/xfs_ncheck.sh0000755000175000017500000000125513435336036016314 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # OPTS=" " DBOPTS=" " USAGE="usage: xfs_ncheck [-sfV] [-l logdev] [-i ino]... special" while getopts "b:fi:l:svV" c do case $c in s) OPTS=$OPTS"-s ";; i) OPTS=$OPTS"-i "$OPTARG" ";; v) OPTS=$OPTS"-v ";; f) DBOPTS=$DBOPTS" -f";; l) DBOPTS=$DBOPTS" -l "$OPTARG" ";; V) xfs_db -p xfs_ncheck -V status=$? exit $status ;; \?) echo $USAGE 1>&2 exit 2 ;; esac done set -- extra $@ shift $OPTIND case $# in 1) xfs_db$DBOPTS -r -p xfs_ncheck -c "blockget -ns" -c "ncheck$OPTS" $1 status=$? ;; *) echo $USAGE 1>&2 exit 2 ;; esac exit $status xfsprogs-5.3.0/debian/Makefile0000644000175000017500000000176113435336036016141 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LSRCFILES = changelog compat control copyright rules watch DEV_DOC_DIR = $(PKG_DOC_DIR)/../xfslibs-dev BOOT_MKFS_BIN = $(TOPDIR)/mkfs/mkfs.xfs-xfsprogs-udeb LDIRDIRT = xfslibs-dev xfsprogs xfsprogs-udeb LDIRT = files *.log *.substvars *.debhelper default: include $(BUILDRULES) install: default ifeq ($(PKG_DISTRIBUTION), debian) $(INSTALL) -m 755 -d $(PKG_DOC_DIR) $(INSTALL) -m 644 changelog $(PKG_DOC_DIR)/changelog.Debian endif install-dev: default ifeq ($(PKG_DISTRIBUTION), debian) $(INSTALL) -m 755 -d $(PKG_DOC_DIR) $(INSTALL) -m 755 -d $(DEV_DOC_DIR) $(INSTALL) -m 644 copyright $(DEV_DOC_DIR) $(INSTALL) -m 644 changelog $(DEV_DOC_DIR)/changelog.Debian endif install-d-i: default ifeq ($(PKG_DISTRIBUTION), debian) $(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR) $(INSTALL) -m 755 $(BOOT_MKFS_BIN) $(PKG_ROOT_SBIN_DIR)/mkfs.xfs endif xfsprogs-5.3.0/debian/changelog0000644000175000017500000007200413570057155016353 0ustar nathansnathansxfsprogs (5.3.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 15 Nov 2019 14:57:03 -0500 xfsprogs (5.3.0-rc2-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Thu, 07 Nov 2019 11:12:30 -0500 xfsprogs (5.3.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Wed, 28 Aug 2019 10:59:10 -0500 xfsprogs (5.3.0-rc0-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Fri, 16 Aug 2019 12:14:23 -0500 xfsprogs (5.2.1-1) unstable; urgency=low * New upstream release -- Nathan Scott Wed, 21 Aug 2019 10:42:23 -0500 xfsprogs (5.2.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 09 Aug 2019 11:39:01 -0500 xfsprogs (5.1.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 19 Jul 2019 12:38:19 -0500 xfsprogs (5.1.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Thu, 11 Jul 2019 20:53:37 -0400 xfsprogs (5.1.0-rc0-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Tue, 07 May 2019 21:27:56 -0500 xfsprogs (5.0.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 03 May 2019 11:55:58 -0500 xfsprogs (5.0.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Fri, 26 Apr 2019 16:18:28 -0500 xfsprogs (4.20.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 22 Feb 2019 12:04:48 -0600 xfsprogs (4.20.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Fri, 08 Feb 2019 12:17:15 -0600 xfsprogs (4.19.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 09 Nov 2018 14:20:39 -0600 xfsprogs (4.19.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Fri, 02 Nov 2018 09:40:25 -0500 xfsprogs (4.19.0-rc0-1) unstable; urgency=low * New upstream pre-release * Merge libxfs changes from kernel-4.19 -- Nathan Scott Wed, 10 Oct 2018 17:52:48 +1100 xfsprogs (4.18.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 24 Aug 2018 14:45:57 -0500 xfsprogs (4.18.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Wed, 01 Aug 2018 16:44:08 -0500 xfsprogs (4.18.0-rc0-1) unstable; urgency=low * New upstream pre-release * Merge libxfs changes from kernel-4.18 -- Nathan Scott Thu, 05 Jul 2018 15:24:46 -0500 xfsprogs (4.17.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 28 Jun 2018 11:49:17 -0500 xfsprogs (4.17.0-rc1-1) unstable; urgency=low * New upstream pre-release -- Nathan Scott Fri, 22 Jun 2018 13:51:30 -0500 xfsprogs (4.16.1-1) unstable; urgency=low * New upstream release * Remove bashism in fsck.xfs -- Nathan Scott Mon, 30 Apr 2018 21:27:59 -0500 xfsprogs (4.16.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 26 Apr 2018 15:13:07 -0500 xfsprogs (4.15.1-1) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 26 Feb 2018 19:45:12 -0600 xfsprogs (4.15.0-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 23 Feb 2018 13:06:35 -0600 xfsprogs (4.15.0-rc1-1) unstable; urgency=low * Use source-only uploads using quilt format (closes: #144876) * Includes copy_file_range patch for xfs_io (closes: #890716) * Drop libreadline5-dev package dependency (closes: #695875) * Includes old metadump CVE-2012-2150 fix (closes: #793495) * New upstream release (closes: #874209) -- Nathan Scott Wed, 21 Feb 2018 10:52:38 -0600 xfsprogs (4.14.0) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 27 Nov 2017 10:52:38 -0600 xfsprogs (4.13.1) unstable; urgency=low * New upstream release -- Nathan Scott Tue, 26 Sep 2017 20:42:32 -0500 xfsprogs (4.13.0) unstable; urgency=low * New upstream release -- Nathan Scott Tue, 26 Sep 2017 11:40:08 -0500 xfsprogs (4.12.0) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 20 Jul 2017 10:54:03 -0500 xfsprogs (4.11.0) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 05 May 2017 13:22:41 -0500 xfsprogs (4.10.0) unstable; urgency=low * New upstream release -- Nathan Scott Sun, 26 Feb 2017 14:02:20 -0600 xfsprogs (4.9.0) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 05 Jan 2017 16:05:55 -0600 xfsprogs (4.8.0) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 17 Oct 2016 14:13:45 +1100 xfsprogs (4.7.0) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 05 Aug 2016 11:35:57 +1000 xfsprogs (4.5.0) unstable; urgency=low * New upstream release -- Nathan Scott Tue, 15 Mar 2016 12:05:21 +1100 xfsprogs (4.3.0) unstable; urgency=low * New upstream release * Add a postinst to update the initramfs on install/upgrade. (Closes: #804255) -- Nathan Scott Mon, 23 Nov 2015 15:22:56 +1100 xfsprogs (4.2.0) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 07 Sep 2015 10:13:54 +1000 xfsprogs (3.2.4) unstable; urgency=low * New upstream release * Fix xfs_metadump information leak (CVE-2012-2150) -- Nathan Scott Wed, 29 Jul 2015 15:31:27 +1000 xfsprogs (3.2.3) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 01 Jun 2015 11:35:02 +1000 xfsprogs (3.2.2) unstable; urgency=low * New upstream release * Rework dh-autoreconf invocation (closes: #757455) * Update licensing words for headers (closes: #751511) -- Nathan Scott Mon, 10 Nov 2014 20:35:27 +1100 xfsprogs (3.2.1) unstable; urgency=low * New upstream release (closes: #747080) * Add a watch file (closes: #748483) -- Nathan Scott Wed, 16 Jul 2014 13:47:49 +1000 xfsprogs (3.2.0) unstable; urgency=low * New upstream release * Add dh-autoreconf invocation (closes: #725971) -- Nathan Scott Sat, 03 May 2014 15:59:55 +1000 xfsprogs (3.1.11) unstable; urgency=low * New upstream release -- Nathan Scott Wed, 08 May 2013 12:59:56 -0500 xfsprogs (3.1.9) unstable; urgency=low * New upstream release -- Nathan Scott Wed, 31 Oct 2012 13:29:00 +1100 xfsprogs (3.1.8) unstable; urgency=low * New upstream release * Numerous xfs_repair fixes -- Nathan Scott Mon, 19 Mar 2012 14:21:00 +1100 xfsprogs (3.1.7) unstable; urgency=low * New upstream release * Fix libreadline build dependency (closes: #553875) -- Nathan Scott Thu, 17 Nov 2011 08:47:00 +1100 xfsprogs (3.1.6) unstable; urgency=low * New upstream release * Handle upcoming libreadline5-dev removal (closes: #553875) -- Nathan Scott Wed, 11 Oct 2011 16:47:10 +1100 xfsprogs (3.1.5) unstable; urgency=low * New upstream release * No more xfsquota error message for non-quota mounts (closes: #618730) -- Nathan Scott Wed, 31 Mar 2011 09:00:00 +1100 xfsprogs (3.1.4) unstable; urgency=low * New upstream release (32 projid resolution, fsr uses /proc/mounts) * Annotate Debian packages as being team maintained now. * Resolve Lenny upgrade issue with xfsdump (closes: #601988, #601710) -- Nathan Scott Tue, 09 Nov 2010 22:39:04 +1100 xfsprogs (3.1.3) unstable; urgency=low * New upstream release * Enforce building with libblkid (closes: #593320) -- Nathan Scott Thu, 26 Aug 2010 23:06:46 +1000 xfsprogs (3.1.2) unstable; urgency=low * New upstream release * Allow for building on GNU/kFreeBSD (closes: #485796) -- Nathan Scott Mon, 3 May 2010 14:25:43 +1100 xfsprogs (3.1.1) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 28 Jan 2010 20:54:22 +1100 xfsprogs (3.1.0) unstable; urgency=low * New upstream release * Merged German translation (closes: #521389) * Merged German translation update (closes: #557100) * Uptodate po file is provided now (closes: #538962) * Fixed typos in xfs_quota man page (closes: #481715) * Tighten permissions on temp fsr files (closes: #559490) -- Nathan Scott Thu, 10 Dec 2009 09:19:37 +1100 xfsprogs (3.0.4) unstable; urgency=low * New bugfix release * Resolve a libxfs unaligned access (closes: #517553) -- Nathan Scott Thu, 17 Sep 2009 14:32:48 +1000 xfsprogs (3.0.2) unstable; urgency=low * New bugfix release -- Nathan Scott Wed, 06 May 2009 11:29:18 +1000 xfsprogs (3.0.0-1) unstable; urgency=low * New upstream release (closes: #263170) * Remove watch file, xfsprogs is native * Updated dependencies as this requires xfsdump 3 also -- Nathan Scott Wed, 28 Jan 2009 21:15:07 +1100 xfsprogs (2.10.2-1) unstable; urgency=low * New upstream release * No longer ignore -i maxpct option in mkfs.xfs (closes: #500593) * Correct features2 superblock field handling (closes: #473135) * 32 bit emulation on 64 bit kernels works (closes: #485020) * Fix up large sector handling in mkfs (closes: #489421) -- Nathan Scott Sat, 20 Dec 2008 10:14:27 +1100 xfsprogs (2.9.10-1) unstable; urgency=low * New upstream release -- Anibal Monsalve Salazar Fri, 05 Sep 2008 14:02:20 +1000 xfsprogs (2.9.8-1) unstable; urgency=low * New upstream release * xfsprogs and xfsprogs-udeb depend on ${misc:Depends} * Add Homepage control header * Add watch file * Fix the following lintian issues: W: xfsprogs source: package-uses-deprecated-debhelper-compat-version 1 W: xfsprogs source: ancient-standards-version 3.5.9 (current is 3.7.3) W: xfslibs-dev: package-contains-empty-directory usr/share/doc/xfsprogs/ -- Anibal Monsalve Salazar Tue, 22 Apr 2008 13:04:05 +1000 xfsprogs (2.9.7-1) unstable; urgency=high * New upstream release. * Add -y fsck option (closes: #463810) * Lazy superblock counters not yet mkfs default (closes: #465737, #468184) * xfs_repair memory requirements significantly reduced (closes: #289665) -- Nathan Scott Sat, 01 Mar 2008 06:24:21 +1100 xfsprogs (2.9.5-1) unstable; urgency=low * New upstream release. -- Nathan Scott Tue, 22 Jan 2008 16:46:18 +1100 xfsprogs (2.9.0-1) unstable; urgency=low * New upstream release. -- Nathan Scott Tue, 12 Jun 2007 07:22:21 +1000 xfsprogs (2.8.20-1) unstable; urgency=low * New upstream release (closes: #414079) * Fixed up autoconf version dependency (closes: #414073) -- Nathan Scott Fri, 16 Mar 2007 08:24:33 +1100 xfsprogs (2.8.19-1) unstable; urgency=low * New upstream release (closes: #409063) -- Nathan Scott Wed, 31 Jan 2007 08:53:32 +1100 xfsprogs (2.8.18-1) unstable; urgency=low * New upstream release (closes: #399888) -- Nathan Scott Fri, 08 Dec 2006 08:30:29 +1100 xfsprogs (2.8.12-1) unstable; urgency=low * New upstream release. -- Nathan Scott Tue, 29 Aug 2006 14:28:05 +1000 xfsprogs (2.8.11-1) unstable; urgency=low * New upstream release. * More efficient use of buffer cache memory (closes: #382935) -- Nathan Scott Tue, 08 Aug 2006 17:06:58 +1000 xfsprogs (2.8.10-1) unstable; urgency=low * New upstream release. -- Nathan Scott Wed, 02 Aug 2006 11:17:07 +1000 xfsprogs (2.8.4-1) unstable; urgency=low * New upstream release. * Improved udeb packaging, thanks to Frans Pop (closes: #375439) * Fix filesystem-from-path detection logic (closes: #374687) -- Nathan Scott Mon, 26 Jun 2006 10:04:18 +1000 xfsprogs (2.8.3-1) unstable; urgency=low * New upstream release. * Fix segv in xfs_growfs command (closes: #374686) * Ensure source tarball in correct location (closes: #374696) -- Nathan Scott Wed, 21 Jun 2006 15:19:56 +1000 xfsprogs (2.7.16-1) unstable; urgency=low * New upstream release. -- Nathan Scott Wed, 05 Apr 2006 11:45:58 +1000 xfsprogs (2.7.14-1) unstable; urgency=low * New upstream release. * Switch from debmake to debhelper -- Nathan Scott Wed, 15 Feb 2006 20:04:55 +1100 xfsprogs (2.7.12-1) unstable; urgency=low * New upstream release. * Includes polish translation from Jakub Bogusz. -- Nathan Scott Tue, 31 Jan 2006 13:35:39 +1100 xfsprogs (2.7.7-1) unstable; urgency=low * New upstream release. * Add support for (optional) ATTR2 format extension (closes: #336350) * Allow gcc -pedantic option for C++ users (closes: #249429) * Fix segv in xfs_db frag command (closes: #338207) -- Nathan Scott Wed, 16 Nov 2005 16:32:35 +1100 xfsprogs (2.7.4-1) unstable; urgency=low * New upstream release. -- Nathan Scott Sat, 08 Oct 2005 10:34:10 +1000 xfsprogs (2.6.36-1) unstable; urgency=low * New upstream release. * Fix xfs_repair secondary SB search 32 bit wrap (closes: #320081) -- Nathan Scott Thu, 28 Jul 2005 14:01:50 +1000 xfsprogs (2.6.28-1) unstable; urgency=low * New upstream release. * Fix compilation with gcc version 4 (closes: #300544) -- Nathan Scott Wed, 30 Mar 2005 10:52:07 +1000 xfsprogs (2.6.26-2) unstable; urgency=low * No code differences, recompiled with a more recent gcc version. -- Nathan Scott Tue, 29 Mar 2005 11:57:57 +1000 xfsprogs (2.6.26-1) unstable; urgency=low * New upstream release. * Man page updates (closes: #295397) * Fix compilation with gcc version 4 (closes: #297876) * Switch build dependency from readline4 to readline5. -- Nathan Scott Tue, 08 Mar 2005 16:56:35 +1100 xfsprogs (2.6.23-1) unstable; urgency=low * New upstream release. -- Nathan Scott Fri, 17 Sep 2004 17:04:45 +1000 xfsprogs (2.6.21-1) unstable; urgency=low * New upstream release. * Fix xfs_io build for older glibc versions (current stable). -- Nathan Scott Mon, 09 Aug 2004 16:09:42 +1000 xfsprogs (2.6.20-1) unstable; urgency=low * New upstream release. * Fix xfs_io segfault on non-XFS files. (closes: #260470) * Fix packaging botch, deleted files included. (closes: #260491) -- Nathan Scott Wed, 28 Jul 2004 21:11:38 +1000 xfsprogs (2.6.19-1) unstable; urgency=low * New upstream release. -- Nathan Scott Sat, 17 Jul 2004 11:28:39 +1000 xfsprogs (2.6.18-1) unstable; urgency=low * New upstream release. -- Nathan Scott Fri, 25 Jun 2004 16:57:09 +1000 xfsprogs (2.6.15-1) unstable; urgency=low * New upstream release. -- Nathan Scott Wed, 09 Jun 2004 21:10:14 +1000 xfsprogs (2.6.14-1) unstable; urgency=low * New upstream release. * Add a Provides: fsck-backend clause as requested in the context of bug number 111651. -- Nathan Scott Thu, 13 May 2004 09:56:19 +1000 xfsprogs (2.6.11-1) unstable; urgency=low * New upstream release. -- Nathan Scott Fri, 16 Apr 2004 11:50:56 +1000 xfsprogs (2.6.5-1) unstable; urgency=low * New upstream release. -- Nathan Scott Thu, 26 Feb 2004 14:44:41 +1100 xfsprogs (2.6.3-1) unstable; urgency=low * New upstream release. * Add support for debian-installer. (closes: #225444) Author: Steve Langasek. * Use debhelper instead of debmake, for proper udeb building. Author: Steve Langasek. * Drop boot-floppies support. (closes: #112715) Author: Steve Langasek. * Add support for the security attribute namespace. -- Nathan Scott Mon, 19 Jan 2004 10:08:59 +1100 xfsprogs (2.6.0-1) unstable; urgency=low * New upstream release. * Note: change in the mkfs algorithm for sizing allocation groups. -- Nathan Scott Tue, 28 Oct 2003 15:23:48 +1100 xfsprogs (2.5.11-1) unstable; urgency=low * New upstream release. -- Nathan Scott Fri, 10 Oct 2003 09:37:57 +1000 xfsprogs (2.5.6-1) unstable; urgency=low * New upstream release. -- Nathan Scott Tue, 19 Aug 2003 09:44:48 +1000 xfsprogs (2.5.5-1) unstable; urgency=low * New upstream release. -- Nathan Scott Thu, 07 Aug 2003 12:58:36 +1000 xfsprogs (2.5.4-1) unstable; urgency=low * New upstream release, includes xfs_copy command * Fix shell quoting in xfs_bmap, from Kai S. Juse (closes: #202588) -- Nathan Scott Wed, 23 Jul 2003 10:36:28 +1000 xfsprogs (2.5.3-1) unstable; urgency=low * New upstream release * Changed mkfs.xfs default log size scaling algorithm slightly, to create larger logs at smaller filesystem sizes by default * Enable support for sector sizes larger than 512 bytes -- Nathan Scott Mon, 7 Jul 2003 16:06:21 +1000 xfsprogs (2.4.12-1) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 2 Jun 2003 13:51:06 +1000 xfsprogs (2.4.10-1) unstable; urgency=low * New upstream release * Add missing xfslibs-dev dependency on uuid-dev (closes: #193309) -- Nathan Scott Thu, 15 May 2003 08:50:22 +1000 xfsprogs (2.4.9-1) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 2 May 2003 09:34:17 +1000 xfsprogs (2.4.4-1) unstable; urgency=low * New upstream release * Dependencies on libreadline4 and libreadline4-dev added -- Nathan Scott Sun, 30 Mar 2003 10:30:18 +1000 xfsprogs (2.4.1-1) unstable; urgency=low * New upstream release * Updated policy version to which this package conforms * Note: unwritten extents are now enabled by default in mkfs.xfs -- Nathan Scott Tue, 18 Mar 2003 16:16:43 +1100 xfsprogs (2.3.11-1) unstable; urgency=low * Add missing build dependency on gettext (closes: #181331) -- Nathan Scott Tue, 18 Feb 2003 08:57:46 +1100 xfsprogs (2.3.10-1) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 17 Feb 2003 14:52:20 +1100 xfsprogs (2.3.6-1) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 31 Oct 2002 17:26:44 +1100 xfsprogs (2.3.5-1) unstable; urgency=low * New upstream release * Fix mkfs bug, patch from Anton Blanchard (closes: #163897) -- Nathan Scott Mon, 7 Oct 2002 05:19:51 +1000 xfsprogs (2.3.4-1) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 7 Oct 2002 05:19:51 +1000 xfsprogs (2.3.0-1) unstable; urgency=low * New upstream release * Improve backwards compatibility of tools using the XFS geometry ioctl for older kernel versions which don't support the new ioctl -- Nathan Scott Tue, 3 Sep 2002 09:55:48 +1000 xfsprogs (2.2.1-1) unstable; urgency=low * New upstream release * Default mkfs.xfs blocksize is now 4096 bytes, not getpagesize(2) * Fix to allow install process to work for newer autoconf versions -- Nathan Scott Wed, 7 Aug 2002 11:37:23 +1000 xfsprogs (2.1.2-1) unstable; urgency=low * New upstream release * Support for the XFS version 2 log format -- Nathan Scott Tue, 30 Jul 2002 09:49:08 +1000 xfsprogs (2.0.6-2) unstable; urgency=low * Fix a problem in xfs_repair's handling of ACLs -- Nathan Scott Thu, 30 May 2002 17:22:05 +1000 xfsprogs (2.0.6-1) unstable; urgency=low * New upstream release -- Nathan Scott Thu, 30 May 2002 14:31:30 +1000 xfsprogs (2.0.4-1) unstable; urgency=low * New upstream release, minor changes only -- Nathan Scott Wed, 17 Apr 2002 15:30:52 +1000 xfsprogs (2.0.3-1) unstable; urgency=low * New upstream bugfix release -- Nathan Scott Sat, 13 Apr 2002 09:45:06 +1000 xfsprogs (2.0.2-1) unstable; urgency=low * New upstream bugfix release -- Nathan Scott Thu, 4 Apr 2002 12:11:01 +1100 xfsprogs (2.0.1-1) unstable; urgency=low * New upstream bugfix (minor) release -- Nathan Scott Tue, 12 Mar 2002 13:25:32 +1100 xfsprogs (2.0.0-1) unstable; urgency=low * New upstream release with support for new libhandle interfaces * Major release for switch to official extended attributes syscalls -- Nathan Scott Thu, 7 Feb 2002 13:25:26 +1100 xfsprogs (1.3.18-1) unstable; urgency=low * New upstream bugfix (minor) release -- Nathan Scott Thu, 17 Jan 2002 11:13:19 +1100 xfsprogs (1.3.17-1) unstable; urgency=low * New upstream release * mkfs.xfs overwrites other filesystem signatures * xfs_repair fix for "avl_insert: duplicate range" bug -- Nathan Scott Mon, 14 Jan 2002 10:59:50 +1100 xfsprogs (1.3.16-1) unstable; urgency=low * Remove temporary file use in xfs_db * Add "type text" command into xfs_db -- Nathan Scott Mon, 17 Dec 2001 12:17:54 +1100 xfsprogs (1.3.15-1) unstable; urgency=low * Fix minor package version numbering issue (closes: #117545) * Fix bug in mkfs.xfs device size cross-check for realtime device * Reenable use of the BLKBSZSET ioctl in libxfs -- Nathan Scott Wed, 12 Dec 2001 09:25:42 +1100 xfsprogs (1.3.14-1) unstable; urgency=low * Fix minor package version numbering issue (closes: #117545) * Fix bug in mkfs.xfs device size cross-check for realtime device -- Nathan Scott Wed, 5 Dec 2001 17:13:06 +1100 xfsprogs (1.3.13-0) unstable; urgency=low * New upstream release * Fixes an important mkfs.xfs bug for >1TB filesystems * xfs_repair will no longer blindly zero a dirty log -- Nathan Scott Fri, 26 Oct 2001 10:42:26 +1000 xfsprogs (1.3.11-0) unstable; urgency=low * Upstream release fixing several issues on 64 bit platforms -- Nathan Scott Wed, 17 Oct 2001 10:00:35 +1000 xfsprogs (1.3.10-0) unstable; urgency=low * New upstream release * Fix up some issues building the bootfloppies package -- Nathan Scott Fri, 12 Oct 2001 17:43:20 +1000 xfsprogs (1.3.9-0) unstable; urgency=low * Upstream bug fix release * Additional and updated manual page entries -- Nathan Scott Fri, 5 Oct 2001 14:39:47 +1000 xfsprogs (1.3.8-0) unstable; urgency=low * New upstream release * Fix inclusion of mkfs man page in boot floppies package (closes: #112634) -- Nathan Scott Wed, 19 Sep 2001 14:49:30 +1000 xfsprogs (1.3.7-0) unstable; urgency=low * New upstream release * Change to libhandle licensing (was GPL, now LGPL-2.1) * Create a boot-floppies package with smaller mkfs.xfs (closes: #111426) * Make install-sh posix compliant so ash as /bin/sh works (closes: #111985) -- Nathan Scott Mon, 10 Sep 2001 10:52:04 +1000 xfsprogs (1.3.5-0) unstable; urgency=low * Upstream bugfix release; fixes listed below * Fix bug in xfs_db bit handling on big endian platforms * Fix mkfs.xfs bug related to too-small final allocation group * Fix signedness bug in DMAPI ioctl structure definition -- Nathan Scott Mon, 13 Aug 2001 09:38:27 +1000 xfsprogs (1.3.4-0) unstable; urgency=low * Upstream bugfix release; fixes listed below * Fix endian bug in xfs_db "frag" command * Several man pages updated to document external log usage * IA64 build issues fixed (use -fno-strict-aliasing for libraries) * Fixed several minor compiler warnings when building on IA64 * Added a Suggests entry for dvhtool (for those using SGI disks) * configure.in changes to allow cross compilation -- Nathan Scott Sat, 4 Aug 2001 10:32:00 +1000 xfsprogs (1.3.3-0) unstable; urgency=low * New upstream release -- Nathan Scott Fri, 27 Jul 2001 07:59:49 +1000 xfsprogs (1.3.2-0) unstable; urgency=low * New upstream release -- Nathan Scott Mon, 23 Jul 2001 10:27:37 +1000 xfsprogs (1.3.1-0) unstable; urgency=low * Reworked package slightly so that it's not Debian native * Debian-specific changes now documented in changelog.Debian.gz * New upstream release (see /usr/share/doc/xfsprogs/changelog.gz) * Checked standards compliance - update standards version to 3.5.5 -- Nathan Scott Sat, 15 Jul 2001 16:34:43 +1000 xfsprogs (1.3.0) unstable; urgency=low * Reworked Makefiles to use libtool * New libdisk to allow sharing of generic mount/disk code and * Also abstracts individual driver support (LVM, MD, XVM..) * Partition table detection so mkfs.xfs doesn't blindly overwrite * Small xfs_repair bug fix from Steve -- Nathan Scott Thu, 19 Jul 2001 10:12:03 +1000 xfsprogs (1.2.8) unstable; urgency=low * Fixed a bug in libxfs /etc/mtab read-only mount detection * First try procfs, fall back to /etc/mtab, for read-only mounts * Sync with recent mount code changes for reiserfs and ext3 probes * Fix logprint build problem under gcc 3.0 -- Nathan Scott Mon, 2 Jul 2001 13:59:08 +1000 xfsprogs (1.2.7) unstable; urgency=low * New xfs_freeze(8) command - volume manager snapshot helper -- Nathan Scott Tue, 22 May 2001 17:22:32 +1000 xfsprogs (1.2.6) unstable; urgency=low * Merge support for -d agsize=/su=/sw= (AG, stripe unit/width size) * Merge support for dynamic configuration of default log size * Document these updates, and fix a couple of man page typos too -- Nathan Scott Tue, 15 May 2001 12:34:17 +1000 xfsprogs (1.2.5) unstable; urgency=low * Fix missing Makefile include entries for LVM headers * Add experimental xfs_rtcp (realtime copy) command * PowerPC build failure fixups - thanks to Robert Ramiega * Cleanup arch-specific code, esp. the byteswab routines * Suggests xfsdump and attr packages -- Nathan Scott Tue, 8 May 2001 15:50:27 +1000 xfsprogs (1.2.4) unstable; urgency=low * Add -L option to mkfs.xfs (filesystem label) -- Nathan Scott Tue, 1 May 2001 14:03:14 +1000 xfsprogs (1.2.3) unstable; urgency=low * Add dquot and quotaoff log item support into xfs_logprint * Fix logprint core dump reporting AGI in "continue"'d transactions -- Nathan Scott Fri, 27 Apr 2001 10:17:25 +1000 xfsprogs (1.2.2) unstable; urgency=low * Fix problem in xfs_db (check) group quota logic * Fixes to warnings from recent gcc and/or 64-bit builds -- Nathan Scott Fri, 13 Apr 2001 09:50:37 +1000 xfsprogs (1.2.1) unstable; urgency=low * Support for group quota added * Stripe unit/stripe width extraction for MD devices * Added mkfs.xfs heuristics for size of internal log * Sync up with recent changes to XFS kernel headers -- Nathan Scott Wed, 4 Apr 2001 13:54:00 +1000 xfsprogs (1.1.6) unstable; urgency=low * Fix sparc build failure - fcntl.h missing O_DIRECT (closes: #90211) * Added README.quota describing the use of quota with XFS -- Nathan Scott Tue, 20 Mar 2001 11:25:03 +1100 xfsprogs (1.1.5) unstable; urgency=low * Upgraded LVM stripe unit/width support to 0.9beta2 (IOP 10) * Kernel now supports O_DIRECT - re-enable its use in xfs_mkfile * BLKSETSIZE ioctl replaced by BLKBSZSET ioctl in libxfs * libxfs_init extended so only mkfs and xfs_repair use BLKBSZSET * NOTE: this requires an XFS kernel from 9 March '01 or later -- Nathan Scott Sun, 18 Mar 2001 14:31:17 +1100 xfsprogs (1.1.3) unstable; urgency=low * Minor changes to xfs_logprint tail verification * Update build Makefile to pick up extra dirt before packaging -- Nathan Scott Thu, 1 Mar 2001 12:24:28 +1100 xfsprogs (1.1.2) unstable; urgency=low * Fix stdarg.h issue causing build failure with glibc 2.2.2 * Changes to libhandle for supporting extended attributes -- Nathan Scott Tue, 20 Feb 2001 08:29:36 +1100 xfsprogs (1.1.0) unstable; urgency=low * Initial release (closes: #83829) -- Nathan Scott Thu, 4 Jan 2001 11:15:11 -0500 Local variables: mode: debian-changelog End: xfsprogs-5.3.0/debian/compat0000644000175000017500000000000213245074644015675 0ustar nathansnathans9 xfsprogs-5.3.0/debian/control0000644000175000017500000000470513466663244016115 0ustar nathansnathansSource: xfsprogs Section: admin Priority: optional Maintainer: XFS Development Team Uploaders: Nathan Scott , Anibal Monsalve Salazar Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libicu-dev, dh-python, pkg-config Standards-Version: 4.0.0 Homepage: https://xfs.wiki.kernel.org/ Package: xfsprogs Depends: ${shlibs:Depends}, ${misc:Depends}, python3:any, util-linux Provides: fsck-backend Suggests: xfsdump, acl, attr, quota Breaks: xfsdump (<< 3.0.0) Replaces: xfsdump (<< 3.0.0) Architecture: any Description: Utilities for managing the XFS filesystem A set of commands to use the XFS filesystem, including mkfs.xfs. . XFS is a high performance journaling filesystem which originated on the SGI IRIX platform. It is completely multi-threaded, can support large files and large filesystems, extended attributes, variable block sizes, is extent based, and makes extensive use of Btrees (directories, extents, free space) to aid both performance and scalability. . Refer to the documentation at https://xfs.wiki.kernel.org/ for complete details. Package: xfslibs-dev Section: libdevel Priority: extra Depends: libc6-dev | libc-dev, uuid-dev, xfsprogs (>= 3.0.0), ${misc:Depends} Breaks: xfsprogs (<< 3.0.0) Architecture: any Description: XFS filesystem-specific static libraries and headers xfslibs-dev contains the libraries and header files needed to develop XFS filesystem-specific programs. . XFS is a high performance journaling filesystem which originated on the SGI IRIX platform. It is completely multi-threaded, can support large files and large filesystems, extended attributes, variable block sizes, is extent based, and makes extensive use of Btrees (directories, extents, free space) to aid both performance and scalability. . Refer to the documentation at https://xfs.wiki.kernel.org/ for complete details. Package: xfsprogs-udeb XC-Package-Type: udeb Section: debian-installer Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: A stripped-down version of xfsprogs, for debian-installer This package is an xfsprogs package built for reduced size, so that it can help to save space in debian-installer. . Don't attempt to install this package, it has no support for a couple of features you surely want. Anyway, it should fail to install. xfsprogs-5.3.0/debian/copyright0000644000175000017500000000135313242461543016427 0ustar nathansnathansThis package was debianized by Nathan Scott nathans@debian.org on Sun, 19 Nov 2000 07:37:09 -0500. It can be downloaded from https://www.kernel.org/pub/linux/utils/fs/xfs/xfsprogs/ Copyright: Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. You are free to distribute this software under the terms of the GNU General Public License. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL file. The library named "libhandle" and the headers in "xfslibs-dev" are licensed under Version 2.1 of the GNU Lesser General Public License. On Debian systems, refer to /usr/share/common-licenses/LGPL-2.1 for the complete text of the GNU Lesser General Public License. xfsprogs-5.3.0/debian/local/initramfs.hook0000644000175000017500000000152213435336036020444 0ustar nathansnathans#!/bin/sh # Put XFS utilities in initramfs if the root fs is XFS. PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac fstab_files() { echo /etc/fstab if [ -d /etc/fstab.d ]; then ls -1 /etc/fstab.d | grep '\.fstab$' | sed -e 's;^;/etc/fstab.d/;' fi } rootfs_type() { fstab_files | while read file; do test ! -f "$file" && continue while read MNT_FSNAME MNT_DIR MNT_TYPE MNT_OPTS MNT_FREQ MNT_PASS MNT_JUNK; do case "$MNT_FSNAME" in ""|\#*) continue; ;; esac test "$MNT_DIR" != "/" && continue echo "$MNT_TYPE" break; done < "$file" done } . /usr/share/initramfs-tools/scripts/functions . /usr/share/initramfs-tools/hook-functions if [ "$(rootfs_type)" = "xfs" ]; then copy_exec /sbin/xfs_repair copy_exec /usr/sbin/xfs_db copy_exec /usr/sbin/xfs_metadump fi exit 0 xfsprogs-5.3.0/debian/postinst0000644000175000017500000000063413245144512016300 0ustar nathansnathans#!/bin/sh set -e case "${1}" in configure) if [ -x /usr/sbin/update-initramfs ] && [ -e /etc/initramfs-tools/initramfs.conf ] then update-initramfs -u fi if [ -x /bin/systemctl ]; then /bin/systemctl daemon-reload 2>&1 || true fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`${1}'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 xfsprogs-5.3.0/debian/rules0000755000175000017500000000602413466663244015566 0ustar nathansnathans#!/usr/bin/make -f export DH_VERBOSE=1 ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) PMAKEFLAGS += -j$(NUMJOBS) endif package = xfsprogs develop = xfslibs-dev bootpkg = xfsprogs-udeb version = $(shell dpkg-parsechangelog | grep ^Version: | cut -d ' ' -f 2 | cut -d '-' -f 1) target ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) udebpkg = $(bootpkg)_$(version)_$(target).udeb dirme = debian/$(package) dirdev = debian/$(develop) dirdi = debian/$(bootpkg) pkgme = DIST_ROOT=`pwd`/$(dirme); export DIST_ROOT; pkgdev = DIST_ROOT=`pwd`/$(dirdev); export DIST_ROOT; pkgdi = DIST_ROOT=`pwd`/$(dirdi); export DIST_ROOT; stdenv = @GZIP=-q; export GZIP; options = export DEBUG=-DNDEBUG DISTRIBUTION=debian \ INSTALL_USER=root INSTALL_GROUP=root \ LOCAL_CONFIGURE_OPTIONS="--enable-readline=yes --enable-blkid=yes --disable-ubsan --disable-addrsan --disable-threadsan --enable-lto" ; diopts = $(options) \ export OPTIMIZER=-Os LOCAL_CONFIGURE_OPTIONS="--enable-gettext=no --disable-ubsan --disable-addrsan --disable-threadsan --enable-lto" ; checkdir = test -f debian/rules build: build-arch build-indep build-arch: built build-indep: built built: dibuild config @echo "== dpkg-buildpackage: build" 1>&2 $(MAKE) $(PMAKEFLAGS) default touch built config: .census .census: @echo "== dpkg-buildpackage: configure" 1>&2 $(checkdir) AUTOHEADER=/bin/true dh_autoreconf $(options) $(MAKE) $(PMAKEFLAGS) include/platform_defs.h touch .census dibuild: $(checkdir) @echo "== dpkg-buildpackage: installer" 1>&2 if [ ! -f mkfs/mkfs.xfs-$(bootpkg) ]; then \ $(diopts) $(MAKE) include/platform_defs.h; \ mkdir -p include/xfs; \ for dir in include libxfs; do \ $(MAKE) $(PMAKEFLAGS) -C $$dir NODEP=1 install-headers; \ done; \ for dir in include libxfs libxcmd libfrog mkfs; do \ $(MAKE) $(PMAKEFLAGS) $$dir; \ done; \ mv mkfs/mkfs.xfs mkfs/mkfs.xfs-$(bootpkg); \ $(MAKE) distclean; \ fi clean: @echo "== dpkg-buildpackage: clean" 1>&2 $(checkdir) -rm -f built .census mkfs/mkfs.xfs-$(bootpkg) $(MAKE) distclean -rm -rf $(dirme) $(dirdev) $(dirdi) -rm -f debian/*substvars debian/files* debian/*.debhelper dh_autoreconf_clean dh_clean binary-indep: binary-arch: checkroot built @echo "== dpkg-buildpackage: binary-arch" 1>&2 $(checkdir) -rm -rf $(dirme) $(dirdev) $(dirdi) $(pkgme) $(MAKE) -C . install $(pkgdev) $(MAKE) -C . install-dev $(pkgdi) $(MAKE) -C debian install-d-i $(pkgme) $(MAKE) dist install -D -m 0755 debian/local/initramfs.hook debian/xfsprogs/usr/share/initramfs-tools/hooks/xfs rmdir debian/xfslibs-dev/usr/share/doc/xfsprogs rm -f debian/xfslibs-dev/lib/libhandle.la rm -f debian/xfslibs-dev/lib/libhandle.a rm -fr debian/xfslibs-dev/usr/lib dh_installdocs dh_installchangelogs dh_strip dh_compress dh_fixperms dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch checkroot: test 0 -eq `id -u` .PHONY: binary binary-arch binary-indep clean checkroot xfsprogs-5.3.0/debian/source/format0000644000175000017500000000001413245074644017205 0ustar nathansnathans3.0 (quilt) xfsprogs-5.3.0/debian/watch0000644000175000017500000000024613242461543015525 0ustar nathansnathansversion=3 opts=uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \ https://www.kernel.org/pub/linux/utils/fs/xfs/xfsprogs/xfsprogs-(.+)\.tar\.xz xfsprogs-5.3.0/doc/CHANGES0000644000175000017500000027150313570057155015024 0ustar nathansnathansxfsprogs-5.3.0 (15 Nov 2019) - No further changes xfsprogs-5.3.0-rc2 (07 Nov 2019) - mkfs.xfs: use libxfs to write out AGs vs. open-coding (Darrick Wong) - mkfs.xfs: fix incorrect error message during AG init (Darrick Wong) - xfs_repair: better info when metadata updates fail (Darrick Wong) - xfs_growfs: allow mounted device node as argument (Eric Sandeen) - xfs_spaceman: always report sick metadata (Darrick Wong) - xfs_io: add a bulkstat command (Darrick Wong) - xfs_io: encrypt command enhancements (Eric Biggers) - xfs_io: expose FS_XFLAG_HASATTR flag (Amir Goldstein) - xfs_io: copy_file_range fixes (Jianhong Yin) - man: document several new ioctls (Darrick Wong) - xfs_scrub: copious rewriting (Darrick Wong) - libfrog: header moves, refactoring, updates (Darrick Wong) - libxfs: fix buffer refcounting (Darrick Wong) xfsprogs-5.3.0-rc1 (28 Aug 2019) - rebase 5.3 branch on top of 5.2.1 xfsprogs-5.3.0-rc0 (16 Aug 2019) - libxfs changes merged from kernel 5.3 xfsprogs-5.2.1 (21 Aug 2019) - fix geometry calls for kernels older than 5.2 (Eric Sandeen) xfsprogs-5.2.0 (09 Aug 2019) - libxfs: cosmetic changes to trans.c to match kernel (Eric Sandeen) xfsprogs-5.2.0-rc0 (24 Jul 2019) - libxfs changes merged from kernel 5.2 xfsprogs-5.1.0 (19 Jul 2019) - No further changes xfsprogs-5.1.0-rc1 (11 Jul 2019) - mkfs: enable reflink by default (Darrick Wong) - mkfs: fix stripe unit handling (Allison Collins) - mkfs: remove useless log options in usage() (Yang Xu) - mkfs: validate start and end of aligned logs (Darrick Wong) - xfs_quota: fix built-in help for project setup (Eric Sandeen) - xfs_io: allow passing an open file to copy_range (Amir Goldstein) - xfs_info: limit findmnt to mounted xfs filesystems (Amir Goldstein) - man: break out several ioctl man pages (Darrick Wong) - man: Fix an inconsistency in the mkfs man page (Alvin Zheng) - xfs_scrub: fix background-mode sleep throttling (Darrick Wong) - libxfs: sync up xfs_trans_inode.c with the kernel (Eric Sandeen) - libfrog: fix bitmap return values (Darrick Wong) - libfrog: don't set negative errno in conversion f'ns (Darrick Wong) xfsprogs-5.1.0-rc0 (07 May 2019) - libxfs changes merged from kernel 5.1 xfsprogs-5.0.0 (03 May 2019) - xfs_db: scan all sparse inodes when using 'frag' (Jorge Guerra) - Fix build with newer statx headers (Eric Sandeen) xfsprogs-5.0.0-rc1 (26 Apr 2019) - mkfs: validate extent size hint parameters (Darrick Wong) - xfs_repair: bump on-disk nlink when adding lost+found (Darrick Wong) - xfs_repair: reinitialize root directory nlink correctly (Darrick Wong) - xfs_repair: use lenient verifiers for half-fixed inodes (Darrick Wong) - xfs_repair: acct for btree shrinks when fixing freelist (Darrick Wong) - xfs_repair: better cli option parameter checking (Darrick Wong) - xfs_repair: fix deadlock due to failed inode flushes (Dave Chinner) - xfs_info: handle devices, mountpoints, and loop files (Darrick Wong) - xfs_metadump: fix symlink handling (Darrick Wong) - xfs_io: fix label parsing and validation (Darrick Wong) - xfs_io: print attributes_mask in statx (Darrick Wong) - xfs_scrub: fix Make targets which depend on builddefs (Darrick Wong) - xfs_scrub: check label for misleading characters (Darrick Wong) - xfs_scrub: parallelize based on storage not CPUS (Darrick Wong) - xfs_scrub: activate timer only after system is up (Darrick Wong) - libxfs: fix buffer & inode lifetimes (Darrick Wong) - misc: fix strncpy length complaints from gcc (Darrick Wong) - debian build & packaging fixes (Darrick Wong) - Merge libxfs from kernel 5.0 xfsprogs-4.20.0 (22 Feb 2019) - No further changes xfsprogs-4.20.0-rc1 (08 Feb 2019) - mkfs.xfs: null-terminate symlinks created via protofile (Eric Sandeen) - xfs_repair: allow '/' in attribute names (Eric Sandeen) - xfs_repair: skip block reservation when fixing freelist (Darrick Wong) - xfs_repair: rebuild dir when nonroot blocks corrupt (Darrick Wong) - xfs_repair: int nonleaf finobt blocks with proper magic (Brian Foster) - xfs_repair: fix off by one error rebuilding high keys (Darrick Wong) - xfs_io: allow open file permissions to be changed (Dave Chinner) - xfs_io: open pipes in non-blocking mode (Dave Chinner) - xfs_metadump: multiple stale data zeroing fixes (Stefan Ring) - xfs_quota: allow reg files w/o prjinherit flag (Achilles Gaikwad) - xfs_db: properly decode finobt record w/ sparse inodes (Darrick Wong) - xfs_db: fix frag command to work w/ sparse inodes (Eric Sandeen) - xfs_scrub: move all executables to /usr/sbin (Darrick Wong) - xfs_scrub: handle totally empty inode chunks (Darrick Wong) - xfs.5 manpage: Remove barrier related options (Eric Sandeen) - xfs_io.8 manpage: rearrange command listings by section (Darrick Wong) - Remove generated scrub files under make clean (Eric Sandeen) - Skip scrub manpage install if not configured (Eric Sandeen) - Merge libxfs from kernel 4.20 xfsprogs-4.19.0 (09 Nov 2018) - Fix up debian subdir build w.r.t. CHECK_CMD (Darrick Wong) xfsprogs-4.19.0-rc1 (02 Nov 2018) - Remove non-linux platforms (Eric Sandeen) - Remove retpoline support (Eric Sandeen) - Add sparse checking & related fixes/cleanups (Eric Sandeen) - Fix cross-platform building w.r.t. crc32selftest - libxfs: add agfl free deferred op type (Darrick Wong) - mkfs.xfs: discard only after all validations (Jan Tulak) - xfs_repair: fix segfault in longform_dir2_entry_check (Eric Sandeen) - xfs_repair: fix ASSERT in xfs_bunmapi (Eric Sandeen) - xfs_repair: fix readahead thread deadlock/stall (Eric Sandeen) - xfs_repair: avoid writing back all inodes (Dave Chinner) - xfs_repair: don't treat directory root LEAFN as corrupt (Dave Chinner) - xfs_io: add crc32 self test (Darrick Wong) - xfs_io: remove useless do_preadv and do_pwritev arguments (Zorro Lang) - xfs_scrub: make scrub build config-optional (Eric Sandeen) - xfs_scrub: lack of kernel support is not a service failure (Darrick Wong) - xfs_scrub_all: fix systemd escaping (Darrick Wong) xfsprogs-4.19.0-rc0 (10 Oct 2018) - Majority of 4.19 libxfs changes merged from kernel - Big sparse static checker cleanup (Eric Sandeen) - mkfs.xfs discard fixes (Jan Tulak) - xfs_io readv/writev cleanup (Zorro Lang) - libxfs transaction commit error checking (Darrick Wong) xfsprogs-4.18.0 (24 Aug 2018) - Tweak SPDX license in xfs_cksum.h (Darrick Wong) xfsprogs-4.18.0-rc1 (01 Aug 2018) - xfs_repair: notify user if free inodes are corrupt (Eric Sandeen) - xfs_repair: use extent size validation helpers (Darrick Wong) - xfs_quota: don't stop the directory tree walk at DEPTH (Kazuya Mio) - xfs_scrub: ongoing updates (Darrick Wong) - xfs_io: document shutdown -f (Carlos Maiolino) - xfs_io: wire up online repair ioctls (Darrick Wong) - misc: adddebian initramfs hook to package (Darrick Wong) - misc: remove unused macros (Eric Sandeen) - misc: remove many XFS_BUF macros (Carlos Maiolino) - misc: convert to SPDX license tags (Dave Chinner) xfsprogs-4.18.0-rc0 (05 Jul 2018) - Majority of 4.18 libxfs changes merged from kernel xfsprogs-4.17.0 (28 Jun 2018) - No further changes xfsprogs-4.17.0-rc1 (22 Jun 2018) - mkfs.xfs: only stat block devices during mkfs init (Eric Sandeen) - xfs_repair: multiple fixes and improvements (Darrick Wong) - xfs_repair: check and repair quota metadata (Eric Sandeen) - xfs_repair: fix shortform root inode parent (Marco Benatto) - xfs_db: don't ASSERT on unrecognized metadata (Carlos Maiolino) - xfs_db: add superblock info command ala xfs_info (Darrick Wong) - xfs_spaceman: add superblock info command ala xfs_info (Darrick Wong) - xfs_info: call xfs_db for unmounted devices (Darrick Wong) - xfs_io: add online label command (Eric Sandeen) - xfs_io: add O_PATH and O_NOFOLLOW options (David Howells) - xfs_io: recognize *iB units in copy_range (Goldwyn Rodrigues) xfsprogs-4.16.1 (30 Apr 2018) - fsck.xfs: remove bashism which may interfere with boot (Eric Sandeen) xfsprogs-4.16.0 (25 Apr 2018) - No further changes xfsprogs-4.16.0-rc1 (12 Apr 2018) - platforms: warn of impending deprecation of irix, freebsd, darwin - mkfs.xfs : enable sparse inodes by default (Darrick Wong) - fsck.xfs: allow forced boot-time repairs using xfs_repair (Jan Tulak) - xfs_repair: new -e flag alters exit code for fixed errors (Jan Tulak) - xfs_repair: fix to allow zeroing of corrupt log (Xiao Yang) - xfs_repair: remove old dead code (Eric Sandeen) - xfs_io: fix operation time reporting (Dave Chinner) - xfs_io: add RWF_DSYNC support to pwrite (Dave Chinner) - xfs_io: support a basic extent swap command (Brian Foster) - xfs_scrub: Many updates, still experimental (Darrick Wong) - xfs_db: print transaction reservation type information - libxfs: framework to detect memory leaks (Eric Sandeen) - misc: Fix up new warnings from gcc 7.3 (Darrick Wong) - misc: enable link time optimization, if requested (Darrick Wong) - misc: enable retpolines across all xfsprogs utilities (Darrick Wong) xfsprogs-4.15.1 (26 Feb 2018) - debian: add build-depends on pkg-config (Darrick Wong) - debian: don't fail postinst when upgrading chroot (Darrick Wong) - update Polish translation (Jakub Bogusz) xfsprogs-4.15.0 (23 Feb 2018) - various debian-related packaging fixes (Nathan Scott) xfsprogs-4.15.0-rc1 (13 Feb 2018) - xfs_scrub: experimental new tool added (Darrick Wong) - xfs_metadump: fix issues with -i flag (Marco Benatto) - mkfs.xfs: don't allow creation of realtime+reflink (Darrick Wong) - mkfs.xfs: don't crash on dswidth overflow (Darrick Wong) - mkfs.xfs: much refactoring (Dave Chinner) - xfs_copy: fix copy of v5 filesystems (Eric Sandeen) - xfs_io: add a new 'log_writes' command (Ross Zwisler) - xfs_io: add MAP_SYNC support to mmap() (Ross Zwisler) - libxfs: memory zone handling cleanups (Eric Sandeen) xfsprogs-4.14.0 (27 Nov 2017) - no changes from v4.14.0-rc2 xfsprogs-4.14.0-rc2 (20 Nov 2017) - xfs_repair: fix deadlock on failed refcountbt checks (Darrick Wong) - xfs_repair: fix cowextsize field checking and repairing (Darrick Wong) - xfs_repair: clear DAX flag from non-file inodes (Darrick Wong) - xfs_repair: fix bag memory overwrite problems (Darrick Wong) - xfs_metadump: zap stale data in DIR2_LEAF1 dirs (Eric Sandeen) - xfs_metadump: allow large directory extents by default (Darrick Wong) - xfs_copy: don't hang if all targets hit write errors (Darrick Wong) - xfs_io: stat: treat statfs.f_flags as optional (Jeff Mahoney) - xfs_io: stat: fix typo in statfs->f_flags (Jeff Mahoney) - xfs_io: Allow partial writes in pwrite (Goldwyn Rodrigues) - xfs_io: Add support for pwritev2() (Goldwyn Rodrigues) - xfs_io: Add RWF_NOWAIT to pwritev2() (Goldwyn Rodrigues)) - xfs_io: Disable pwrite -V if pwritev unavailable (Goldwyn Rodrigues) - xfs_io: add new error injection knobs to inject command (Darrick Wong) - xfs_io: report io errors from pwrite -W and -w (Liu Bo) xfsprogs-4.13.1 (26 Sep 2017) - fix global array overrun in mkfs (Darrick Wong) xfsprogs-4.13.0 (26 Sep 2017) - no changes from v4.13.0-rc2 xfsprogs-4.13.0-rc2 (21 Sep 2017) - mkfs.xfs: pass custom cowextsize to created filesystem (Darrick Wong) - xfs_repair: handle missing extent states (Darrick Wong) - xfs_db: version command misses RMAPBT feature string (Zirong Lang) xfsprogs-4.13.0-rc1 (15 Sep 2017) - mkfs.xfs: document forgotten flags (Darrick Wong) - mkfs.xfs: don't stagger AG on single disk (Donald Douwsma) - xfs_repair: various threading fixes (Jeff Mahoney) - xfs_repair: validate symlink target length (Darrick Wong) - xfs_repair: fix error exit status with -v flag (Masatake YAMATO) - xfs_fsr: Fix uninitalized varable use aftger timeout (Jeff Mahoney) - xfs_io: fix fiemap -n documentation to match reality (Nikolay Borisov) - xfs_io: Allow lsattr & lsproj on foreign filesystems (Ross Zwisler) - xfs_io: Print filesystem statfs flags in statfs output (Carlos Maiolino) - xfs_io: add seek consistency checks (Andreas Gruenbacher) - xfs_db: Fix metadump redirection (Darrick Wong) - xfs_db: Add fuzz command (Darrick Wong) - xfsprogs: Fix multiple compiler warnings (Darrick Wong) xfsprogs-4.12.0 (20 Jul 2017) - mkfs.xfs: allow specification of 0 stripe width & unit (Eric Sandeen) - xfs_db: redirect printfs when metadumping to stdout (Darrick Wong) - libxfs: propagate transaction block reservations (Darrick Wong) - xfs_db: properly set inode type (Eric Sandeen) xfsprogs-4.12.0-rc2 (13 Jul 2017) - mkfs.xfs: minimum log size calculation fixes (Darrick Wong) xfsprogs-4.12.0-rc1 (30 Jun 2017) - xfs_spaceman: new space management tool (Dave Chinner, Darrick Wong) - xfs_io: implement fsmap command (Darrick Wong) - xfs_repair: fix 512 sector image repair on 4k sector host (Zorro Lang) - xfs_growfs: ensure target is an active xfs mountpoint (Bill O'Donnell) - xfs_metadump: warn about corruption if log is dirty (Jan Tulak) - xfs_metadump: tag metadump with informational flags (Eric Sandeen) - xfs_db: fix 'type' command for interesting geoms (Bill O'Donnell) - xfs_db: add alignment filter to freesp command (Eric Sandeen) - libxfs: use crc32c slice-by-8 variant by default (Darrick Wong) - update Polish translation (Jakub Bogusz) xfsprogs-4.11.0 (5 May 2017) - xfs_io: man page fixups (Zorro Lang) xfsprogs-4.11.0-rc2 (2 May 2017) - xfs_db: add btree dumping command (Darrick Wong) - mkfs.xfs: change bare -m rmapbt,reflink to enable (Eric Sandeen) - xfs_io: document -d option, enable for dqblks & inodes (Darrick Wong) - xfs_io: minor statx fixes, updates (Chandan Rajendra, Gwendal Grignou) xfsprogs-4.11.0-rc1 (4 Apr 2017) - xfs_io: add statx support (David Howells, Eric Sandeen) - xfs_io: fix "falloc -p" to pass KEEP_SIZE (Calvin Owens) - xfs_io: support shutdown on foreign filesystems (Darrick Wong) - xfs_repair: repair zero-sized symlinks (Brian Foster) - xfs_repair: warn about dirty log with -n option (Eric Sandeen) - xfs.5: document barrier mount option deprecation (Eric Sandeen) xfsprogs-4.10.0 (6 Feb 2017) - build: fix __bitwise definitions vs kernel headers (Darrick Wong) xfsprogs-4.10.0-rc1 (15 Feb 2017) - build: fix cross-compile (Gwendal Grignou) - remove old Irix support (Christoph Hellwig) - xfs_repair: various additional checks (Darrick Wong) - xfs_repair: document dirty log conditions (Darrick Wong) - xfs_repair: document exit codes (Zirong Lang) - xfs_io: fix building with musl (Ralph Sennhauser) - xfs_io: add set_encpolicy / get_encpolicy (Eric Biggers) - xfs_io: Fix command iteration (Dave Chinner) - xfs_io: fix missing syncfs command (Amir Goldstein) - xfs_db: fix 'source' command when passed as a -c option (Darrick Wong) - xfs_logprint: handle log operation split of inode item (Hou Tao) - xfs_metadump: ignore empty attribute leaf (Eric Sandeen) - libxfs: don't OOM on corrupt agcount (Darrick Wong) xfsprogs-4.9.0 (5 Jan 2017) - no changes from v4.9.0-rc1 xfsprogs-4.9.0-rc1 (22 Dec 2016) - add reflink and dedupe support (Darrick Wong) - Convert from off64_t to off_t (Felix Janda) - xfs_io: add command line option to start an idle thread (Amir Goldstein) - xfs_repair: junk leaf attribute if count == 0 (Eric Sandeen) - xfs_quota: handle wrapped id from GETNEXTQUOTA (Eric Sandeen) - xfs_repair: fix some potential null pointer deferences (Darrick Wong) - libxfs_apply: filtering fixes (Dave Chinner) xfsprogs-4.8.0 (17 Oct 2016) - no changes from v4.8.0-rc3 xfsprogs-4.8.0-rc3 (3 Oct 2016) - xfs_io: clean up inode command (Eric Sandeen) - xfs_repair: fix phase 5 btree size overestimation (Darrick Wong) - xfs_repair: fix phase 5 AGFL rmap update (Darrick Wong) - libxfs: libxfs_iget() cleanup (Eric Sandeen) - libxcmd: fix count of XFS filesystems in path table (Eryu Guan) xfsprogs-4.8.0-rc2 (23 Sep 2016) - xfs_copy: uuid handling fixes (Eric Sandeen) - xfs_repair: directory rebuild segfault fix (Eric Sandeen) - xfs_repair: report log dirtiness correctly (Eric Sandeen) - libxfs: mounted filesystem detection cleanups (Eric Sandeen) - xfs_logprint: don't print transaction types anymore (Hou Tao) - xfs_quota: allow operation on non-XFS filesystems (Bill O'Donnell) - xfs_io: allow project quota operations on non-XFS (Eric Sandeen) - mkfs.xfs: man page calrification for ftype defaults (Eric Sandeen) xfsprogs-4.8.0-rc1 (9 Sep 2016) - change contact emails to linux-xfs@vger.kernel.org - libxfs: kernel sync up to 4.8-rc1 - Initial reverse mapping support (Darrick Wong) - buffer lock trace analysis tool (Darrick Wong) - logprint: cleanups and fixes (Darrick Wong) - man page updates (various) - libxcmd: mount option parsing fixes (Darrick Wong) - xfs_quota: use XFS_GETQSTATV (Eric Sandeen) - xfs_quota: allow use on non-XFS filesystems (Bill O'Donnell) - xfs_db: allow direct manipulation of CRCs (Eric Sandeen) - libxfs: get rid of ustat() calls (Felix Janda) xfsprogs-4.7.0 (5 Aug 2016) - xfs_io: man page for copy_file_range (Anna Schumaker) - xfs_quota: handle XFS_GETNEXTQUOTA failure sanely (Zorro Lang) - mkfs: remove old glibc build failure workaround (Felix Janda) xfsprogs-4.7.0-rc2 (20 Jul 2016) - xfs_io: add support for copy_file_range (Anna Schumaker) - repair: fix exit value after low memory is detected (Zorro Lang) - repair: fix quota inode detection issue (Eric Sandeen) - fix coverity issues from 4.7-rc1 (Bill O'Donnell) xfsprogs-4.7.0-rc1 (22 Jun 2016) - libxfs kernel sync up to 4.7-rc1 - quota: new efficient iteration mechanism (Eric Sandeen) - quota: support usernames starting with digits (Zorro Lang) - xfs_io: mmap/mremap fixes (Zorro Lang) - build/translation fixes (Mike Frysinger) - repair: error messge cleanups (Eric Sandeen) - mkfs: table based option parsing (Jan Tulak, Eric Sandeen) - metadump: sector size support fixes (Eric Sandeen) - db: unaligned acces fixes (Eric Sandeen) - db: add CRC recalculation for corrupt blocks - db: fix array notation handling in print commands - db: Note that fragmenation factor is meaningless (Eric Sandeen) - repair: more efficient secondary superblock search (Bill O'Donnell) - quota: timer reporting corner case fixes (Eric Sandeen) - headers: struct fsxattr redifinition fixes (Christoph Hellwig) - man page updates (Eric Sandeen, Jan Tulak, Zorro Lang) - repair: RT summary inode rebuild fix (Eric Sandeen) - db: sparse inode check fixes (Brian Foster) xfsprogs-4.5.0 (15 Mar 2016) - xfs_io: prevent divide-by-zero on random IO (Dmitry Monakhov) - xfs_db: dquot command documentation fixes (Eric Sandeen) - xfs_quota: better command line parsing and documentation (Zorro Lang) xfsprogs-4.5.0-rc1 (17 Feb 2016) - libxfs: update to match kernel 4.5-rc1 code base - xfs_io: add DAX inode flag support - repair: scalability improvements on large corrupt filesystems - repair: directory rebuild fixes - mdrestore: progress accounting now works - metadump: fix btree block unused region zeroing - quota: timer command fixes (Eric Sandeen) - mkfs: man page cleanups (Eric Sandeen) - xfs_io: reflink, dedupe and other fixes (Darrick Wong) - quota: Q_XGETNEXTQUOTA support (Eric Sandeen) - build cleanups for alternate C librarys (Joshua Kinard, Felix Janda) - db: check fixes for sparse inodes (Darrick Wong) - various: Fixes for Coverity reports (Vivek Trivedi) - xfs_io: Document zero and help commands (Eric Sandeen) - mkfs: DIO can use logical sector size limits (Eric Sandeen) - repair: don't reset log cycle numbers when zeroing (Brian Foster) - db: add ability to format log to a specific cycle (Brian Foster) xfsprogs-4.3.0 (23 Nov 2015) - xfs_fsr: cleanups to recent changes (Eric Sandeen) - xfs_fsr: improved temp file attr fork handling (Eric Sandeen) - libxfs: output verifier names in warnings (Eric Sandeen) - xfs_repair: enable verifier corruption warnings on very verbose output settings (Eric Sandeen) - debian: update initramfs in postinst script (Steve McIntyre) xfsprogs-4.3.0-rc2 (10 Nov 2015) - xfs_fsr: abstract mntinfo/mntent differences (Jan Tulak) - xfs_io: update reflink/dedupe ioctl definitions and implementation (Darrick Wong) - libxcmd: factoring of runtime reporting (Darrick Wong) - man page fixes (Ville Skyttä) - removal of ASSERT from exported headers xfsprogs-4.3.0-rc1 (14 Oct 2015) - xfs_io: reflink and dedupe operation support (Darrick Wong) - xfs_db: blockget/blocktrash support for v5 filesystems (Darrick Wong) - xfs_repair: many directory/attr cleanups and fixes (Eric Sandeen) - More OS X build improvements (Jan Tulak) - Log zeroing rework for v5 filesystems to prevent log sequence numbers from going backwards (Brain Foster) xfsprogs-4.2.0 (7 Sep 2015) - repair: fix crashes due to missing geometry pointer (Eric Sandeen) - repair: fix node handling on large attribute btrees (Brian Foster) - repair: attribute block header verification fixes (Darrick Wong) - libxfs: more error negation fixes (Darrick Wong) - libxfs: cancelled readahead buffer state initialisation fixes (Darrick Wong) - build: include/xfs header path fix (Lucas Stach) xfsprogs-4.2.0-rc3 (25 Aug 2015) - xfs_repair: directory verification fixes (Darrick Wong) - libxfs: errno negation fixes (Darrick Wong) - xfs_db: corrupt inode handling fixes (Darrick Wong) - repair: memory leak fixes (Eric Sandeen) - libxfs: directory corruption fix (Jan Kara) - libxfs: gcc miscompile fixes (Jan Kara) - libxfs: merge across bug fixes from 4.2 kernel code - man pages: minor updates (Eric Sandeen) xfsprogs-4.2.0-rc2 (18 Aug 2015) - OS X build improvements (Jan Tulak) - libxfs: fix code miscompilation w/ gcc 4.8.3 (Jan Kara) - mkfs.xfs: default to using ftype=1 for all filesystems - mkfs.xfs: CLI options parsing order fix (Eric Sandeen) - xfs_repair: improve inode version checks (Roger Willcocks) - libxfs: remove excessive EXPERIMENTAL feature warnings for sparse inodes (Brian Foster) - xfs_db: fix new gcc 4.9.3 build warnings xfsprogs-4.2.0-rc1 (4 Aug 2015) - update libxfs to match kernel 4.2-rc1 - libxfs and include restructuring to match kernel code - sparse inode support (Brian Foster) - Android build support (Ted Tso) - Mac OS X build fixes (Jan Tulak) - changing UUIDs on v5 filesystems (Eric Sandeen) - libxfs-apply script for keeping kernel/progs libxfs in sync (Eric Sandeen) - lots of header and type cleanups (Christoph Hellwig) - libblkid now mandatory (Jan Tulak) - lots of bug fixes (Brian Foster, Eric Sandeen, Christoph Hellwig, Mike Grant) xfsprogs-3.2.4 (30 Jul 2015) - xfs_metadump: information leakage fixes (CVE-2012-2150) (Eric Sandeen) xfsprogs-3.2.3 (10 Jun 2015) - Debian packaging updates (Nathan Scott) xfsprogs-3.2.3-rc2 (1 Jun 2015) - xfs_repair: handle speciall atribute names correctly (Eric Sandeen) - xfs_repair: handle v5 format feature flags correctly (Darrick Wong) - xfs_repair: Better v5 format validation for directories (Darrick Wong) xfsprogs-3.2.3-rc1 (11 May 2015) - mkfs.xfs: enable metadata CRCs by default - mkfs.xfs: enable free inode btrees by default - build: glibc support updates (Jan Tulak) - man page updates (Sage Weil, Namjae Jeon, Eric Sandeen) - xfs_admin: Changing UUIDs disable for CRC enabled filesystems (Eric Sandeen) - xfs_repair: Separate pquota inode fixes (Brian Foster) - xfs_db: inode alignment fixes (Brian Foster) - mkfs.xfs: fix failures creating file images (Brian Foster) - libxfs: zero new buffers before use (Darrick J. Wong) - xfs_repair: handle directory leaf CRC errors gracefully (Darrick J. Wong) - xfs_repair: validate and repair inode CRCs (Eric Sandeen) - xfs_repair: lots of broken directory repair fixes (Eric Sandeen) - xfs_db: handle v3 inodes properly (Eric Sandeen) - xfs_db: allow writing corrupted metadata on CRC enabled filesystems (Eric Sandeen) - xfs_repair: gracefully handle > 512 byte sector superblocks - mkfs.xfs: take into acocunt log stripe unit when sizing log - xfs_metadump: inode alignment and null inode fixes (Brian Foster) - xfs_io: FALLOC_FL_INSERT_RANGE support (Namjae Jeon) - build: libtool static library build fixes (Romain Naour) - mkfs.xfs: large block size inode alignment fixes (Brian Foster) - xfs_repair: secondary superblock scan fixes (Brian Foster) - xfs_repair: don't care about symlink compenent lengths (Eric Sandeen) xfsprogs-3.2.2 (4 December 2014) - Debian packaging updates (Nathan Scott) - xfs_repair, mkfs.xfs stripe geometry fixes (Eric Sandeen) - libxcmd path handling fixes (Eric Sandeen) - xfs_crash crash fix (Jie Liu) - xfs_logprint AGI/AGF handling improvements (Jan Kara) - libhandle support for symlinked /usr (Jan Tulak) - fix multiple Coverity and sparse reported issues (Eric Sandeen) - new mremap, sync, syncfs commands for xfs_io (Eric Sandeen) - man page updates (Eric Sandeen, Mark Tinguely) - xfs_repair sets ftype in lost+found dirents (Jan Kara) - xfs_repair handles bad inodes better (Eric Sandeen) - xfs_repair freelist rebuild improvements - xfs_repair finobt crash fixes (Brian Foster) - xfs_copy handles 4k sector devices better (Eric Sandeen) xfsprogs-3.2.1 (15 July 2014) - Added support for new on-disk free inode btree (Brian Foster) - libxfs inode use-after free fixes (Mark Tinguely) - xfs_copy threading cleanups (Junxiao Bi) - xfs_check has been removed - C++ header compiler fixes (Roger Willcocks) - xfs_repair prefetch fixes (Eric Sandeen) - xfs_repair directory block CRC detection fixes (Jan Kara) - xfs_repair directory rebuild fixes - libxfs buffer error handling fixes - xfs_repair quota inode handling fixes - removed incorrect asserts from phase 2 of xfs_repair - updated Polish translations (Jakub Bogusz) - xfs_mkfs 4k sector device fixes (Eric Sandeen) - xfs_fsr cleanups nd fixes (Eric Sandeen) - mount options described in xfs(5) man page (Eric Sandeen) xfsprogs-3.2.0 (16 May 2014) - First release with full support of CRC enabled filesystems - No code changes from 3.2.0-rc3 xfsprogs-3.2.0-rc3 (9 May 2014) - Third release candidate for full support of CRC enabled filesystems - Updated Debian change logs in preparation for release (Nathan Scott) - Build warning fixes (Nathan Scott) - xfs_repair prefetch fix (Eric Sandeen) - xfs_repair block tracking scalability fix xfsprogs-3.2.0-rc2 (2 May 2014) - Second release candidate for full support of CRC enabled filesystems - xfs_repair has full CRC validation and repair - Coverity related cleanups and fixes xfsprogs-3.2.0-rc1 (14 April 2014) - First release candidate for full support of CRC enabled filesystems - Large number of Coverity related fixes and cleanups - disambiguous of CRC validation errors from IO errors. - Improved dangerous mode handling in repair - repair handles garbage in zeroed areas of superblocks better - repair validates dirent ftype field fully - metadump fully supports discontiguous directory blocks - metadump only recalculates CRCs on metadata it obfuscates so as to preserve errors in the metadata where possible. - default log size that mkfs creates is now reverted to the same size as 3.1.x releases create. - mkfs sets the ftype on directory entries correctly during protofile population - xfs_io support O_TMPFILE, flink, FALLOC_FL_ZERO_RANGE and FALLOC_FL_COLLAPSE_RANGE, - logprint handles split entries better xfsprogs-3.2.0-alpha2 (25 November 2013) - Alpha release for the purpose of testing the CRC feature in kernels 3.10 and newer. - Enable xfs_db write support and xfs_metadump support for CRC enabled filesystems. - Add directory entry filetype support for non-CRC filesystems. - Remove experimental warnings for CRC filesystems. - Ensure all inodes created by xfs_repair have a proper d_type set. - Fix build on big endian machines. - Properly handle symlinks to devices on various tool commandlines. - Fix xfs_repair's dirty log detection for 4k sector logs, broken in Alpha1. - Fix a potential segfault in xfs_repair when issuing progress reports. - Fix potential xfs_fsr failures when running w/ selinux. - Update config.guess/config.sub for arm64, thanks to Colin Watson. - Stop wasting memory by caching inode structures in xfs_repair - they are never re-used. Thanks to Christoph Hellwig. - Fix several Coverity-found defects, thanks to Li Zhong. - Fix platform_test_xfs_fd to return false on special files which cannot take an xfs ioctl. - Sync up libxfs with kernel code. - Improved xfs_repair performance on large filesystems (always use prefetch and strided AG scanning functionality) xfsprogs-3.2.0-alpha1 (26 September 2013) - Alpha release for the purpose of testing the CRC feature in kernels 3.10 and newer. - Remove all vestiges of old, unsupported version 1 directory code. - Add a "readdir" command to xfs_io, thanks to Brian Foster. - Fix potential segfault in xfs_repair when creating lost+found. - Zero out unused parts of on-disk superblocks during repair, to avoid metadata verifier failures at runtime. - Add directory entry type support to mkfs.xfs and xfs_db. - Add the icreate transaction to xfs_logprint, and fix continuation transactions. - Add the lseek SEEK_DATA/SEEK_HOLE support into xfs_io. - Print all AGI unlinked buckets in xfs_logprint. - Fix mkfs.xfs ENOSPC with protofile which creates a very large directory. - Fix several Coverity-found defects, thanks to Li Zhong. - Do all file reads in xfs_fsr using O_DIRECT. - Sync up libxfs with kernel code. - Add support for concurrent group and project quota usage on CRC enabled filesystems. - Ensure mkfs creates log sizes that are always large enough for the configured fileystem geometry. xfsprogs-3.1.11 (8 May 2013) - Support for relative paths in xfs_quota thanks to Satoru Takeuchi. - mkfs.xfs will always go into multidisk mode when filesystem geometry is specified on the command line. - Document all commands in xfs_io. - Remove setfl command from xfs_io. - xfs_metadump will obfuscate symlinks by path component. - mkfs.xfs no longer accepts geometry settings smaller than the physical sector size. - xfs_logprint now supports multiply-logged inode fields and handles continued inode transactions correctly. - kill XLOG_SET - Update release scripts to use git archive to address a missing source file reported by Arkadiusz Mi?kiewicz - Fix a build error with -Werror=format-security, reported by Arkadiusz Mi?kiewicz - mkfs.xfs no longer attempts to discard when -N option is used. - Update 'make deb' to use tarball - Sync up with log reservation changes in the kernel. - Fix possible unallocated memory access in fiemap. - Guard against string overflow in path_to_fspath. - Fix setup_cursor array allocation. - Fix free of unintialized pointer in xfs_acl_valid error path. - Guard against path string overflows. - Check strdup results properly in initallfs(). - Fix attribute no_change_count logic. - Remove extraneous close() in fsrallfs(). - xfs_repair now skips the freelist scan of a corrupt agf when in no-modify mode. - xfs_db now skips freelist scans of corrupt agfs. - Remove unconditional ASSERT(0) in xfs_repair. - Reduce bb_numrecs in bno/cnt btrees when log consumes all agf space. - Add depraction message for xfs_check. - xfs_quota allow user or group names beginning with digits reported by James Carter. - Fix manpages and usage() spelling, errors and omissions. - Validate the extent count is at least within the positive range of a signed 32 bit integer before using it. xfsprogs-3.1.10 (13 December 2012) - Update release script to make a source tarball. xfsprogs-3.1.9 (31 October 2012) - Print nice details if agsize is out of bounds in mkfs.xfs. - Various fixes for fragmented multi-block dir2 handling in xfs_repair. - Fix extent record printing in xfs_db on big endian arches. - Use the correct macros when dumping block maps in extent form in xfs_db, thanks to Peter Watkins. - Add sync file range support to xfs_io. - Implement preadv/pwritev in xfs_io. - Link against libreadline for libxcmd, thanks to Mike Frysinger. - Clean up mkfs.xfs output on invalid inode size. - Various build fixes, thanks to Mike Frysinger and Jan Engelhardt. xfsprogs-3.1.8 (20 March 2012) - Fix xfs_repair segfault on a corrupted filesystem by validating the acl count before reading it. - Avoid xfs_repair deadlocks on prefetched buffers. - Fix various incorrect printf formats, thanks to Jakub Bogusz for reporting. - Polish translation update, thanks to Jakub Bogusz. - Refuse mkfs.xfs on misaligned devices when using 4k sectors, unless the -f option is specified, and then force 512b sector size, thanks to Carlos Maiolino. - Avoid a possible loop on the unlinked inode list in phase 3 of xfs_repair, thanks to Stefan Pfetzing for reporting. - Allocate inode and free extent records individually in xfs_repair. - Fix a possible deadlock btree nodes in xfs_repair by using recursive locking, thanks to Arkadiusz MiÅ›kiewicz for reporting and testing. - Fix possible xfs_repair deadlocks in inode prefetching, thanks to Arkadiusz MiÅ›kiewicz for reporting and testing. - Make xfs_repair handle filesystems with the log in ag 0, thanks to Sindre Skogen for reporting. - Deprecate the -F foreign flag to xfs_io. - Add debian linux-libc-dev build dependancy. - Add an extended fiemap configure check. - Various cleanups in xfs_repair. - Update xfs_check man page to recommend xfs_repair over xfs_check, thanks to Arkadiusz MiÅ›kiewicz. - Update the on-disk extent count as part of inode repair when moving inodes to lost+found to avoid to avoid tripping over a check in xfs_iformat, thanks to Arkadiusz MiÅ›kiewicz for reporting and testing. - Check for size parsing errors in xfs_quota, thanks to James Lawrie for reporting. - Fix fiemap loop continuation in xfs_io. - Make mkfs.xfs properly handle physical sector size. - Fix /proc/mounts parsing in xfs_fsr. - Fix xfs_repair when ag_stride options with attributes and dirv1 code, thanks to Tom Crane for reporting and testing. - Fix message formats in process_dinode_int. - Fix xfs_repair handling of link counts when the on-disk count overflows 8 bits. - Fix messages from set_nlinks in xfs_repair. xfsprogs-3.1.7 (17 November 2011) - Pull in fix for debian/control - Polish translation update, thanks to Jakub Bogusz - Fix xfs_repair link count on lost+found, thanks to Carlos Maiolino - Fix various incorrect printf formats xfsprogs-3.1.6 (14 October 2011) - Re-synch of the header and libxfs files with the kernel code as of Linux 2.6.37, including reviving xfs_repair radix tree code. - Fix a xfs_repair phase 4 hang, thanks to Ajeet Yadav. - Subcommand names within various programs are no longer translated/localized, thanks to Arkadiusz Mi?kiewicz. - Build system fixes, thanks to Ted Ts'o. - Updates to teh xfs_info(8)/xfs_growfs(8) man page, thanks to Roman Ovchinnikov. - xfs_quota "df" no longer reports values twice what they should have been for project quotas. - mkfs.xfs now requires that sub-options are non-empty strings; thanks to Chris Pearson for reporting. - Better handling of short reads in libxfs. - xfs_quota now prints "N/A" rather than a large number for the quota file inode number for disabled quota types. - Bogus (unrelated) mount point entries no longer cause xfs_growfs, xfs_quota, and xfs_io to quit early. - xfs_repair no longer fails when the sector size of an underlying device is larger than the sector size in a hosted filesystem image. - Various other internal improvements, including refactoring and eliminating more build warnings. xfsprogs-3.1.5 (30 March 2011) - Polish translation update, thanks to Jakub Bogusz - xfs_repair now warns if running in low memory mode - Phase 2 of xfs_repair is now multithreaded - xfs_quota no longer attempts to get quota information if not enabled - Inode flags are now properly validated by xfs_repair - Metadump now obfuscates all file names reliably - xfs_io now supports the "fiemap" command, a more generic form of the "bmap" command - xfs_io now supports the "fpunch" command, as well as a "-p" flag to the "fallocate command. Both implement hole punching. Thanks to Josef Bacik - A number of other bug fixes thanks to Ajeet Yadav xfsprogs-3.1.4 (9 November 2010) - Add projid32bit handling to userspace, resolving type sizing issues when dealing with 32 bit project ids. - Make xfs_fsr use /proc/mounts if available. - Annotate that Debian packages are group maintained. - Fix a Debian packaging issue causing upgrade pain. xfsprogs-3.1.3 (26 August 2010) - Add xfs_io support for XFS_IOC_ZERO_RANGE - Fix depend targets. - Allow xfs_io resvsp command for foreign filesystems. - Fix configure --prefix. - Make xfs_db check for valid inode data pointer before dereferencing. - Validate btree block magic in the xfs_db freesp command, thanks to Peter Watkins. - Unbreak make update-po, permissions problem, thanks to Arkadiusz MiÅ›kiewicz. - Fix linking of libxfs and librt detection (needs pthread), thanks to Arkadiusz MiÅ›kiewicz. - Add a platform_discard_blocks stub for GNU/kFreebsd. xfsprogs-3.1.2 (6 May 2010) - Fix missing thread synchronization in xfs_repair duplicate extent tracking. - Fix handling of dynamic attribute fork roots in xfs_fsr. - Fix sb_bad_features2 manipulations when tweaking the lazy count flag. - Add support for building on Debian GNU/kFreeBSD, thanks to Petr Salinger. - Improvements to the mkfs.xfs manpage, thanks to Wengang Wang. - Various small blkid integration fixes in mkfs.xfs. - Fix build against stricter system headers. xfsprogs-3.1.1 (29 January 2010) - Fix various blkid topology support problems in mkfs.xfs. - Fix various build warnings. - Add automatic build dependency calculations. - Cleaner build system output. - Add missing aclocal m4 file to the package generation. - Arrange for release tags to be digitally signed. xfsprogs-3.1.0 (13 January 2010) - Reduce memory usage in xfs_repair by using better data structures. - Add additional checks in xfs_repair to detect freespace btree corruption instead of only rebuilding the btrees. Useful for the no-modify mode. - Fix libhandle to use the right path to issue by-handle ioctls for symbolic links and special files. - Use lazy superblock counters by default. At least kernel 2.6.22 is needed for this feature. - Use physical device sector size if available in mkfs.xfs, so 4K sector devices are handed more gracefully. - Add a German translation, thanks to Chris Leick. - Enable the madvise and mincor commands in xfs_io. - Fix unsafe temporary file creation in xfs_fsr. - Add support for discarding unused space on SSDs or thin provisioned arrays in mkfs.xfs. - Allow linking against libblkid for topology information. - Add symbol versioning for libhandle. - Remove the included RPM and binary tarball built infrastructure. - Various build system improvements. - Small fixes to xfs_db and xfs_io. xfsprogs-3.0.4 (17 September 2009) - Fix a memory leak in xfsprogs. - Increase hash chain length in xfsprogs when running out of memory. - Fix dmsetup invocation in libdisk to avoid warnings during mkfs on multipath devices. - Fix the -V option to various installed tools. - Small internal fixes to please the clang semantical analysis tool. - Debian packaging updates. - Rework Makepkgs and Makefiles to improve deb generation. xfsprogs-3.0.3 (30 August 2009) - Fix unaligned accesses in libxfs. - Various small fixes to xfs_db, xfs_repair and xfs_io. - Add fallocate command to xfs_io. - Enable readline support in xfs_io and xfs_quota. - Allow log sizes up to 2GiB (minus 1 byte) in xfs_mkfs. - Open the block device in xfs_repair exclusively, thanks to Nathaniel W. Turner. xfsprogs-3.0.2 (6 May 2009) - Updates to Debian build process after recent autoconf tweaks. - Fix a couple of minor man page syntax issues. xfsprogs-3.0.1 (4 May 2009) - Update the Makepkgs script to generate proper source tarballs. - New project(5) and projid(5) man pages. - Fix extent array reallocation in the xfs_io bmap command, thanks to Tomasz Majkowski. - Small specfile improvements, thanks to Jan Engelhardt. - Allow xfs_freeze to freeze non-XFS filesystems. - Fix the xfs_db bmbta command. - Fix parallel builds, thanks to Mike Frysinger. - Various autoconf/libtool fixes, thanks to Andreas Gruenbacher. xfsprogs-3.0.0 (4 February 2009) - Various smaller xfs_repair improvements. - Various gettext improvements, thanks to Jakub Bogusz. - Polish translation update, thanks to Jakub Bogusz. - Various xfs_quota fixes, thanks to Arkadiusz Miskiewicz. - Support parallel builds. - Detection of btrfs, gfs and gfs2 in libdisk. - Addition of the xfs_fsr and xfs_estimate tools previous found in the xfsdump package. - Resync libxfs to latest kernel implemenation. - Update all of xfsprogs to latest kernel interfaces. - Add sparse support to xfsprogs build. - Cleanup devel package for xfsctl, libhandle and libdisk only (remove libxfs interfaces). xfsprogs-2.10.1 (5 September 2008) - Improve xfs_repair -P option to disable xfs_buf_t locking. - Fix inode cluster I/O size for > 8KB block size filesystems. - Fix up ASCII CI output for mkfs.xfs and xfs_growfs. - Fix buffer handling in error cases in xfs_db (includes xfs_check and xfs_metadump). - Add packed on-disk shortform directory for ARM's old ABI, thanks to Eric Sandeen. - Increase default valid block count for a directory extent in xfs_metadump (from 20 to 1000). - Fix up mkfs.xfs -N option with "-d file" so it doesn't resize the target file (thanks to Michal Marek). - Improve libxfs cache handling with (un)referenced blocks. - Check that directory size is not too big in xfs_repair. - Improve xfs_repair to restore bad or missing ".." entries. xfsprogs-2.10.0 (26 May 2008) - Add ASCII case-insensitive support to xfsprogs. xfsprogs-2.9.8 (21 April 2008) - Add support for sb_features2 in wrong location in mkfs.xfs, xfs_repair and xfs_db. - Improve memory limits for libxfs cache in xfs_repair and added a -m option to manually limit usage of xfs_repair. - Add -c option to xfs_admin to turn lazy-counters on/off. - Added support for mdp in libdisk/mkfs.xfs, thanks to Hubert Verstraete. - Add -p option to fsck.xfs, thanks to Markus Rothe. - Cleanup sys v3 bzero/bcopy calls, thanks to Nigel Kukard. xfsprogs-2.9.7 (1 Mar 2008) - Lazy superblock counters not yet the default with mkfs.xfs. - Add -y (another no-op) fsck option. - Resolve mkfs allocation group count issue with small devices. - Fix mkfs to sector align the device size so zeroing the end of the device doesn't fail. xfsprogs-2.9.6 (7 Feb 2008) - Fix regression introduced by changing the mkfs.xfs defaults. - Made lazy superblock counters the default with mkfs.xfs. xfsprogs-2.9.5 (21 Jan 2008) - Updated mkfs.xfs defaults. - Make xfs_info handle mount points with spaces. - Improve xfs_repair's handling of invalid freespace btree extents. - Rebuild directories in xfs_repair if "." and ".." aren't the first two directory entries. This guarantees a directory is deletable. - Changed mkfs.xfs -f to wipe all old AG headers, not just the ones up to the end of the new filesystem size. - Purged the end of device whack buffer in mkfs.xfs to prevent a warning in certain device sizes. - Man page fixes. Thanks to Utako Kusaka for this. - Disable the ability to turn off unwritten extents in mkfs. xfsprogs-2.9.4 (7 Sep 2007) - Fixed xfs_repair segfaulting with directory block size different to the filesystem blocksize. - Fixed xfs_quota disable, enable, off and remove commands. Thanks to Utako Kusaka for this. - Improved the robustness of xfs_metadump. - Fix link issues with pthread library. xfsprogs-2.9.3 (23 July 2007) - Make xfs_repair support > 512 byte sector sizes. - Fixed include Makefile for new common header (xfs_metadump.h). - Fixed xfs_quota state command segfaulting with no mounted XFS filesystems. - Fixed xfs_quota printing out unusual message with "path n" command with no mounted XFS filesystems. - Fixed "quota -n" command with project IDs. - Improved "free" output when project quotas are defined, but haven't been enable on the filesystem. Thanks to Utako Kusaka for the above four fixes. xfsprogs-2.9.2 (18 July 2007) - Next major round of xfs_repair performance improvements: - Cache disk nlink values in Phase 3 for Phase 7. - Do multithreaded prefetch/processing based on AG stride option (ie. for concats). - Don't trash lost+found at the start of Phase 4, eliminates repeated "moving disconnected inode to lost+found" with successive xfs_repair runs. - Do multi-threaded sequential metadata prefetch. Method based on Agami patches posted for 2.7.18 xfsprogs. - Improve the libxfs cache with priority tagging to keep blocks around that have unfavourable I/O characteristics. - Make mkfs.xfs -f zero the old secondary superblocks before writing the new superblocks. - Fix up xfs_info and xfs_quota's -c handling with global commands. - Improve xfs_bmap -vp output to always show the FLAGS column. - Update man pages. xfsprogs-2.9.1 (28 June 2007) - Added filestreams support to xfs_io. - Fix up libattr Makefile to append to LTLDFLAGS. Thanks to Arfrever Frehtes Taifersar Arahesis for this. - Fix up build not to ignore LDFLAGS generated by configure. Thanks to SpanKY for this. xfsprogs-2.9.0 (5 June 2007) - Added new tools: xfs_metadump and xfs_mdrestore. - Fix up the HAVE___U32 fix from 2.8.20 Thanks to Eric Sandeen for pointing this out. xfsprogs-2.8.21 (28 May 2007) - Add support for lazy superblock counters in mkfs.xfs, xfs_db, xfs_repair, xfs_growfs and also libxfs. - Fix xfs_quota project command to stop it operating on special files. Thanks to Leo Baltus. xfsprogs-2.8.20 (23 February 2007) - Fix xfs_repair not detecting invalid btree root in inodes. - Fix xfs_repair restoring corrupted superblock after repairing it. - Fix xfs_repair crashing on invalid quota inode values. - Fix xfs_quota gracetime reporting. Thanks to Utako Kusaka for this. - Fix libxfs IO_DEBUG output. - Instead of using AC_CHECK_TYPES which isn't supported for older versions of autoconf, add our own type check in the m4/package_types.m4 file for __u32. Suggested by Nathan Scott and discovered by wookey@aleph1.co.uk. xfsprogs-2.8.19 (31 January 2007) - Fix pthread stack size setting in xfs_repair. - Fix xfs_bmap -n option displaying a truncated extent. - Fix xfs_io mwrite segfault. Thanks to Utako Kusaka for these two fixes. - Fix errors in xfs_quota(8) man page. xfsprogs-2.8.18 (8 December 2006) - is an installed file, we cannot simply rename it, as other applications using it (accidentally or not) may break. The xfs_list.h name was inconsistent with everything else too. - Fix "pointer targets in assignment differ in signedness" warnings - Update Debian packaging. - Fix up two issues with xfs_db and bmap. If the data/attr fork is local, it either infinite loops or crashes. If both are displayed, the attrs are wrong. - Fix up xfs_io mmap read that read from the wrong offset. - Updated xfs_io man page. Thanks to Utako Kusaka for the above three fixes. xfsprogs-2.8.17 (5 December 2006) - Fix up libxfs SEGV when attempting to mount a non-XFS filesystem. Thanks to Utako Kusaka for this. - Fix up xfs_repair aborting if it finds an inode with an invalid inode type. - Fix up default realtime extent size for large block sizes. - Rename include/list.h to xfs_list.h so that other applications do not accidentally use it. xfsprogs-2.8.16 (30 October 2006) - Fix up an endian problem for nlink setting in phase 7 for xfs_repair. xfsprogs-2.8.15 (19 October 2006) - Fix up nlink checks and repairs in phase 7 for xfs_repair. - Remove a bogus LEAFN warning for a single leaf node v2 dir. Thanks to Roger Willcocks for this. xfsprogs-2.8.14 (6 October 2006) - Fix up the ring command in xfs_db, Thanks to Utako Kusaka for this. - Set the blocksize on the device to the given sector size which is _not_ necessarily 512 bytes; idea suggested by Shailendra Tripathi. - Fix up xfs_copy and its variable argument handling around vfprintf; xfs_copy was seg faulting on x86_64. xfsprogs-2.8.13 (21 September 2006) - Fix v2 directory checking with holes and unreadable blocks. - Fix a memory leak in dir2 checking. - Update libdisk/md support to work out the stripe width based on (# raid-disks - # parity disks) which doesn't include any spare disks (which we mistakenly did before). Thanks to Shailendra Tripathi's suggestions. - Get the kernel int types of __u32 and friends from if we can, otherwise define them ourselves. xfsprogs-2.8.12 (29 August 2006) - Multi-thread modifications to xfs_repair. - Updated Polish translation, thanks to Jakub Bogusz. - Change default mkfs realtime extent size setting to perform better for buffered writes. xfsprogs-2.8.11 (08 August 2006) - xfs_repair prefetch optimisations. - Make many tools use direct I/O on Linux if the underlying device supports it. Mainly for speeding up xfs_repair as libxfs does its own internal metadata buffering now. - Fix warnings from mkfs.xfs on ramdisk devices. - Fix issues with symbolic link handling in Makefiles. xfsprogs-2.8.10 (02 August 2006) - Fix v2 directory rebuilds in phase6 of xfs_repair. - Fix buffer sizing issue for large pagesize systems, affecting mkfs auto-device-type-detection heuristics. xfsprogs-2.8.9 (18 July 2006) - Fix rpm issue with install targets as uid/gid zero (we now using symbolic names rather than the numeric versions). xfsprogs-2.8.8 (14 July 2006) - Fix issues with makedepend on libtool libraries. xfsprogs-2.8.7 (10 July 2006) - Fix build of xfs_logprint for different uuid_t definitions; thanks to Craig Rodrigues. xfsprogs-2.8.6 (07 July 2006) - Fixed xfs_repair handling of duplicate names in a directory. xfsprogs-2.8.5 (05 July 2006) - Update translation Makefile to work better with the Ubuntu translation system. Thanks to feedback from Martin Pitt. - Fix annoying "ignores datarootdir" warning from configure. - Fix issues with makedepend build infrastructure. - Add prefetch code for improved xfs_repair run times. xfsprogs-2.8.4 (23 June 2006) - Improve Debian udeb package handling, thanks to Frans Pop. - Fix a situation where xfs_growfs can fail to match a block device to a filesystem correctly; thanks to Bastian Kleineidam. - Minor corrections to the xfs_growfs man page. xfsprogs-2.8.3 (21 June 2006) - Fix a possible segv in xfs_growfs; thanks to Bastian Kleineidam. xfsprogs-2.8.2 (17 June 2006) - More updates to repair/libxfs for improving performance - Incorporate librt into the build process for lio_listio - Minor xfs_logprint tweaks and fixes. - Small updates to xfs_io manual page. - Several fixes from earler 2.8 releases with respect to inode/buffer cache refcounting. xfsprogs-2.8.1 (29 May 2006) - Fix endianness issues on FreeBSD. xfsprogs-2.8.0 (18 May 2006) - Initial pass at user space caching, ultimately provides a starting point for a faster, parallel version of repair. - Fix several inode/buffer reference counting issues. - Fix compiler warnings, and builds on certain glibc versions having issues with the device major() macro. - Added code to xfs_db and xfs_admin to allow conversion from version 1 to version 2 logs. xfsprogs-2.7.18 (16 May 2006) - Fixed a case where xfs_repair was reporting a valid used block as a duplicate during phase 4. - Fixed a case where xfs_repair could incorrectly flag extent b+tree nodes as corrupt. - Portability changes, get xfs_repair compiling on IRIX. - Parent pointer updates in xfs_io checker command. - Allow LDFLAGS to be overridden, for Gentoo punters. xfsprogs-2.7.17 (05 April 2006) - Fix libxfs access(2) check on /proc/mounts, which was causing issues when xfs_check/xfs_repair run on readonly root filesystem mounts. - Fix Debian packaging for libc-dev build dependency. - Fix up auto lib64 install detection for x86_64 platforms. xfsprogs-2.7.16 (22 March 2006) - Fix freespace accounting in xfs_quota(8) df command. - Fix a typo on the xfs_quota(8) man page. - Make -O2 (cc optimisation level) the default. xfsprogs-2.7.15 (03 March 2006) - Fix the way external log/realtime devices were handled in userspace with older kernels (subtely different in procfs) - Fix a corruption problem in xfs_copy(8) when attempting to zero the (old) log, a section was sometimes missed (depends on log and I/O buffer (mis)alignment). xfsprogs-2.7.14 (15 February 2006) - Debian packaging updates (debmake out, debhelper in). - Fix a header to work with additional compiler variants. xfsprogs-2.7.13 (08 February 2006) - Convert fsck into a shell script and make it provide a hint to run repair/check (in non-auto fsck modes). Thanks to Marian Jancar for this. - Fix compilation botch on non-Linux platforms (duplicate type definitions). xfsprogs-2.7.12 (31 January 2006) - Added initial Polish translation. Thanks to Jakub Bogusz for this. - Fixed rpm specfile with respect to INSTALL_{USER,GROUP}. xfsprogs-2.7.11 (16 January 2006) - Fix a problem with the generated source tarballs and a missing parent.h header file. xfsprogs-2.7.10 (16 December 2005) - Make xfs_db keep trying when root inode can't be read. - Make xfs_db check AGF BNO and CNT btree consistency. - Tweak a couple of libxfs headers so they can be used by C++ programs (removes nested struct declarations, which are used outside the scope they're declared in). - Fix a rounding issue in xfs_quota time reporting, making it more consistent with the standard quota utilities. - Fix dopey libxfs message "Unmount and run xfs_repair.", especially annoying when printed by xfs_repair itself. - Fix a dir2 xfs_repair bug, misdiagnosing a valid dir as corrupt. Thanks to Masanori Tsuda. xfsprogs-2.7.9 (08 December 2005) - Fix thinko in libxcmd cvtnum routine - Fix EFI/EFD printing in xfs_logprint xfsprogs-2.7.8 (05 December 2005) - Extend xfs_io to do aligned direct IO automatically - Report direct IO parameters (dioinfo) in xfs_io - Make xfs_mkfile a shell script wrapper around xfs_io xfsprogs-2.7.7 (16 November 2005) - Fix some gcc compiler warnings on 64 bit platforms. - Remove last reference to a (kernel) header. - Updated aclocal.m4 - Fix a bug in xfs_io lsproj/chproj recursive modes. - Add xfs_io recursive modes for the extsize command. - Add xfs_db version command modes for attr1 and attr2. xfsprogs-2.7.6 (31 October 2005) - Add support for the inode extent size hint for the regular data device (previously was realtime only), and allow the optional inheritance of this property. - Add support for additional read/write patterns in xfs_io (reverse and random, in addition to sequential forwards). - Add some mkfs debugging options to aid testing inheritance of realtime, project ID, and extsize inode attributes. - Add mkfs option for forcing use of ATTR2, and make growfs report its use. - Fix use of cursor in attr_list_by_handle() libhandle code. - Fix several compiler warnings when building on IRIX. xfsprogs-2.7.5 (26 October 2005) - Fix an endian bug in xfs_db "frag" command. - Fix some errors on the xfs_quota(8) man page. xfsprogs-2.7.4 (08 October 2005) - Fix read and write calls in xfs_io to allow buffers larger than 4GiB on 64 bit platforms. - FreeBSD build tweaks from Craig Rodrigues. - Fixed a few minor compiler warnings. xfsprogs-2.7.3 (29 September 2005) - Fix xfs_repair handling of the morebits bit. - Merge back several kernel changes related to attr2. - Extended xfs_db expert mode commands - Clean up some fsxattr uses to reduce number of syscalls, now that IRIX also supports project identifiers via this interface. xfsprogs-2.7.2 (28 September 2005) - Fix up xfs_repair segmentation fault due to wrong allocation size. xfsprogs-2.7.1 (20 September 2005) - Fix up reporting of devices in xfs_growfs - now uses /proc/mounts in preference to /etc/mtab. - Fix a strtok-related bug in the extraction of device names, also only affecting xfs_growfs. xfsprogs-2.7.0 (16 September 2005) - Support for updated extended attributes format (attr2) - Make xfs_quota tool issue a quota sync in all the needed places, before reporting, to counter affects of delayed allocation. - Quota-related ID signedness issue fixes. - Expert mode xfs_db commands to set/remove attributes. xfsprogs-2.6.37 (11 August 2005) - Fix FreeBSD builds (getmntinfo), thanks to Craig Rodrigues. xfsprogs-2.6.36 (28 July 2005) - Fix mkfs stripe unit alignment checks for external logs - Fix running xfs_db on non-XFS devices (was segfaulting) - Fix a 32 bit wrap in xfs_repair searching for secondary superblocks. xfsprogs-2.6.35 (01 July 2005) - Add back fd_to_handle() to libhandle. - Add handle call mappings to xfsctl() for IRIX. xfsprogs-2.6.34 (20 June 2005) - Switch to the fsxattr xfsctl for getting/setting project identifiers on inodes, remove the short-lived specialised ioctls for doing this. - Make the "blocktrash" xfs_db command available in expert- mode only. xfsprogs-2.6.33 (13 June 2005) - Another libhandle fix on 64bit, Big Endian systems. xfsprogs-2.6.32 (08 June 2005) - Minor endian cleanups in some tools. - Fix a couple of xfs_quota double-reporting issues when issuing commands via the -c (command line) 0option. xfsprogs-2.6.31 (06 June 2005) - Fix previous MD driver-specific change to correctly handle (i.e. not "stripe align") linear arrays. - Add MD RAID level 4, 6, and 10 support. - Make mkfs.xfs automatically adjiust the geometry to use a sector size that matches the block size when MD RAID level 4/5/6 are in use. - Couple of minor man page fixups, including patch botch on initial revision of xfs_quota(8). xfsprogs-2.6.30 (03 June 2005) - Add xfs_quota(8) command which knows how to do all things quota related, and can also do the XFS specific extensions like project quota, realtime device quota, etc. - Created a library of common code (libxcmd.a) shared by xfs_growfs, xfs_io and xfs_quota. - Fix use of regular files for realtime subvolumes (debugging only, really). - Fix bug in xfs_io command line option handling when commands where specified for multiple files at once. - Allow xfs_io to specify O_NONBLOCK for regular file IO. - Fix MD driver-specific code to not attempt stripe alignment for volumes that are not stripes (e.g. concat/mirror). xfsprogs-2.6.29 (19 April 2005) - Fix mkfs.xfs -dfile. - Fix libhandle on 64bit, Big Endian systems. xfsprogs-2.6.28 (30 March 2005) - Fix compiler warning in repair/dir.c size checks. - Fix more compilation problem with version 4 of gcc (thanks to Andreas Jochens). - Make xfs_db and xfs_repair cope with filesystems that have project quota enabled. xfsprogs-2.6.27 (23 March 2005) - Fix default mkfs allocation group size calculations for filesystem sizes in the range 32 - 64 terabytes. - Add noalign mkfs suboptions for -d/-r to disable the sunit/swidth auto-alignment (based on logical volume geometry, extracted from the driver). xfsprogs-2.6.26 (08 March 2005) - Fix compilation problem with version 4 of gcc (thanks to Andreas Jochens). - Added a streamlined for programs wanting to make use of the XFS-specific kernel interfaces (to address complaints that was "heavy"). - Add imap as an expert command in xfs_io, making it more easily accessible to those who need it. - Extended statistics reporting for xfs_io command. - Fixed readline support for current distributions. - Add an --enable-termcap=[yes/no] configure option, and changed --enable-readline=[yes/no] to not force linking with libtermcap. Builds on some platforms may need to use both options, but most distributions do not require --enable-termcap when linking against libreadline. - Minor man page updates. xfsprogs-2.6.25 (08 October 2004) - Fix build with really old glibc versions. xfsprogs-2.6.24 (29 September 2004) - Allow 'e' suffix in size arguments to mkfs. - Update mkfs man page description of maximum allocation group size. - Update mkfs and xfs_db man pages to use consistent, standard notations. - Sync up user/kernel source in libxfs and headers. xfsprogs-2.6.23 (17 September 2004) - Fix xfs_io pread/pwrite -b option, when used more than once we would use the largest of the previous values, instead of the (possibly smaller) value specified. - Add recursive modes to lsattr/chattr xfs_io commands. - Make xfs_io run any given command line commands (-c) on all files specified, not just the first. xfsprogs-2.6.22 (10 September 2004) - Update xfs_io to get a clean compile on IRIX with the MIPSPro compilers. - Add documentation about additional XFS inode flags. - Add xfs_io write options to include fsync/fdatasync in the timing results it displays. - Add xfs_fsop_counts output to the xfs_io statfs data, which also shows free realtime space, etc. - Add knowledge of additional inode flags for nosymlinks and project ID inheritance. xfsprogs-2.6.21 (09 August 2004) - Support realtime bit inheritance on directories. - Fix xfs_io build with unusual (old) glibc versions. - Fix tools to not issue the BLKFLSBUF ioctl to ramdisk devices. Thanks to Bo Yang for this fix. xfsprogs-2.6.20 (28 July 2004) - Fix a segfault on xfs_io open error path for non-XFS files. Thanks to Steinar H. Gunderson for this fix. xfsprogs-2.6.19 (16 July 2004) - Fix two byte count size wraps in xfs_copy. - Minor man page fixes from Eric Raymond. xfsprogs-2.6.18 (23 June 2004) - Fix libhandle from possibly returning an invalid handle length on systems where size_t is 64 bits. - Minor autoconf fixups to get rpm test working on all platforms again. - Minor man page updates fixing minus/hyphen usage. xfsprogs-2.6.17 (23 June 2004) - Fix use of isset macro, getting realtime devices to function correctly in xfs_db and xfs_repair. - Fix initialisation of realtime devices in libxfs. xfsprogs-2.6.16 (17 June 2004) - Add sendfile command into xfs_io(8) to exercise that functionality. - Remove maxtrres program that was used in the build to generate a header for mkfs' consumption. - This allows cross-compiles to be greatly simplified. - Portability tweaks for building on other platforms. - Fix obscure bug in log size lower boundary checks for auto-sized logs when stripe alignment is in effect; the enforced lower bound could have been set too low. xfsprogs-2.6.15 (09 June 2004) - Make xfs_check test for a dirty log before proceeding to check the filesystem. - Fix couple of minor bugs in xfs_io (readonly handling on writes, off-by-one error in open file error reporting). xfsprogs-2.6.14 (13 May 2004) - Allow logprint to copy a log to a file (-C) and to dump a log from beginning to end showing ondisk log record (-d). - Fix logprint handling of -f option - shouldn't be doing the UUID check in that case, since we don't have the SB. - Remove MD device superblock "clean" check, following Neil Brown's advice. - Small Debian packaging tweak to say xfsprogs has an fsck. xfsprogs-2.6.13 (03 May 2004) - Zero out more at beginning and end of device at mkfs time (get all old MD superblocks at the end, for mount by label). xfsprogs-2.6.12 (30 April 2004) - Extract stripe unit/width from device mapper devices (added libdisk infrastructure, used by mkfs.xfs). - Fix rounding in xfs_io(8) bytes read/written output. - Sync up user/kernel source in libxfs and headers. - Fix compiler warnings on 64 bit platforms. - Update i18n message catalog. xfsprogs-2.6.11 (15 April 2004) - Fix file descriptor leak in path_to_fshandle. A file was being opened but never closed, regardless of whether that descriptor was being cached. Now close the file on error or if it is not being cached. - Fix xfs_repair handling of a corrupt v2 directory with multiple entries having the same name. xfsprogs-2.6.10 (05 April 2004) - Fix botch in recent addition of new superblock field (features2) which could result in filesystems with v2 logs being created with invalid superblock fields. Thanks to Chris Pascoe for this fix. - Fix error when forcing a too-large v2 log stripe size back to 32K. Thanks to Chris Pascoe for this fix too. - Fix xfs_copy -d option so that it really does create a duplicate filesystem (the log is duplicated too now in that case, whereas previously a fresh log was created). xfsprogs-2.6.9 (26 March 2004) - Update HFILES in xfsprogs/io/Makefile to package io/io.h xfsprogs-2.6.8 (25 March 2004) - Fix xfs_db when dumping v2 dirs larger than the fsb size. - Several xfs_io additions - support for memory mapped areas, multiple open files, expert mode (freeze, shutdown, error injection, etc), fadvise (Linux-specific), allow user to specify a create mode to open(2). - Fix xfs_bmap verbose mode stripe alignment information. - Fix typo on xfs(5) man page. xfsprogs-2.6.7 (19 March 2004) - Fix up UUID library checks again, previous fix didn't work for older versions of autconf. - Allow for future extensions to the XFS ondisk structure by reserving an extra 32 bits in the superblock for feature bits (update xfs_db to dump them). - Fix xfs_repair handling of version 2 directories with a hole at the start. - Fix an endian bug in xfs_copy, when operating on allocation groups with multi-level freespace btrees. - Ensure xfs_repair "dangerous" mode does not attempt to set the device blocksize, this generates an error when target filesystem is mounted readonly. xfsprogs-2.6.6 (03 March 2004) - mkfs now opens the devices it's operating on with the O_EXCL flag set, which is used by the Linux 2.6 block layer to ensure concurrent access does not happen. - Allow xfs_io to operate on files from other filesystems, with the XFS-specific commands unavailable in this mode. - Fix configure scripts to also search for a UUID library in /usr/lib64 which is its home on AMD64/x86_64. xfsprogs-2.6.5 (20 February 2004) - Fix up mkfs to ensure that the log size is a multiple of the v2 log stripe size even if the log happens to be aligned on a log stripe boundary (always check it). xfsprogs-2.6.4 (17 February 2004) - Fix a few more libxfs/repair leaks. - Fix up some libhandle routines, add the open_by_fshandle routine required by recent versions of xfsdump. xfsprogs-2.6.3 (19 January 2004) - Merge Steve Langasek's work on the Debian installer support for xfsprogs. - Add knowledge to xfs_db about the security namespace in its extended attributes commands. - Sync up user/kernel source in libxfs and headers. - Fix a couple of compilation warnings. - Workaround for some versions of autoconf mishandling the AC_CHECK_SIZEOF macro. - Fix a memory leak in libxfs, most noticable in xfs_repair. xfsprogs-2.6.2 (17 December 2003) - Fix dev_t sizing issues in user tools - glibc uses a 64 bit number and XFS has a 32 device bit number, confusion reigns. Not much manipulates device numbers in the XFS user tools though, hence hasn't really been seen before. Thanks to Christoph for the patch. xfsprogs-2.6.1 (27 November 2003) - Human-friendly xfs_io read/write bsize specifications. - Dump throughput and IOPs values after xfs_io reads/writes. - Sync up user/kernel source in libxfs, libxlog and headers. xfsprogs-2.6.0 (28 October 2003) - Change to mkfs strategy for allocation group count and size default. Scales significantly better for large filesystems. xfsprogs-2.5.11 (10 October 2003) - Incorporate Jan Derfinaks change to the Linux block ioctls used in libxfs, allowing this code to compile cleanly with include files from Linux 2.6.0-test5 onward. xfsprogs-2.5.10 (30 September 2003) - Fix up xfs_logprint to handle version 2 logs for its operation output (previously core dumped on it). xfsprogs-2.5.9 (19 September 2003) - Sync up user/kernel source in libxfs, libxlog and headers. - Add new inode flags into xfs_db too. xfsprogs-2.5.8 (12 September 2003) - Add missing options to xfs_db frag command one-line summary. - Add xfs_io commands for setting and clearing new inode flags for immutable/append-only/sync/no-atime/no-dump. - Dump some other statfs fields in the xfs_io statfs commands. - Remove "test" mode from xfs_repair, only useful in xfs_check. - Fix problem in xfs_logprint where it was trying to continue in the presence of a corrupt log when it shouldn't have. - Fix an incorrect assertion in xfs_logprint in regards to the validity of the log start block. - Fix xfs_growfs (and hence xfs_info) to allow it to be given either a mount point or a device in the mount table - it'll figure it out and should do the right thing either way now. xfsprogs-2.5.7 (29 August 2003) - Sync up user/kernel source in libxfs and headers. - Make xfs_copy a tad more portable, although work remains. - Add a "test" mode to xfs_repair and xfs_check which allows for sparse (and hence extremely large) filesystem testing. xfsprogs-2.5.6 (19 August 2003) - Fix a mkfs problem where it could exit inappropriately when a large data volume stripe unit was either specified on the command line or via querying the underlying volume manager. xfsprogs-2.5.5 (07 August 2003) - Update xfs_io command to allow reading from non-XFS files. - Sync up user/kernel source in libxfs, libxlog and headers. - Update xfs_db and xfs_logprint commands to print new inode flush iteration field. xfsprogs-2.5.4 (23 July 2003) - Update xfs_io bmap command to report unwritten extent flag if it is set on an extent (in verbose mode only). - Introducing xfs_copy. - Fix shell quoting problem in xfs_bmap script. xfsprogs-2.5.3 (07 July 2003) - Update xfs_io commands which take user input in terms of byte counts to now also allow unit prefixes like mkfs.xfs. - Tweak build to avoid unnecessary rebuilds of international language files (if present), suggested by Steve Langasek. - Fix usage message in mkfs.xfs, it was out of date. - Fix some filesystem type detection code, in particular the bfs probe code was broken for 64 bit machines (found by QA test 032) and the hfs code was broken too (originally found by Ethan Benson). We now also detect hfs+ filesystems. xfsprogs-2.5.2 (25 June 2003) - Fix xvm stripe detection in libdisk - pass correctly sized structures to xvm ioctls. - Add pthread library checks into configure and build scripts for work-in-progress on xfs_repair and xfs_copy. - Fix missing initialisation of stripe unit/width alignment information during libxfs_mount. - Fix botched repair typecast for multi-terabyte filesystems. xfsprogs-2.5.1 (23 June 2003) - Fix libdisk device driver (volume managers) detection code used by mkfs, so that drivers with multiple majors are not incorrectly processed. xfsprogs-2.5.0 (18 June 2003) - Fix libdisk (and hence mkfs) code which warns on MD devices with the clean flag not set, apparently this is not so wise. - Fix libxfs_device_zero to work with smaller-than-requested write return values. - Fix error in xfs_io pwrite code with large request sizes. - Fix rounding-down-input problems in several xfs_io commands. - Changed mkfs.xfs default log size scaling algorithm slightly, to create larger logs at smaller filesystem sizes by default (thanks to Andi Kleen for the patch). - Enable support for sector sizes larger than 512 bytes. xfsprogs-2.4.12 (02 June 2003) - Fix xfs_logprint handling of any version 2 log device. - Remove calls to exit in libhandle, propogate errors to caller, and bumped libhandle version from 1.0.1 to 1.0.2. xfsprogs-2.4.11 (30 May 2003) - Extract device sector size at mkfs time and issue warnings if the requested filesystem sector size is too small. - Sync up user/kernel source in libxfs, libxlog and headers. - Skip realtime initialisation in libxfs mount path if the caller is xfs_db, otherwise we get nonsense warnings. - Update xfs_io with a couple of additional commands. - Fix xfs_logprint handling of corrupt v2 log devices. xfsprogs-2.4.10 (12 May 2003) - Fix a bug in mkfs - creating version 2 logs, an incorrect stripe unit value was being passed to libxfs_clear_log. All recent versions of xfs_repair will fix this, however, because xfs_repair uses the correct stripe unit value. - Fix a bug in xfs_logprint, when dumping a corrupt log. - FreeBSD updates from Alexander Kabaev. - Large sector size updates for mkfs (disabled at the moment). - Large sector size fixes for xfs_repair. - Sync up with aeb's mount source for filesystem detection. xfsprogs-2.4.9 (03 May 2003) - Allow xfs_repair to run on read-only filesystems. xfsprogs-2.4.8 (26 April 2003) - Rework configure.in to make use of shared macros. - Fix up #include lines to allow compilation of sources with installed headers rather than local headers. - Fix botches in xfs_bmap shell script which prevented any arguments being passed on to xfs_io (from Jan Derfinak). xfsprogs-2.4.7 (22 April 2003) - Clarify XFS system call interfaces, fix up documentation. xfsprogs-2.4.6 (11 April 2003) - Fix a bug in detection of "clean" and "error" states with MD devices. - Fix configure tests that used AC_PATH_PROG incorrectly. - Add support for libedit, if libreadline is unavailable. - Fix the libxfs build on big endian platforms. - Sync up user/kernel source in libxfs and headers. xfsprogs-2.4.5 (03 April 2003) - Sync up xfs_inode.c in libxfs. - Implement get_unaligned/put_unaligned in libxfs. xfsprogs-2.4.4 (30 March 2003) - Correct display of imaxpct in mkfs.xfs output. - Portability changes; including some code to support use of several tools on Mac OS X (for Russell), ditto for FreeBSD (from Russell); also did a simplistic backport to IRIX (for me), so that I can run purify on some of the tools. - See doc/INSTALL for more details on this. - Sync up user/kernel source in libxfs and headers. - Fix up some warnings when compiling libxfs on big endian platforms. - Fix a configure.in botch which resulted in libreadline always being used even when it was not asked for. - Fixed the configure.in script so that if gettext disabled, we don't check for the gettext tools (and no longer fails if they were not found). - Added the ability to specify a different user and/or group to install as (previously, and still by default, root/root were always used here). xfsprogs-2.4.3 (27 March 2003) - Cleanups to the build process, in particular the automatic rpm package generation Makefile and spec file template. - Makepkgs script can now propagate failures back from make. - Minor configure.in update to deal with readline libraries which have not been linked correctly. xfsprogs-2.4.2 (25 March 2003) - Added the xfs_io(8) command, an xfs_db(8) alike command for testing and debugging the XFS file IO path. - Added an optional dependency on the GNU readline library which is "off" by default and enabled with the configure option --enable-readline=yes; it affects the interactive tools only (xfs_db and now xfs_io). - Implemented xfs_bmap(8) as a shell script wrapper. - Documented the mkfs.xfs -f, -llogdev and -rrtdev options. - Corrected size check for realtime summary inode (not the same as the realtime bitmap inode) in xfs_repair. xfsprogs-2.4.1 (18 March 2003) - Fix error reporting when zeroing parts of the realtime device in phase6 of xfs_repair. - Add a mkfs.xfs check for Mac partitions before writing to the device. - Thanks to Ethan Benson for this. - Minor fix to the xfs_bmap(8) man page. - Sync up user/kernel source in libxfs and headers. xfsprogs-2.4.0 (06 March 2003) - Enable unwritten extents by default in mkfs.xfs. - Add a command to xfs_db to enable unwritten extents. - Add an option to xfs_admin to use the above command. - Add command to xfs_db to print out the currently enabled feature bits and version number. - Make xfs_db slightly more robust in the presense of bad ondisk data. - Rationalise some xfs_db superblock-related code and the uuid command now checks for a dirty log before zeroing. - Add stripe alignment information to xfs_bmap. - Sync up user/kernel source in libxfs and headers. - Update man pages, fix a typo in the xfs_admin man page relating to the UUID options. xfsprogs-2.3.11 (18 February 2003) - Missed a build dependency for the Debian build process. xfsprogs-2.3.10 (17 February 2003) - Fix a divide-by-zero error in mkfs with certain stripe unit and/or width options specified. - Sync up user/kernel source in libxfs and headers. xfsprogs-2.3.9 (31 December 2002) - Additional xfs_repair check in v2 directory handling for blks with no data entries (merged from IRIX), includes several handy comments sprinkled throughout this v2 dir code. - Fix an endian bug in the same area of code (v2 dirs, phase 6, longform_dir2_rebuild_setup) - xfs_repair has additional checks for bad sector values now. - xfs_repair I18N changes. - Fix detection of readonly mounts, slightly botched in 2.3.8. - Fix references to removed ioctl commands on xfs(5) man page. xfsprogs-2.3.8 (18 December 2002) - Initial support for I18N (still more to do here). - Initial changes for filesystems with greater than 512 byte sector sizes (still plenty more to do here too). - Tidy up libxfs functions which take a "flags" argument. - Sync up user/kernel source in lib{xfs,xlog} and headers. - Fixed incorrect use of XFS_FSB_TO_DADDR macro in xfs_db's faddr.c::fa_dirblock routine - now use XFS_FSB_TO_BB here, as set_cur() takes basic blocks as its third parameter. - Fixed obscure issue in mkfs where only the first AG would get its AGFL freelist "fixed" - not clear this caused any issues in practice (on Linux it's always been this way, we now match up with IRIX though). - Made xfs_growfs filesystem geometry output match up with that displayed by mkfs.xfs (xfs_growfs was missing a comma before the log version field). - Fixed an issue in xfs_repair where data past the end of the valid superblock fields was sometimes not cleared, when it really should have been (due to a libxfs problem). - Shell scripts (xfs_info, xfs_check, etc) now also report the xfsprogs version number via -V, like other commands. xfsprogs-2.3.7 (14 November 2002) - Fix an endian bug in xfs_db freesp command when descending into multi-level agf cnt/bno btrees. xfsprogs-2.3.6 (31 October 2002) - Sync up user/kernel source in lib{xfs,xlog} and headers. - Fix several warnings from newer (3.2) versions of gcc. - Minor header file shuffling. xfsprogs-2.3.5 (10 October 2002) - Sync up user/kernel source in lib{xfs,xlog} and headers. - Fix mkfs (libxfs) bug when using BLKFLSBUF ioctl - we passed in the device number instead of a file descriptor (and EBADF was the end result, which we ignored). - Thanks to Anton Blanchard for fixing this. xfsprogs-2.3.4 (04 October 2002) - Fix size calculation bug in xfs_repair's memory allocation, reduces memory usage by a factor of 4. xfsprogs-2.3.3 (16 September 2002) - Fix mkfs bug when optimizing AG size on striped devices, ASSERT(agcount != 0) tripped on single-ag filesystems. xfsprogs-2.3.2 (10 September 2002) - Use pread/pwrite instead of lseek + read/write. xfsprogs-2.3.1 (03 September 2002) - Allow xfs_db to accept negative numbers when writing values. xfsprogs-2.3.0 (03 September 2002) - Several changes to geometry ioctl callers which will make the tools useable on older kernel versions too. - Mainly affects xfs_bmap and xfs_growfs. - Do some additional cleanup after autoconf has run. xfsprogs-2.2.3 (28 August 2002) - Update libdisk for a few other filesystems. - Fix call to lvdisplay on LVM volumes so that lvdisplay always gets the full, real path to the volume, as required. xfsprogs-2.2.2 (19 August 2002) - Fix endian bug in xfs_db, was not flipping 16-bit numbers. - Make xfs_repair recognize a NULLFSINO and print that in addition to "18446744073709551615" for easy recognition. - Fix format string that xfs_repair uses when fixing inodes, so that the new inode numbers are printed correctly. xfsprogs-2.2.1 (09 August 2002) - Fix buglet in libdisk get_driver_block_major() routine which would result in incorrect majors being returned for not-found drivers. - Fix problem in install process with newer autoconf versions. xfsprogs-2.2.0 (08 August 2002) - mkfs.xfs defaults to a blocksize of 4096 bytes, and no longer uses getpagesize(2) to dynamically configure the default size. - Add EVMS stripe unit/width auto-detection support in mkfs.xfs (patch from Luciano Chavez). - Sync user/kernel headers (arch.h incorporated into xfs_arch.h, and several other minor changes). xfsprogs-2.1.2 (17 July 2002) - Fix up log stripe unit specification options, and update man page. Also fix suffix handling for data su/sw options (disallow unit suffixes on -d sunit,swidth,sw and -l sunit). Add "s" (512-byte sectors) as valid suffix. - Automatically select v2 logs if a log stripe unit is specified. xfsprogs-2.1.1 (04 July 2002) - Build infrastructure updates so that configure options can be used to specify paths rather than semi-hard-coded path names controlled by the ROOT/ROOT_PREFIX environment variables; eg. now allows /lib64 and /lib32 xfsprogs-2.1.0 (14 June 2002) - Support for XFS version 2 log format. - Fix for xfs_repair mangling i8count for dir2_sf directories - Minor mkfs.xfs man page update for blocksize limits on Linux - xfs_cred.h split into xfs_acl.h, xfs_cap.h and xfs_mac.h - Fix typo in mkfs realtime summary inode alloc failure message xfsprogs-2.0.6 (30 May 2002) - Fix error returns from log recovery (affects xfs_repair). - Fix the way mkfs.xfs round downs the device when the last AG is smaller than the minimum AG size. - Fix bug in xfs_repair da_write() routine, which affects filesystems where the data blocksize != naming blocksize (see xfs_info output). - Fix a use-after-free bug in xfs_repair code for checking version 1 btree-format directories. - Add checks of the ACL permissions field into xfs_repair. xfsprogs-2.0.5 (02 May 2002) - Size AGs so that they do not always start on the same part of a striped disk - Fix an off-by-one error on rounding down an AG that is too small to be an AG - Don't auto-grow the log to be larger than an AG - Change the error philosophy for -d su=,sw= away from forcing the XFS stripe size to match the volume manager stripe size and instead accept, with a warning, the stripe unit & width supplied on the commandline. - Update xfs_growfs man page - Don't build libxlog.a with DEBUG enabled - xfs_db fixes from ASANO Masahiro at NEC xfsprogs-2.0.4 (17 April 2002) - Minor update sync'ing with kernel changes (less endian swabbing in libxfs code) xfsprogs-2.0.3 (13 April 2002) - Important build system update, was causing libxfs to be built incorrectly, which can cause xfs_repair to fail by tripping asserts in additional libxfs debug code. xfsprogs-2.0.2 (04 April 2002) - Bumped version of libhandle to libhandle.so.1.0.1 This changes open_by_handle() and friends so that O_LARGEFILE is added to the open flags. This allows xfsdump to dump files greater than 2^31-1 bytes instead of not dumping the large files and giving warning messages. xfsprogs-2.0.1 (12 March 2002) - Fall back to BLKGETSIZE if BLKGETSIZE64 fails - Sync user/kernel headers and shared code xfsprogs-2.0.0 (26 February 2002) - Major release to coincide with switch to new extended attributes system call interfaces - bumped version of libhandle, added new symbols to use the reworked extended attributes handle ioctl interface - xfs_repair in no-modify mode opens the filesystem device read-only now (fix from Chris Pascoe) - sync up with recent (minor) changes to shared kernel code - switch to using the BLKGETSIZE64 ioctl in libxfs, instead of the (previously busted) BLKGETSIZE ioctl xfsprogs-1.3.19 (15 February 2002) - fix xfs_repair option parsing for external logs - add xfs_repair option parsing for realtime device - fix xfs_repair version (-V) option - should not require an argument - add -V option to usage string - document verbose (-v) and -r options in manpage xfsprogs-1.3.18 (17 January 2002) - fix mkfs.xfs buglet in overwriting signatures when run on a regular file xfsprogs-1.3.17 (14 January 2002) - mkfs.xfs overwrites pre-existing filesystem, swap, or md driver signatures. - xfs_repair fix to prevent double insertion into the uncertain_inode AVL trees ("avl_insert: duplicate range") - xfs_repair fix if the log is corrupted and we can't find the head, don't exit - just proceed on with zeroing it - use snprintf instead of sprintf throughout xfsprogs-1.3.16 (17 December 2001) - added text dump type to xfs_db (mkp) - removed use of a temporary file in xfs_db when processing commands on the command line - allows xfs_check to be run on read-only root filesystems xfsprogs-1.3.15 (12 December 2001) - reenable the use of the BLKBSZSET ioctl, it's baaack - sync recent XFS kernel source changes back into libxfs xfsprogs-1.3.14 (05 December 2001) - fix minor debian package version numbering issue - add documentation for xfs_db(8) label/uuid commands - automatic inode sizing code in mkfs.xfs has been removed (restricting inodes to 32 bits) - Steve's recent kernel changes mean this is no longer an issue - fix bug in mkfs.xfs size cross-check for realtime device xfsprogs-1.3.13 (25 October 2001) - fix bug in mkfs for 1Tbyte + filesystems - sync with recent kernel changes - this does not affect userspace (libxfs), all affected code is removed by cpp. xfsprogs-1.3.12 (17 October 2001) - implement the -f (file) option to xfs_logprint - rework the xlog code into libxlog for code sharing - xfs_repair now detects a dirty log and, without -L, will no longer blindly zero it (which prevents any recovery) xfsprogs-1.3.11 (17 October 2001) - tidy up some (benign) compiler warnings from libxfs - fixed 64-bit pointer alignment issues in xfs_check - fixed 64-bit pointer alignment issues in xfs_repair - verified these on IA64, also reported to fix sparc issues xfsprogs-1.3.10 (12 October 2001) - sync with XFS kernel header changes for EAs by-handle - ported xfs_imap command for dumping the inode map xfsprogs-1.3.9 (03 October 2001) - fix xfs_repair bug in handling a corrupt root directory inode with multiple "lost+found" entries - fix xfs_logprint bug in scanning for log head and tail - ensure xfs_bmap doesn't issue XFS ioctls to non-XFS files - numerous man page updates xfsprogs-1.3.8 (19 September 2001) - rewrote the LVM support used by mkfs.xfs to call external lvdisplay program to get volume geometry (mkp@mkp.net) - fix bug in LVM driver wrapper where it would not have been used at all, ever (since 1.3.0), due to idiot programmer error (*blush*) -- also thanks to mkp for the bug fix xfsprogs-1.3.7 (10 September 2001) - enable preallocation in xfs_mkfile [missed during port?] - fix xfs_db core dump when reporting freespace - allow libuuid to be linked dynamically if desired (based on a patch from Colin Walters , helps the folk working on the Debian installer for XFS) - licensing change for "libhandle" (was GPL, now LGPL-2.1) and some related header files xfsprogs-1.3.6 (31 August 2001) - make mkfs.xfs aware of geometries that might cause inode numbers to exceed 32 significant bits. - make xfs_growfs warn if new filesystem will have inode numbers that exceed 32 significant bits. - fix logprint bug in reporting extended attributes (thanks to Tang Lingbo for fixing this) - fix mkfs.xfs core dump when attemping to run on devices which are too small to hold a valid XFS filesystem xfsprogs-1.3.5 (13 August 2001) - fix bug in xfs_db bit handling on big endian platforms - fix mkfs bug related to too-small final allocation group - fix signedness bug in DMAPI ioctl structure definition xfsprogs-1.3.4 (04 August 2001) - fix endian bug in xfs_db "frag" command - small configure script changes to allow cross compilation - several man pages updated to document external log usage - install another shared library symlink for ld to find - switched on -fno-strict-aliasing for library object builds - fix several minor compiler warnings when building on IA64 xfsprogs-1.3.3 (27 July 2001) - fixes for (hopefully) the last few nits in libtool usage xfsprogs-1.3.2 (23 July 2001) - install static libs and libtool archives into /usr/lib - shared libraries are unchanged, however xfsprogs-1.3.1 (15 July 2001) - updated xfs_types.h file from the kernel changes needed for an xfsdump fix. - tidy up various aspects of the libtool rework - XVM stripe unit/width extraction - fix an endian bug in xfs_db "write" command - fix a build problem with liblvm.a installed - fix bug in xfs_growfs mount option parsing with external log - BLKSZSET ioctl now conditional via the Makefile (off by default) - rework some of the Debian packaging rules - fix sign of BLKGETSIZE ioctl argument in libxfs - updated xfs_fs.h with DMAPI setdm details for dump/restore xfsprogs-1.3.0 (11 July 2001) - reworked Makefiles to use libtool - new libdisk to allow sharing of generic mount/disk code and - also abstracts individual driver support (LVM, MD, XVM..) - partition table detection so mkfs.xfs doesn't blindly overwrite - small xfs_repair bug fix from Steve xfsprogs-1.2.8 (02 July 2001) - fixed a bug in libxfs /etc/mtab read-only mount detection - first try procfs, fall back to /etc/mtab, for read-only mounts - sync with recent mount code changes for reiserfs and ext3 probes - fix logprint build problem under gcc 3.0 xfsprogs-1.2.7 (22 May 2001) - new xfs_freeze(8) command - volume manager snapshot helper xfsprogs-1.2.6 (15 May 2001) - merge support for -d agsize=/su=/sw= (AG, stripe unit/width size) - merge support for dynamic configuration of default log size - document these and fix a couple of man page typos too xfsprogs-1.2.5 (07 May 2001) - fix missing Makefile include entries for LVM headers - configure script default man path now /usr/share/man - add experimental xfs_rtcp (realtime copy) command - powerpc build failure fixups - thanks to Robert Ramiega - cleanup arch-specific code, esp. the byteswab routines - as a result, move to -O1 as default for extern inlines xfsprogs-1.2.4 (01 May 2001) - added -L option to mkfs.xfs (filesystem label) xfsprogs-1.2.3 (27 April 2001) - add dquot and quotaoff log item support into xfs_logprint - fix logprint core dump reporting AGI in "continue"'d transactions xfsprogs-1.2.2 (09 April 2001) - fix problem in xfs_db (check) group quota logic - fixes to warnings from recent gcc and/or 64-bit builds xfsprogs-1.2.1 (04 April 2001) - sync up with recent changes to XFS kernel headers xfsprogs-1.2.0 (01 April 2001) - support for group quota added - some headers updated, in particular - now in late stages of beta xfsprogs-1.1.9 (26 March 2001) - added automagic stripe unit/stripe width extraction for MD devices xfsprogs-1.1.8 (23 March 2001) - mkfs heuristics to make a qualified guess of internal logsize xfsprogs-1.1.7 (20 March 2001) - upgraded LVM to 0.9beta6 - minor rpm spec file changes xfsprogs-1.1.6 (20 March 2001) - fix sparc build failure - fcntl.h missing O_DIRECT - added README.quota describing use of quota with XFS xfsprogs-1.1.5 (12 March 2001) - upgraded LVM support to 0.9beta2 (IOP 10) xfsprogs-1.1.4 (10 March 2001) - kernel now supports O_DIRECT - re-enable its use in xfs_mkfile - BLKSETSIZE ioctl replaced by BLKBSZSET ioctl in libxfs - libxfs_init extended so only mkfs and xfs_repair use BLKBSZSET - NOTE: this version requires an XFS kernel from March 9 or later xfsprogs-1.1.3 (02 March 2001) - minor Makefile-related cleanups xfsprogs-1.1.2 (10 February 2001) - added libhandle routines to simplify dump/restore EA support xfsprogs-1.1.1 (30 January 2001) - minor rpm and deb packaging work xfsprogs-1.1.0 (15 January 2001) - rework xfs-cmds package into base, devel and dump packages - completed Debian packaging - late beta code xfs-cmds-1.0.7 (02 January 2001) - added mkfs support for extracting LVM stripe unit/width - libattr (*experimental* extended attributes interface) added - removed xfs_fstab.5 man page (merged into mount.8) - install xfs_repair into /sbin, not /usr/sbin xfs-cmds-1.0.6 (04 October 2000) - reworked external log format to be IRIX compatible - mkfs, repair, db, logprint now work with new format - xfs_admin added for setting filesystem label xfs-cmds-1.0.5 (18 September 2000) - minor bug fixes - first beta release xfs-cmds-1.0.4 (18 August 2000) - minor bug fixes - xfs_growfs added - xfs_info added - late alpha code xfs-cmds-1.0.3 (16 August 2000) - numerous bug fixes - xfsdump and xfsrestore added - xfsstats added - fsck.xfs (symlink to /bin/true) added - demise of sim library complete, mkfs and repair reworked - no longer need to have an XFS kernel handy for building xfs-cmds - xfs_copy compiles on Linux - dump/restore README added - late alpha code xfs-cmds-1.0.2 (27 July 2000) - numerous bug fixes - xfs_attr (extended attributes) command added - fsr_xfs added (ported by jones@tacc.utexas.edu) - LVM+XFS README added - early alpha code xfs-cmds-1.0.1 (5 July 2000) - numerous bug fixes - reworked build environment - begun work on user/kernel separation - early alpha code xfs-cmds-1.0.0 (16 June 2000) - initial release for USENIX CDs - early alpha code xfsprogs-5.3.0/doc/CREDITS0000644000175000017500000000376013034246041015034 0ustar nathansnathans This is a credits-file of people that have contributed to the Linux/XFS project. It is sorted by name and formatted to allow easy grepping and beautification by scripts (i.e. it follows the same format Linus has used in the kernel). The fields are: name (N), email (E), web-address (W), PGP key ID and fingerprint (P), description (D), and snail-mail address (S). ---------- N: Jens Axboe E: axboe@suse.de D: Block/elevator/kiobuf hacking, IDE kiobuf support S: Peter Bangs Vej 258, 2TH S: 2500 Valby S: Denmark N: Ethan Benson E: erbenson@alaska.net D: Additional inode flags (immutable, append-only, etc) S: P.O. Box 770525 S: Eagle River, AK 99577 S: Alaska N: Nicolas Boullis E: nboullis@debian.org D: fix XFS recovery on 64-bit big-endian architectures N: Danny Cox E: danscox@mindspring.com D: ACL port to Linux N: Thomas Graichen E: tgr@spoiled.org D: Original XFS FAQ maintainer D: PowerPC and Alpha porting S: Berlin, Germany N: Juergen Hasch E: hasch@t-online.de D: libacl fixes S: Meisenstr. 23, 73066 Uhingen, Germany N: Bill Jones E: jones@hpc.utexas.edu D: fsr port to Linux S: Austin, Texas, USA N: Jan Kara E: jack@atrey.karlin.mff.cuni.cz E: jack@suse.cz D: Quota 3.01 user tools, allowing different forms of quota to coexist D: Merging XFS support into quota user tools W: http://atrey.karlin.mff.cuni.cz/~jack/ S: Krosenska' 543 S: 181 00 Praha 8 S: Czech Republic N: Andi Kleen E: ak@muc.de D: Most recently, fine-tuning default mkfs/mount logsize/logbufs values S: Schwalbenstr. 96 S: 85551 Ottobrunn S: Germany N: Seth Mos E: seth@arosa.nl D: XFS FAQ ( http://oss.sgi.com/projects/xfs/faq.html ) maintainer W: http://iserv.nl/ S: Den Helder, The Netherlands N: Bart Samwel E: bart@samwel.tk W: http://www.xs4all.nl/~bsamwel/laptop_mode/ D: Laptop mode for XFS N: Robert Stickel E: previously: rstickel@connex.com D: libacl port to Linux N: John Trostel E: john.trostel@gtri.gatech.edu D: libacl extensions for Linux S: GTRI/EOEML, Georgia Institute of Technology, Atlanta, GA 30332, USA xfsprogs-5.3.0/doc/INSTALL0000644000175000017500000000315313435336036015052 0ustar nathansnathansThis document describes how to configure and build the open source XFS commands and utilites ("xfsprogs") from source, and how to install and run them. See the README file in the top level directory for details about how to contribute to the XFS project. Linux Instructions ================== 0. If you have the binary rpm, simply install it and skip to step 2 (below). The rpm command to do this is: # rpm -Uvh xfsprogs-*.rpm [and optionally, for the development libraries and headers] # rpm -Uvh xfsprogs-devel-*.rpm The Debian command to do this is: # apt-get install xfsprogs [and optionally, for the development libraries and headers] # apt-get install xfslibs-dev 1. Configure, build and install the package The xfsprogs package uses autoconf/configure and expects a GNU build environment (your platform must at least have both autoconf and gmake). You will also need to have installed either the e2fsprogs-devel package (on an RPM based system) or the uuid-dev package (on a Debian system) as some of the commands make use of the UUID library provided by these. To build the package and install it manually, use the following steps: # make # su root # make install [and optionally, for the development libraries and headers] # make install-dev Note that there are so many "install" variants out there that we wrote our own script (see "install-sh" in the top level directory). If you wish to turn off debugging asserts in the command build and turn on the optimizer then set the shell environment variables: OPTIMIZER=-O1 DEBUG=-DNDEBUG before running make or Makepkgs. xfsprogs-5.3.0/doc/Makefile0000644000175000017500000000105713435336036015462 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LSRCFILES = INSTALL CHANGES CREDITS sparse.txt LDIRT = *.gz default: CHANGES.gz include $(BUILDRULES) CHANGES.gz: @echo " [ZIP] $@" $(Q)$(ZIP) --best -c < CHANGES > $@ install: default $(INSTALL) -m 755 -d $(PKG_DOC_DIR) $(INSTALL) -m 644 CHANGES.gz CREDITS $(PKG_DOC_DIR) ifeq ($(PKG_DISTRIBUTION), debian) $(INSTALL) -S CHANGES.gz $(PKG_DOC_DIR)/changelog.gz endif install-dev: xfsprogs-5.3.0/doc/README-env-vars.txt0000644000175000017500000000226713435336036017263 0ustar nathansnathansSeveral environment variables are used within the code, primarily for for debugging purposes; they are documented here. In most cases simply setting the environment variable enables the behavior, but in some cases the value assigned influences behavior as well, as noted below. General ------- LIBXFS_LEAK_CHECK -- warn and exit(1) if zone-allocated memory is leaked at exit. xfs_fsr ------- FSRXFSTEST -- enable -C nfrag in theory coalesces into nfrag extents. Doesn't work. xfs_scrub --------- Known debug tweaks (pass -d and set the environment variable): XFS_SCRUB_FORCE_ERROR -- pretend all metadata is corrupt XFS_SCRUB_FORCE_REPAIR -- repair all metadata even if it's ok XFS_SCRUB_NO_KERNEL -- pretend there is no kernel ioctl XFS_SCRUB_NO_SCSI_VERIFY -- disable SCSI VERIFY (if present) XFS_SCRUB_PHASE -- run only this scrub phase XFS_SCRUB_THREADS -- start exactly this number of threads Available even in non-debug mode: SERVICE_MODE -- compress all error codes to 1 for LSB service action compliance xfsprogs-5.3.0/doc/sparse.txt0000644000175000017500000000254513435336036016063 0ustar nathansnathansThis document describes how to use the sparse source code checking tool to check the source code of the open source XFS commands and utilites ("xfsprogs"). First you need to install sparse, either from your distribution or from source as provided at http://www.kernel.org/pub/software/devel/sparse/. Then, run make with "make C=1" to run sparse on all the C files that get recompiled, or use "make C=2" to run sparse on the files whether they need to be recompiled or not. The latter is a fast way to check the whole tree if you have already built it. See the top-level Makefile for a list of which sparse flags are enabled. If you'd rather run sparse more manually, just set the compiler to cgcc, which is a wrapper that calls both sparse and gcc using: CC=cgcc ./configure Now that default warnings from sparse are a little bit verbose checking for various not that important things and also complaining about the glibc system headers. It does however not check for bitwise annotation which are very important for xfsprogs to verify the endianess handling of the on-disk structures is correct. To get a more reasonable set of warnings build xfsprogs using: LCFLAGS="-Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl" make You are of course free to experiment with the warnings flags documented in the sparse manpage to check xfsprogs for other issues. xfsprogs-5.3.0/estimate/Makefile0000644000175000017500000000061213435336036016524 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_estimate CFILES = xfs_estimate.c default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/estimate/xfs_estimate.c0000644000175000017500000001367013435336036017733 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002 Silicon Graphics, Inc. * All Rights Reserved. */ /* * Estimate space of an XFS filesystem * * XXX: assumes dirv1 format. */ #include "libxfs.h" #include #include static unsigned long long cvtnum(char *s) { unsigned long long i; char *sp; i = strtoll(s, &sp, 0); if (i == 0 && sp == s) return 0LL; if (*sp == '\0') return i; if (*sp =='k' && sp[1] == '\0') return 1024LL * i; if (*sp =='m' && sp[1] == '\0') return 1024LL * 1024LL * i; if (*sp =='g' && sp[1] == '\0') return 1024LL * 1024LL * 1024LL * i; return 0LL; } int ffn(const char *, const struct stat *, int, struct FTW *); #define BLOCKSIZE 4096 #define INODESIZE 256 #define PERDIRENTRY \ (sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_data_entry_t)) #define LOGSIZE 1000 #define FBLOCKS(n) ((n)/blocksize) static unsigned long long dirsize=0; /* bytes */ static unsigned long long logsize=LOGSIZE*BLOCKSIZE; /* bytes */ static unsigned long long fullblocks=0; /* FS blocks */ static unsigned long long isize=0; /* inodes bytes */ static unsigned long long blocksize=BLOCKSIZE; static unsigned long long nslinks=0; /* number of symbolic links */ static unsigned long long nfiles=0; /* number of regular files */ static unsigned long long ndirs=0; /* number of directories */ static unsigned long long nspecial=0; /* number of special files */ static unsigned long long verbose=0; /* verbose mode TRUE/FALSE */ static int __debug = 0; static int ilog = 0; static int elog = 0; static void usage(char *progname) { fprintf(stderr, _("Usage: %s [opts] directory [directory ...]\n" "\t-b blocksize (fundamental filesystem blocksize)\n" "\t-i logsize (internal log size)\n" "\t-e logsize (external log size)\n" "\t-v prints more verbose messages\n" "\t-V prints version and exits\n" "\t-h prints this usage message\n\n" "Note:\tblocksize may have 'k' appended to indicate x1024\n" "\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n"), basename(progname)); exit(1); } int main(int argc, char **argv) { unsigned long long est; extern int optind; extern char *optarg; char dname[40]; int c; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); while ((c = getopt (argc, argv, "b:hdve:i:V")) != EOF) { switch (c) { case 'b': blocksize=cvtnum(optarg); if (blocksize <= 0LL) { fprintf(stderr, _("blocksize %llu too small\n"), blocksize); usage(argv[0]); } else if (blocksize > 64LL * 1024LL) { fprintf(stderr, _("blocksize %llu too large\n"), blocksize); usage(argv[0]); } break; case 'i': if (elog) { fprintf(stderr, _("already have external log " "noted, can't have both\n")); usage(argv[0]); } logsize=cvtnum(optarg); ilog++; break; case 'e': if (ilog) { fprintf(stderr, _("already have internal log " "noted, can't have both\n")); usage(argv[0]); } logsize=cvtnum(optarg); elog++; break; case 'v': verbose = 1; break; case 'd': __debug++; break; case 'V': printf(_("%s version %s\n"), basename(argv[0]), VERSION); exit(0); default: case 'h': usage(argv[0]); } } if (optind == argc) usage(argv[0]); if (!elog && !ilog) { ilog=1; logsize=LOGSIZE * blocksize; } if (verbose) printf(_("directory bsize blocks megabytes logsize\n")); for ( ; optind < argc; optind++) { dirsize=0LL; /* bytes */ fullblocks=0LL; /* FS blocks */ isize=0LL; /* inodes bytes */ nslinks=0LL; /* number of symbolic links */ nfiles=0LL; /* number of regular files */ ndirs=0LL; /* number of directories */ nspecial=0LL; /* number of special files */ nftw(argv[optind], ffn, 40, FTW_PHYS | FTW_MOUNT); if (__debug) { printf(_("dirsize=%llu\n"), dirsize); printf(_("fullblocks=%llu\n"), fullblocks); printf(_("isize=%llu\n"), isize); printf(_("%llu regular files\n"), nfiles); printf(_("%llu symbolic links\n"), nslinks); printf(_("%llu directories\n"), ndirs); printf(_("%llu special files\n"), nspecial); } est = FBLOCKS(isize) + 8 /* blocks for inodes */ + FBLOCKS(dirsize) + 1 /* blocks for directories */ + fullblocks /* blocks for file contents */ + (8 * 16) /* fudge for overhead blks (per ag) */ + FBLOCKS(isize / INODESIZE); /* 1 byte/inode for map */ if (ilog) est += (logsize / blocksize); if (!verbose) { printf(_("%s will take about %.1f megabytes\n"), argv[optind], (double)est*(double)blocksize/(1024.0*1024.0)); } else { /* avoid running over 39 characters in field */ strncpy(dname, argv[optind], 40); dname[39] = '\0'; printf(_("%-39s %5llu %8llu %10.1fMB %10llu\n"), dname, blocksize, est, (double)est*(double)blocksize/(1024.0*1024.0), logsize); } if (!verbose && elog) { printf(_("\twith the external log using %llu blocks "), logsize/blocksize); printf(_("or about %.1f megabytes\n"), (double)logsize/(1024.0*1024.0)); } } return 0; } int ffn(const char *path, const struct stat *stb, int flags, struct FTW *f) { /* cases are in most-encountered to least-encountered order */ dirsize+=PERDIRENTRY+strlen(path); isize+=INODESIZE; switch (S_IFMT & stb->st_mode) { case S_IFREG: /* regular files */ fullblocks+=FBLOCKS(stb->st_blocks * 512 + blocksize-1); if (stb->st_blocks * 512 < stb->st_size) fullblocks++; /* add one bmap block here */ nfiles++; break; case S_IFLNK: /* symbolic links */ if (stb->st_size >= (INODESIZE - (sizeof(xfs_dinode_t)+4))) fullblocks+=FBLOCKS(stb->st_size + blocksize-1); nslinks++; break; case S_IFDIR: /* directories */ dirsize+=blocksize; /* fudge upwards */ if (stb->st_size >= blocksize) dirsize+=blocksize; ndirs++; break; case S_IFIFO: /* named pipes */ case S_IFCHR: /* Character Special device */ case S_IFBLK: /* Block Special device */ case S_IFSOCK: /* socket */ nspecial++; break; } return 0; } xfsprogs-5.3.0/fsck/Makefile0000644000175000017500000000054613435336036015645 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2006 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LSRCFILES = xfs_fsck.sh default: $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR) $(INSTALL) -m 755 xfs_fsck.sh $(PKG_ROOT_SBIN_DIR)/fsck.xfs install-dev: xfsprogs-5.3.0/fsck/xfs_fsck.sh0000755000175000017500000000366013435336036016352 0ustar nathansnathans#!/bin/sh -f # # Copyright (c) 2006 Silicon Graphics, Inc. All Rights Reserved. # NAME=$0 # get the right return code for fsck repair2fsck_code() { case $1 in 0) return 0 # everything is ok ;; 1) echo "$NAME error: xfs_repair could not fix the filesystem." 1>&2 return 4 # errors left uncorrected ;; 2) echo "$NAME error: The filesystem log is dirty, mount it to recover" \ "the log. If that fails, refer to the section DIRTY LOGS in the" \ "xfs_repair manual page." 1>&2 return 4 # dirty log, don't do anything and let the user solve it ;; 4) return 1 # The fs has been fixed ;; 127) echo "$NAME error: xfs_repair was not found!" 1>&2 return 4 ;; *) echo "$NAME error: An unknown return code from xfs_repair '$1'" 1>&2 return 4 # something went wrong with xfs_repair esac } AUTO=false FORCE=false while getopts ":aApyf" c do case $c in a|A|p|y) AUTO=true;; f) FORCE=true;; esac done eval DEV=\${$#} if [ ! -e $DEV ]; then echo "$0: $DEV does not exist" exit 8 fi # The flag -f is added by systemd/init scripts when /forcefsck file is present # or fsck.mode=force is used during boot; an unclean shutdown won't trigger # this check, user has to explicitly require a forced fsck. # But first of all, test if it is a non-interactive session. # Invoking xfs_repair via fsck.xfs is only intended to happen via initscripts. # Normal administrative filesystem repairs should always invoke xfs_repair # directly. # # Use multiple methods to capture most of the cases: # The case for *i* and -n "$PS1" are commonly suggested in bash manual # and the -t 0 test checks stdin case $- in *i*) FORCE=false ;; esac if [ -n "$PS1" -o -t 0 ]; then FORCE=false fi if $FORCE; then xfs_repair -e $DEV repair2fsck_code $? exit $? fi if $AUTO; then echo "$0: XFS file system." else echo "If you wish to check the consistency of an XFS filesystem or" echo "repair a damaged filesystem, see xfs_repair(8)." fi exit 0 xfsprogs-5.3.0/fsr/Makefile0000644000175000017500000000110513435336036015501 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_fsr CFILES = xfs_fsr.c LLDLIBS = $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBBLKID) LTDEPENDENCIES = $(LIBHANDLE) $(LIBFROG) LLDFLAGS = -static-libtool-libs ifeq ($(HAVE_GETMNTENT),yes) LCFLAGS += -DHAVE_GETMNTENT endif default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/fsr/xfs_fsr.c0000644000175000017500000012163013570057155015667 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "xfs.h" #include "xfs_types.h" #include "jdm.h" #include "xfs_bmap_btree.h" #include "xfs_attr_sf.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" #include #include #include #include #include #include #include #include #include #define _PATH_FSRLAST "/var/tmp/.fsrlast_xfs" #define _PATH_PROC_MOUNTS "/proc/mounts" char *progname; static int vflag; static int gflag; static int Mflag; /* static int nflag; */ static int dflag = 0; /* static int sflag; */ static int argv_blksz_dio; extern int max_ext_size; static int npasses = 10; static int startpass = 0; static struct getbmap *outmap = NULL; static int outmap_size = 0; static int RealUid; static int tmp_agi; static int64_t minimumfree = 2048; #define MNTTYPE_XFS "xfs" #define SMBUFSZ 1024 #define ROOT 0 #define NULLFD -1 #define GRABSZ 64 #define TARGETRANGE 10 #define BUFFER_MAX (1<<24) static time_t howlong = 7200; /* default seconds of reorganizing */ static char *leftofffile = _PATH_FSRLAST; /* where we left off last */ static time_t endtime; static time_t starttime; static xfs_ino_t leftoffino = 0; static int pagesize; void usage(int ret); static int fsrfile(char *fname, xfs_ino_t ino); static int fsrfile_common( char *fname, char *tname, char *mnt, int fd, struct xfs_bstat *statp); static int packfile(char *fname, char *tname, int fd, struct xfs_bstat *statp, struct fsxattr *fsxp); static void fsrdir(char *dirname); static int fsrfs(char *mntdir, xfs_ino_t ino, int targetrange); static void initallfs(char *mtab); static void fsrallfs(char *mtab, int howlong, char *leftofffile); static void fsrall_cleanup(int timeout); static int getnextents(int); int xfsrtextsize(int fd); int xfs_getrt(int fd, struct statvfs *sfbp); char * gettmpname(char *fname); char * getparent(char *fname); int fsrprintf(const char *fmt, ...); int read_fd_bmap(int, struct xfs_bstat *, int *); int cmp(const void *, const void *); static void tmp_init(char *mnt); static char * tmp_next(char *mnt); static void tmp_close(char *mnt); static struct xfs_fsop_geom fsgeom; /* geometry of active mounted system */ #define NMOUNT 64 static int numfs; typedef struct fsdesc { char *dev; char *mnt; int npass; } fsdesc_t; static fsdesc_t *fs, *fsbase, *fsend; static int fsbufsize = 10; /* A starting value */ static int nfrags = 0; /* Debug option: Coerse into specific number * of extents */ static int openopts = O_CREAT|O_EXCL|O_RDWR|O_DIRECT; static int xfs_swapext(int fd, xfs_swapext_t *sx) { return ioctl(fd, XFS_IOC_SWAPEXT, sx); } static int xfs_fscounts(int fd, xfs_fsop_counts_t *counts) { return ioctl(fd, XFS_IOC_FSCOUNTS, counts); } static void aborter(int unused) { fsrall_cleanup(1); exit(1); } int main(int argc, char **argv) { struct stat sb; char *argname; int c; struct fs_path *fsp; char *mtab = NULL; setlinebuf(stdout); progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); gflag = ! isatty(0); while ((c = getopt(argc, argv, "C:p:e:MgsdnvTt:f:m:b:N:FV")) != -1) { switch (c) { case 'M': Mflag = 1; break; case 'g': gflag = 1; break; case 'n': /* nflag = 1; */ break; case 'v': ++vflag; break; case 'd': dflag = 1; break; case 's': /* frag stats only */ /* sflag = 1; */ fprintf(stderr, _("%s: Stats not yet supported for XFS\n"), progname); usage(1); break; case 't': howlong = atoi(optarg); break; case 'f': leftofffile = optarg; break; case 'm': mtab = optarg; break; case 'b': argv_blksz_dio = atoi(optarg); break; case 'p': npasses = atoi(optarg); break; case 'C': /* Testing opt: coerses frag count in result */ if (getenv("FSRXFSTEST") != NULL) { nfrags = atoi(optarg); openopts |= O_SYNC; } break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); default: usage(1); } } /* * If the user did not specify an explicit mount table, try to use * /proc/mounts if it is available, else /etc/mtab. We prefer * /proc/mounts because it is kernel controlled, while /etc/mtab * may contain garbage that userspace tools like pam_mounts wrote * into it. */ if (!mtab) { if (access(_PATH_PROC_MOUNTS, R_OK) == 0) mtab = _PATH_PROC_MOUNTS; else mtab = _PATH_MOUNTED; } if (vflag) setbuf(stdout, NULL); starttime = time(NULL); /* Save the caller's real uid */ RealUid = getuid(); pagesize = getpagesize(); fs_table_initialise(0, NULL, 0, NULL); if (optind < argc) { for (; optind < argc; optind++) { argname = argv[optind]; if (lstat(argname, &sb) < 0) { fprintf(stderr, _("%s: could not stat: %s: %s\n"), progname, argname, strerror(errno)); continue; } if (S_ISLNK(sb.st_mode)) { struct stat sb2; if (stat(argname, &sb2) == 0 && (S_ISBLK(sb2.st_mode) || S_ISCHR(sb2.st_mode))) sb = sb2; } fsp = fs_table_lookup_mount(argname); if (!fsp) fsp = fs_table_lookup_blkdev(argname); if (fsp != NULL) { fsrfs(fsp->fs_dir, 0, 100); } else if (S_ISCHR(sb.st_mode)) { fprintf(stderr, _( "%s: char special not supported: %s\n"), progname, argname); exit(1); } else if (S_ISDIR(sb.st_mode) || S_ISREG(sb.st_mode)) { if (!platform_test_xfs_path(argname)) { fprintf(stderr, _( "%s: cannot defragment: %s: Not XFS\n"), progname, argname); continue; } if (S_ISDIR(sb.st_mode)) fsrdir(argname); else fsrfile(argname, sb.st_ino); } else { printf( _("%s: not fsys dev, dir, or reg file, ignoring\n"), argname); } } } else { initallfs(mtab); fsrallfs(mtab, howlong, leftofffile); } return 0; } void usage(int ret) { fprintf(stderr, _( "Usage: %s [-d] [-v] [-g] [-t time] [-p passes] [-f leftf] [-m mtab]\n" " %s [-d] [-v] [-g] xfsdev | dir | file ...\n" " %s -V\n\n" "Options:\n" " -g Print to syslog (default if stdout not a tty).\n" " -t time How long to run in seconds.\n" " -p passes Number of passes before terminating global re-org.\n" " -f leftoff Use this instead of %s.\n" " -m mtab Use something other than /etc/mtab.\n" " -d Debug, print even more.\n" " -v Verbose, more -v's more verbose.\n" " -V Print version number and exit.\n" ), progname, progname, progname, _PATH_FSRLAST); exit(ret); } /* * initallfs -- read the mount table and set up an internal form */ static void initallfs(char *mtab) { struct mntent_cursor cursor; struct mntent *mnt= NULL; int mi; char *cp; struct stat sb; /* malloc a number of descriptors, increased later if needed */ if (!(fsbase = (fsdesc_t *)malloc(fsbufsize * sizeof(fsdesc_t)))) { fsrprintf(_("out of memory: %s\n"), strerror(errno)); exit(1); } fsend = (fsbase + fsbufsize - 1); /* find all rw xfs file systems */ mi = 0; fs = fsbase; if (platform_mntent_open(&cursor, mtab) != 0){ fprintf(stderr, "Error: can't get mntent entries.\n"); exit(1); } while ((mnt = platform_mntent_next(&cursor)) != NULL) { int rw = 0; if (strcmp(mnt->mnt_type, MNTTYPE_XFS ) != 0 || stat(mnt->mnt_fsname, &sb) == -1 || !S_ISBLK(sb.st_mode)) continue; cp = strtok(mnt->mnt_opts,","); do { if (strcmp("rw", cp) == 0) rw++; } while ((cp = strtok(NULL, ",")) != NULL); if (rw == 0) { if (dflag) fsrprintf(_("Skipping %s: not mounted rw\n"), mnt->mnt_fsname); continue; } if (mi == fsbufsize) { fsbufsize += NMOUNT; if ((fsbase = (fsdesc_t *)realloc((char *)fsbase, fsbufsize * sizeof(fsdesc_t))) == NULL) { fsrprintf(_("out of memory: %s\n"), strerror(errno)); exit(1); } if (!fsbase) { fsrprintf(_("out of memory on realloc: %s\n"), strerror(errno)); exit(1); } fs = (fsbase + mi); /* Needed ? */ } fs->dev = strdup(mnt->mnt_fsname); fs->mnt = strdup(mnt->mnt_dir); if (fs->dev == NULL) { fsrprintf(_("strdup(%s) failed\n"), mnt->mnt_fsname); exit(1); } if (fs->mnt == NULL) { fsrprintf(_("strdup(%s) failed\n"), mnt->mnt_dir); exit(1); } mi++; fs++; } platform_mntent_close(&cursor); numfs = mi; fsend = (fsbase + numfs); if (numfs == 0) { fsrprintf(_("no rw xfs file systems in mtab: %s\n"), mtab); exit(0); } if (vflag || dflag) { fsrprintf(_("Found %d mounted, writable, XFS filesystems\n"), numfs); if (dflag) for (fs = fsbase; fs < fsend; fs++) fsrprintf("\t%-30.30s%-30.30s\n", fs->dev, fs->mnt); } } static void fsrallfs(char *mtab, int howlong, char *leftofffile) { int fd; int error; int found = 0; char *fsname; char buf[SMBUFSZ]; int mdonly = Mflag; char *ptr; xfs_ino_t startino = 0; fsdesc_t *fsp; struct stat sb, sb2; fsrprintf("xfs_fsr -m %s -t %d -f %s ...\n", mtab, howlong, leftofffile); endtime = starttime + howlong; fs = fsbase; /* where'd we leave off last time? */ if (lstat(leftofffile, &sb) == 0) { if ( (fd = open(leftofffile, O_RDONLY)) == -1 ) { fsrprintf(_("%s: open failed\n"), leftofffile); } else if ( fstat(fd, &sb2) == 0) { /* * Verify that lstat & fstat point to the * same regular file (no links/no quick spoofs) */ if ( (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino) || ((sb.st_mode & S_IFMT) != S_IFREG) || ((sb2.st_mode & S_IFMT) != S_IFREG) || (sb2.st_uid != ROOT) || (sb2.st_nlink != 1) ) { fsrprintf(_("Can't use %s: mode=0%o own=%d" " nlink=%d\n"), leftofffile, sb.st_mode, sb.st_uid, sb.st_nlink); close(fd); fd = NULLFD; } } else { close(fd); fd = NULLFD; } } else { fd = NULLFD; } if (fd != NULLFD) { if (read(fd, buf, SMBUFSZ) == -1) { fs = fsbase; fsrprintf(_("could not read %s, starting with %s\n"), leftofffile, *fs->dev); } else { /* Ensure the buffer we read is null terminated */ buf[SMBUFSZ-1] = '\0'; for (fs = fsbase; fs < fsend; fs++) { fsname = fs->dev; if ((strncmp(buf,fsname,strlen(fsname)) == 0) && buf[strlen(fsname)] == ' ') { found = 1; break; } } if (! found) fs = fsbase; ptr = strchr(buf, ' '); if (ptr) { startpass = atoi(++ptr); ptr = strchr(ptr, ' '); if (ptr) { startino = strtoull(++ptr, NULL, 10); /* * NOTE: The inode number read in from * the leftoff file is the last inode * to have been fsr'd. Since the v5 * xfrog_bulkstat function wants to be * passed the first inode that we want * to examine, increment the value that * we read in. The debug message below * prints the lastoff value. */ startino++; } } if (startpass < 0) startpass = 0; /* Init pass counts */ for (fsp = fsbase; fsp < fs; fsp++) { fsp->npass = startpass + 1; } for (fsp = fs; fsp <= fsend; fsp++) { fsp->npass = startpass; } } close(fd); } if (vflag) { fsrprintf(_("START: pass=%d ino=%llu %s %s\n"), fs->npass, (unsigned long long)startino - 1, fs->dev, fs->mnt); } signal(SIGABRT, aborter); signal(SIGHUP, aborter); signal(SIGINT, aborter); signal(SIGQUIT, aborter); signal(SIGTERM, aborter); /* reorg for 'howlong' -- checked in 'fsrfs' */ while (endtime > time(NULL)) { pid_t pid; if (npasses > 1 && !fs->npass) Mflag = 1; else Mflag = mdonly; pid = fork(); switch(pid) { case -1: fsrprintf(_("couldn't fork sub process:")); exit(1); break; case 0: error = fsrfs(fs->mnt, startino, TARGETRANGE); exit (error); break; default: wait(&error); if (WIFEXITED(error) && WEXITSTATUS(error) == 1) { /* child timed out & did fsrall_cleanup */ exit(0); } break; } startino = 0; /* reset after the first time through */ fs->npass++; fs++; if (fs == fsend) fs = fsbase; if (fs->npass == npasses) { fsrprintf(_("Completed all %d passes\n"), npasses); break; } } fsrall_cleanup(endtime <= time(NULL)); } /* * fsrall_cleanup -- close files, print next starting location, etc. */ static void fsrall_cleanup(int timeout) { int fd; int ret; char buf[SMBUFSZ]; unlink(leftofffile); if (timeout) { fsrprintf(_("%s startpass %d, endpass %d, time %d seconds\n"), progname, startpass, fs->npass, time(NULL) - endtime + howlong); /* record where we left off */ fd = open(leftofffile, O_WRONLY|O_CREAT|O_EXCL, 0644); if (fd == -1) { fsrprintf(_("open(%s) failed: %s\n"), leftofffile, strerror(errno)); } else { ret = sprintf(buf, "%s %d %llu\n", fs->dev, fs->npass, (unsigned long long)leftoffino); if (write(fd, buf, ret) < strlen(buf)) fsrprintf(_("write(%s) failed: %s\n"), leftofffile, strerror(errno)); close(fd); } } } /* * fsrfs -- reorganize a file system */ static int fsrfs(char *mntdir, xfs_ino_t startino, int targetrange) { struct xfs_fd fsxfd = XFS_FD_INIT_EMPTY; int fd; int count = 0; int ret; char fname[64]; char *tname; jdm_fshandle_t *fshandlep; struct xfs_bulkstat_req *breq; fsrprintf(_("%s start inode=%llu\n"), mntdir, (unsigned long long)startino); fshandlep = jdm_getfshandle( mntdir ); if ( ! fshandlep ) { fsrprintf(_("unable to get handle: %s: %s\n"), mntdir, strerror( errno )); return -1; } ret = -xfd_open(&fsxfd, mntdir, O_RDONLY); if (ret) { fsrprintf(_("unable to open XFS file: %s: %s\n"), mntdir, strerror(ret)); free(fshandlep); return -1; } memcpy(&fsgeom, &fsxfd.fsgeom, sizeof(fsgeom)); tmp_init(mntdir); ret = -xfrog_bulkstat_alloc_req(GRABSZ, startino, &breq); if (ret) { fsrprintf(_("Skipping %s: %s\n"), mntdir, strerror(ret)); xfd_close(&fsxfd); free(fshandlep); return -1; } while ((ret = -xfrog_bulkstat(&fsxfd, breq) == 0)) { struct xfs_bstat bs1; struct xfs_bulkstat *buf = breq->bulkstat; struct xfs_bulkstat *p; struct xfs_bulkstat *endp; uint32_t buflenout = breq->hdr.ocount; if (buflenout == 0) goto out0; /* Each loop through, defrag targetrange percent of the files */ count = (buflenout * targetrange) / 100; qsort((char *)buf, buflenout, sizeof(struct xfs_bulkstat), cmp); for (p = buf, endp = (buf + buflenout); p < endp ; p++) { /* Do some obvious checks now */ if (((p->bs_mode & S_IFMT) != S_IFREG) || (p->bs_extents < 2)) continue; ret = -xfrog_bulkstat_v5_to_v1(&fsxfd, &bs1, p); if (ret) { fsrprintf(_("bstat conversion error: %s\n"), strerror(ret)); continue; } fd = jdm_open(fshandlep, &bs1, O_RDWR | O_DIRECT); if (fd < 0) { /* This probably means the file was * removed while in progress of handling * it. Just quietly ignore this file. */ if (dflag) fsrprintf(_("could not open: " "inode %llu\n"), p->bs_ino); continue; } /* Don't know the pathname, so make up something */ sprintf(fname, "ino=%lld", (long long)p->bs_ino); /* Get a tmp file name */ tname = tmp_next(mntdir); ret = fsrfile_common(fname, tname, mntdir, fd, &bs1); leftoffino = p->bs_ino; close(fd); if (ret == 0) { if (--count <= 0) break; } } if (endtime && endtime < time(NULL)) { free(breq); tmp_close(mntdir); xfd_close(&fsxfd); fsrall_cleanup(1); exit(1); } } if (ret) fsrprintf(_("%s: bulkstat: %s\n"), progname, strerror(ret)); out0: free(breq); tmp_close(mntdir); xfd_close(&fsxfd); free(fshandlep); return 0; } /* * To compare bstat structs for qsort. */ int cmp(const void *s1, const void *s2) { return( ((struct xfs_bstat *)s2)->bs_extents - ((struct xfs_bstat *)s1)->bs_extents); } /* * reorganize by directory hierarchy. * Stay in dev (a restriction based on structure of this program -- either * call efs_{n,u}mount() around each file, something smarter or this) */ static void fsrdir(char *dirname) { fsrprintf(_("%s: Directory defragmentation not supported\n"), dirname); } /* * Sets up the defragmentation of a file based on the * filepath. It collects the bstat information, does * an open on the file and passes this all to fsrfile_common. */ static int fsrfile( char *fname, xfs_ino_t ino) { struct xfs_fd fsxfd = XFS_FD_INIT_EMPTY; struct xfs_bulkstat bulkstat; struct xfs_bstat statbuf; jdm_fshandle_t *fshandlep; int fd = -1; int error = -1; char *tname; fshandlep = jdm_getfshandle(getparent (fname) ); if (!fshandlep) { fsrprintf(_("unable to construct sys handle for %s: %s\n"), fname, strerror(errno)); goto out; } /* * Need to open something on the same filesystem as the * file. Open the parent. */ error = -xfd_open(&fsxfd, getparent(fname), O_RDONLY); if (error) { fsrprintf(_("unable to open sys handle for XFS file %s: %s\n"), fname, strerror(error)); goto out; } error = -xfrog_bulkstat_single(&fsxfd, ino, 0, &bulkstat); if (error) { fsrprintf(_("unable to get bstat on %s: %s\n"), fname, strerror(error)); goto out; } error = -xfrog_bulkstat_v5_to_v1(&fsxfd, &statbuf, &bulkstat); if (error) { fsrprintf(_("bstat conversion error on %s: %s\n"), fname, strerror(error)); goto out; } fd = jdm_open(fshandlep, &statbuf, O_RDWR|O_DIRECT); if (fd < 0) { fsrprintf(_("unable to open handle %s: %s\n"), fname, strerror(errno)); goto out; } /* Stash the fs geometry for general use. */ memcpy(&fsgeom, &fsxfd.fsgeom, sizeof(fsgeom)); tname = gettmpname(fname); if (tname) error = fsrfile_common(fname, tname, NULL, fd, &statbuf); out: xfd_close(&fsxfd); if (fd >= 0) close(fd); free(fshandlep); return error; } /* * This is the common defrag code for either a full fs * defragmentation or a single file. Check as much as * possible with the file, fork a process to setuid to the * target file owner's uid and defragment the file. * This is done so the new extents created in a tmp file are * reflected in the owners' quota without having to do any * special code in the kernel. When the existing extents * are removed, the quotas will be correct. It's ugly but * it saves us from doing some quota re-construction in * the extent swap. The price is that the defragmentation * will fail if the owner of the target file is already at * their quota limit. */ static int fsrfile_common( char *fname, char *tname, char *fsname, int fd, struct xfs_bstat *statp) { int error; struct statvfs vfss; struct fsxattr fsx; unsigned long bsize; if (vflag) fsrprintf("%s\n", fname); if (fsync(fd) < 0) { fsrprintf(_("sync failed: %s: %s\n"), fname, strerror(errno)); return -1; } if (statp->bs_size == 0) { if (vflag) fsrprintf(_("%s: zero size, ignoring\n"), fname); return(0); } /* Check if a mandatory lock is set on the file to try and * avoid blocking indefinitely on the reads later. Note that * someone could still set a mandatory lock after this check * but before all reads have completed to block fsr reads. * This change just closes the window a bit. */ if ( (statp->bs_mode & S_ISGID) && ( ! (statp->bs_mode&S_IXGRP) ) ) { struct flock fl; fl.l_type = F_RDLCK; fl.l_whence = SEEK_SET; fl.l_start = (off_t)0; fl.l_len = 0; if ((fcntl(fd, F_GETLK, &fl)) < 0 ) { if (vflag) fsrprintf(_("locking check failed: %s\n"), fname); return(-1); } if (fl.l_type != F_UNLCK) { /* Mandatory lock is set */ if (vflag) fsrprintf(_("mandatory lock: %s: ignoring\n"), fname); return(-1); } } /* * Check if there is room to copy the file. * * Note that xfs_bstat.bs_blksize returns the filesystem blocksize, * not the optimal I/O size as struct stat. */ if (statvfs(fsname ? fsname : fname, &vfss) < 0) { fsrprintf(_("unable to get fs stat on %s: %s\n"), fname, strerror(errno)); return -1; } bsize = vfss.f_frsize ? vfss.f_frsize : vfss.f_bsize; if (statp->bs_blksize * statp->bs_blocks > vfss.f_bfree * bsize - minimumfree) { fsrprintf(_("insufficient freespace for: %s: " "size=%lld: ignoring\n"), fname, statp->bs_blksize * statp->bs_blocks); return 1; } if ((ioctl(fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { fsrprintf(_("failed to get inode attrs: %s\n"), fname); return(-1); } if (fsx.fsx_xflags & (FS_XFLAG_IMMUTABLE|FS_XFLAG_APPEND)) { if (vflag) fsrprintf(_("%s: immutable/append, ignoring\n"), fname); return(0); } if (fsx.fsx_xflags & FS_XFLAG_NODEFRAG) { if (vflag) fsrprintf(_("%s: marked as don't defrag, ignoring\n"), fname); return(0); } if (fsx.fsx_xflags & FS_XFLAG_REALTIME) { if (xfs_getrt(fd, &vfss) < 0) { fsrprintf(_("cannot get realtime geometry for: %s\n"), fname); return(-1); } if (statp->bs_size > ((vfss.f_bfree * bsize) - minimumfree)) { fsrprintf(_("low on realtime free space: %s: " "ignoring file\n"), fname); return(-1); } } if ((RealUid != ROOT) && (RealUid != statp->bs_uid)) { fsrprintf(_("cannot open: %s: Permission denied\n"), fname); return -1; } /* * Previously the code forked here, & the child changed it's uid to * that of the file's owner and then called packfile(), to keep * quota counts correct. (defragged files could use fewer blocks). * * Instead, just fchown() the temp file to the uid,gid of the * file we're defragging, in packfile(). */ if ((error = packfile(fname, tname, fd, statp, &fsx))) return error; return -1; /* no error */ } /* * Attempt to set the attr fork up correctly. This is simple for attr1 * filesystems as they have a fixed inode fork offset. In that case * just create an attribute and that's all we need to do. * * For attr2 filesystems, see if we have the actual fork offset in * the bstat structure. If so, just create additional attributes on * the temporary inode until the offset matches. * * If it doesn't exist, we can only do best effort. Add an attribute at a time * to move the inode fork around, but take into account that the attribute * might be too small to move the fork every time we add one. This should * hopefully put the fork offset in the right place. It's not a big deal if we * don't get it right - the kernel will reject it when we try to swap extents. */ static int fsr_setup_attr_fork( int fd, int tfd, struct xfs_bstat *bstatp) { #ifdef HAVE_FSETXATTR struct xfs_fd txfd = XFS_FD_INIT(tfd); struct stat tstatbuf; int i; int diff = 0; int last_forkoff = 0; int no_change_cnt = 0; int ret; if (!(bstatp->bs_xflags & FS_XFLAG_HASATTR)) return 0; /* * use the old method if we have attr1 or the kernel does not yet * support passing the fork offset in the bulkstat data. */ if (!(fsgeom.flags & XFS_FSOP_GEOM_FLAGS_ATTR2) || bstatp->bs_forkoff == 0) { /* attr1 */ ret = fsetxattr(txfd.fd, "user.X", "X", 1, XATTR_CREATE); if (ret) { fsrprintf(_("could not set ATTR\n")); return -1; } goto out; } /* attr2 w/ fork offsets */ if (fstat(txfd.fd, &tstatbuf) < 0) { fsrprintf(_("unable to stat temp file: %s\n"), strerror(errno)); return -1; } i = 0; do { struct xfs_bulkstat tbstat; char name[64]; int ret; /* * bulkstat the temp inode to see what the forkoff is. Use * this to compare against the target and determine what we * need to do. */ ret = -xfrog_bulkstat_single(&txfd, tstatbuf.st_ino, 0, &tbstat); if (ret) { fsrprintf(_("unable to get bstat on temp file: %s\n"), strerror(ret)); return -1; } if (dflag) fsrprintf(_("orig forkoff %d, temp forkoff %d\n"), bstatp->bs_forkoff, tbstat.bs_forkoff); diff = tbstat.bs_forkoff - bstatp->bs_forkoff; /* if they are equal, we are done */ if (!diff) goto out; snprintf(name, sizeof(name), "user.%d", i); /* * If there is no attribute, then we need to create one to get * an attribute fork at the default location. */ if (!tbstat.bs_forkoff) { ASSERT(i == 0); ret = fsetxattr(txfd.fd, name, "XX", 2, XATTR_CREATE); if (ret) { fsrprintf(_("could not set ATTR\n")); return -1; } continue; } else if (i == 0) { /* * First pass, and temp file already has an inline * xattr, probably due to selinux. * * It's *possible* that the temp file attr area * is larger than the target file's: * * Target Temp * +-------+ 0 +-------+ 0 * | | | | * | | | Data | * | Data | | | * | | v-------v forkoff * | | | | * v-------v forkoff | Attr | local * | Attr | | | * +-------+ +-------+ */ /* * If target attr area is less than the temp's * (diff < 0) write a big attr to the temp file to knock * the attr out of local format. * (This should actually *increase* the temp file's * forkoffset when the attr moves out of the inode) */ if (diff < 0) { char val[2048]; memset(val, 'X', 2048); if (fsetxattr(txfd.fd, name, val, 2048, 0)) { fsrprintf(_("big ATTR set failed\n")); return -1; } /* Go back & see where we're at now */ continue; } } /* * make a progress check so we don't get stuck trying to extend * a large btree form attribute fork. */ if (last_forkoff == tbstat.bs_forkoff) { if (no_change_cnt++ > 10) break; } else /* progress! */ no_change_cnt = 0; last_forkoff = tbstat.bs_forkoff; /* work out which way to grow the fork */ if (abs(diff) > fsgeom.inodesize - sizeof(struct xfs_dinode)) { fsrprintf(_("forkoff diff %d too large!\n"), diff); return -1; } /* * if the temp inode fork offset is still smaller then we have * to grow the data fork */ if (diff < 0) { /* * create some temporary extents in the inode to move * the fork in the direction we need. This can be done * by preallocating some single block extents at * non-contiguous offsets. */ /* XXX: unimplemented! */ if (dflag) printf(_("data fork growth unimplemented\n")); goto out; } /* we need to grow the attr fork, so create another attr */ ret = fsetxattr(txfd.fd, name, "XX", 2, XATTR_CREATE); if (ret) { fsrprintf(_("could not set ATTR\n")); return -1; } } while (++i < 100); /* don't go forever */ out: if (dflag) fsrprintf(_("set temp attr\n")); /* We failed to resolve the fork difference */ if (dflag && diff) fsrprintf(_("failed to match fork offset\n"));; #endif /* HAVE_FSETXATTR */ return 0; } /* * Do the defragmentation of a single file. * We already are pretty sure we can and want to * defragment the file. Create the tmp file, copy * the data (maintaining holes) and call the kernel * extent swap routine. * * Return values: * -1: Some error was encountered * 0: Successfully defragmented the file * 1: No change / No Error */ static int packfile(char *fname, char *tname, int fd, struct xfs_bstat *statp, struct fsxattr *fsxp) { int tfd = -1; int srval; int retval = -1; /* Failure is the default */ int nextents, extent, cur_nextents, new_nextents; unsigned blksz_dio; unsigned dio_min; struct dioattr dio; static xfs_swapext_t sx; struct xfs_flock64 space; off64_t cnt, pos; void *fbuf = NULL; int ct, wc, wc_b4; char ffname[SMBUFSZ]; int ffd = -1; /* * Work out the extent map - nextents will be set to the * minimum number of extents needed for the file (taking * into account holes), cur_nextents is the current number * of extents. */ nextents = read_fd_bmap(fd, statp, &cur_nextents); if (cur_nextents == 1 || cur_nextents <= nextents) { if (vflag) fsrprintf(_("%s already fully defragmented.\n"), fname); retval = 1; /* indicates no change/no error */ goto out; } if (dflag) fsrprintf(_("%s extents=%d can_save=%d tmp=%s\n"), fname, cur_nextents, (cur_nextents - nextents), tname); if ((tfd = open(tname, openopts, 0666)) < 0) { if (vflag) fsrprintf(_("could not open tmp file: %s: %s\n"), tname, strerror(errno)); goto out; } unlink(tname); /* Setup extended attributes */ if (fsr_setup_attr_fork(fd, tfd, statp) != 0) { fsrprintf(_("failed to set ATTR fork on tmp: %s:\n"), tname); goto out; } /* Setup extended inode flags, project identifier, etc */ if (fsxp->fsx_xflags || fsxp->fsx_projid) { if (ioctl(tfd, FS_IOC_FSSETXATTR, fsxp) < 0) { fsrprintf(_("could not set inode attrs on tmp: %s\n"), tname); goto out; } } if ((ioctl(tfd, XFS_IOC_DIOINFO, &dio)) < 0 ) { fsrprintf(_("could not get DirectIO info on tmp: %s\n"), tname); goto out; } dio_min = dio.d_miniosz; if (statp->bs_size <= dio_min) { blksz_dio = dio_min; } else { blksz_dio = min(dio.d_maxiosz, BUFFER_MAX - pagesize); if (argv_blksz_dio != 0) blksz_dio = min(argv_blksz_dio, blksz_dio); blksz_dio = (min(statp->bs_size, blksz_dio) / dio_min) * dio_min; } if (dflag) { fsrprintf(_("DEBUG: " "fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n"), statp->bs_size, blksz_dio, dio.d_miniosz, dio.d_maxiosz, pagesize); } if (!(fbuf = (char *)memalign(dio.d_mem, blksz_dio))) { fsrprintf(_("could not allocate buf: %s\n"), tname); goto out; } if (nfrags) { /* Create new tmp file in same AG as first */ sprintf(ffname, "%s.frag", tname); /* Open the new file for sync writes */ if ((ffd = open(ffname, openopts, 0666)) < 0) { fsrprintf(_("could not open fragfile: %s : %s\n"), ffname, strerror(errno)); goto out; } unlink(ffname); } /* Loop through block map allocating new extents */ for (extent = 0; extent < nextents; extent++) { pos = outmap[extent].bmv_offset; if (outmap[extent].bmv_block == -1) { space.l_whence = SEEK_SET; space.l_start = pos; space.l_len = outmap[extent].bmv_length; if (ioctl(tfd, XFS_IOC_UNRESVSP64, &space) < 0) { fsrprintf(_("could not trunc tmp %s\n"), tname); } if (lseek(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) { fsrprintf(_("could not lseek in tmpfile: %s : %s\n"), tname, strerror(errno)); goto out; } continue; } else if (outmap[extent].bmv_length == 0) { /* to catch holes at the beginning of the file */ continue; } if (! nfrags) { space.l_whence = SEEK_CUR; space.l_start = 0; space.l_len = outmap[extent].bmv_length; if (ioctl(tfd, XFS_IOC_RESVSP64, &space) < 0) { fsrprintf(_("could not pre-allocate tmp space:" " %s\n"), tname); goto out; } if (lseek(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) { fsrprintf(_("could not lseek in tmpfile: %s : %s\n"), tname, strerror(errno)); goto out; } } } /* end of space allocation loop */ if (lseek(tfd, 0, SEEK_SET)) { fsrprintf(_("Couldn't rewind on temporary file\n")); goto out; } /* Check if the temporary file has fewer extents */ new_nextents = getnextents(tfd); if (dflag) fsrprintf(_("Temporary file has %d extents (%d in original)\n"), new_nextents, cur_nextents); if (cur_nextents <= new_nextents) { if (vflag) fsrprintf(_("No improvement will be made (skipping): %s\n"), fname); retval = 1; /* no change/no error */ goto out; } /* Loop through block map copying the file. */ for (extent = 0; extent < nextents; extent++) { pos = outmap[extent].bmv_offset; if (outmap[extent].bmv_block == -1) { if (lseek(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) { fsrprintf(_("could not lseek in tmpfile: %s : %s\n"), tname, strerror(errno)); goto out; } if (lseek(fd, outmap[extent].bmv_length, SEEK_CUR) < 0) { fsrprintf(_("could not lseek in file: %s : %s\n"), fname, strerror(errno)); goto out; } continue; } else if (outmap[extent].bmv_length == 0) { /* to catch holes at the beginning of the file */ continue; } for (cnt = outmap[extent].bmv_length; cnt > 0; cnt -= ct, pos += ct) { if (nfrags && --nfrags) { ct = min(cnt, dio_min); } else if (cnt % dio_min == 0) { ct = min(cnt, blksz_dio); } else { ct = min(cnt + dio_min - (cnt % dio_min), blksz_dio); } ct = read(fd, fbuf, ct); if (ct == 0) { /* EOF, stop trying to read */ extent = nextents; break; } /* Ensure we do direct I/O to correct block * boundaries. */ if (ct % dio_min != 0) { wc = ct + dio_min - (ct % dio_min); } else { wc = ct; } wc_b4 = wc; if (ct < 0 || ((wc = write(tfd, fbuf, wc)) != wc_b4)) { if (ct < 0) fsrprintf(_("bad read of %d bytes " "from %s: %s\n"), wc_b4, fname, strerror(errno)); else if (wc < 0) fsrprintf(_("bad write of %d bytes " "to %s: %s\n"), wc_b4, tname, strerror(errno)); else { /* * Might be out of space * * Try to finish write */ int resid = ct-wc; if ((wc = write(tfd, ((char *)fbuf)+wc, resid)) == resid) { /* worked on second attempt? */ continue; } else if (wc < 0) { fsrprintf(_("bad write2 of %d " "bytes to %s: %s\n"), resid, tname, strerror(errno)); } else { fsrprintf(_("bad copy to %s\n"), tname); } } goto out; } if (nfrags) { /* Do a matching write to the tmp file */ wc_b4 = wc; if (((wc = write(ffd, fbuf, wc)) != wc_b4)) { fsrprintf(_("bad write of %d bytes " "to %s: %s\n"), wc_b4, ffname, strerror(errno)); } } } } if (ftruncate(tfd, statp->bs_size) < 0) { fsrprintf(_("could not truncate tmpfile: %s : %s\n"), fname, strerror(errno)); goto out; } if (fsync(tfd) < 0) { fsrprintf(_("could not fsync tmpfile: %s : %s\n"), fname, strerror(errno)); goto out; } sx.sx_stat = *statp; /* struct copy */ sx.sx_version = XFS_SX_VERSION; sx.sx_fdtarget = fd; sx.sx_fdtmp = tfd; sx.sx_offset = 0; sx.sx_length = statp->bs_size; /* switch to the owner's id, to keep quota in line */ if (fchown(tfd, statp->bs_uid, statp->bs_gid) < 0) { if (vflag) fsrprintf(_("failed to fchown tmpfile %s: %s\n"), tname, strerror(errno)); goto out; } /* Swap the extents */ srval = xfs_swapext(fd, &sx); if (srval < 0) { if (errno == ENOTSUP) { if (vflag || dflag) fsrprintf(_("%s: file type not supported\n"), fname); } else if (errno == EFAULT) { /* The file has changed since we started the copy */ if (vflag || dflag) fsrprintf(_("%s: file modified defrag aborted\n"), fname); } else if (errno == EBUSY) { /* Timestamp has changed or mmap'ed file */ if (vflag || dflag) fsrprintf(_("%s: file busy\n"), fname); } else { fsrprintf(_("XFS_IOC_SWAPEXT failed: %s: %s\n"), fname, strerror(errno)); } goto out; } /* Report progress */ if (vflag) fsrprintf(_("extents before:%d after:%d %s %s\n"), cur_nextents, new_nextents, (new_nextents <= nextents ? "DONE" : " " ), fname); retval = 0; out: free(fbuf); if (tfd != -1) close(tfd); if (ffd != -1) close(ffd); return retval; } char * gettmpname(char *fname) { static char buf[PATH_MAX+1]; char sbuf[SMBUFSZ]; char *ptr; sprintf(sbuf, "/.fsr%d", getpid()); strncpy(buf, fname, PATH_MAX); buf[PATH_MAX] = '\0'; ptr = strrchr(buf, '/'); if (ptr) { *ptr = '\0'; } else { strcpy(buf, "."); } if ((strlen(buf) + strlen (sbuf)) > PATH_MAX) { fsrprintf(_("tmp file name too long: %s\n"), fname); return(NULL); } strcat(buf, sbuf); return(buf); } char * getparent(char *fname) { static char buf[PATH_MAX+1]; char *ptr; strncpy(buf, fname, PATH_MAX); buf[PATH_MAX] = '\0'; ptr = strrchr(buf, '/'); if (ptr) { if (ptr == &buf[0]) ++ptr; *ptr = '\0'; } else { strcpy(buf, "."); } return(buf); } /* * Read in block map of the input file, coalesce contiguous * extents into a single range, keep all holes. Convert from 512 byte * blocks to bytes. * * This code was borrowed from mv.c with some minor mods. */ #define MAPSIZE 128 #define OUTMAP_SIZE_INCREMENT MAPSIZE int read_fd_bmap(int fd, struct xfs_bstat *sin, int *cur_nextents) { int i, cnt; struct getbmap map[MAPSIZE]; #define BUMP_CNT \ if (++cnt >= outmap_size) { \ outmap_size += OUTMAP_SIZE_INCREMENT; \ outmap = (struct getbmap *)realloc(outmap, \ outmap_size*sizeof(*outmap)); \ if (outmap == NULL) { \ fsrprintf(_("realloc failed: %s\n"), \ strerror(errno)); \ exit(1); \ } \ } /* Initialize the outmap array. It always grows - never shrinks. * Left-over memory allocation is saved for the next files. */ if (outmap_size == 0) { outmap_size = OUTMAP_SIZE_INCREMENT; /* Initial size */ outmap = (struct getbmap *)malloc(outmap_size*sizeof(*outmap)); if (!outmap) { fsrprintf(_("malloc failed: %s\n"), strerror(errno)); exit(1); } } outmap[0].bmv_block = 0; outmap[0].bmv_offset = 0; outmap[0].bmv_length = sin->bs_size; /* * If a non regular file is involved then forget holes */ if (!S_ISREG(sin->bs_mode)) return(1); outmap[0].bmv_length = 0; map[0].bmv_offset = 0; map[0].bmv_block = 0; map[0].bmv_entries = 0; map[0].bmv_count = MAPSIZE; map[0].bmv_length = -1; cnt = 0; *cur_nextents = 0; do { if (ioctl(fd, XFS_IOC_GETBMAP, map) < 0) { fsrprintf(_("failed reading extents: inode %llu"), (unsigned long long)sin->bs_ino); exit(1); } /* Concatenate extents together and replicate holes into * the output map. */ *cur_nextents += map[0].bmv_entries; for (i = 0; i < map[0].bmv_entries; i++) { if (map[i + 1].bmv_block == -1) { BUMP_CNT; outmap[cnt] = map[i+1]; } else if (outmap[cnt].bmv_block == -1) { BUMP_CNT; outmap[cnt] = map[i+1]; } else { outmap[cnt].bmv_length += map[i + 1].bmv_length; } } } while (map[0].bmv_entries == (MAPSIZE-1)); for (i = 0; i <= cnt; i++) { outmap[i].bmv_offset = BBTOB(outmap[i].bmv_offset); outmap[i].bmv_length = BBTOB(outmap[i].bmv_length); } outmap[cnt].bmv_length = sin->bs_size - outmap[cnt].bmv_offset; return(cnt+1); } /* * Read the block map and return the number of extents. */ static int getnextents(int fd) { int nextents; struct getbmap map[MAPSIZE]; map[0].bmv_offset = 0; map[0].bmv_block = 0; map[0].bmv_entries = 0; map[0].bmv_count = MAPSIZE; map[0].bmv_length = -1; nextents = 0; do { if (ioctl(fd,XFS_IOC_GETBMAP, map) < 0) { fsrprintf(_("failed reading extents")); exit(1); } nextents += map[0].bmv_entries; } while (map[0].bmv_entries == (MAPSIZE-1)); return(nextents); } /* * Get xfs realtime space information */ int xfs_getrt(int fd, struct statvfs *sfbp) { unsigned long bsize; unsigned long factor; xfs_fsop_counts_t cnt; if (!fsgeom.rtblocks) return -1; if (xfs_fscounts(fd, &cnt) < 0) { close(fd); return -1; } bsize = (sfbp->f_frsize ? sfbp->f_frsize : sfbp->f_bsize); factor = fsgeom.blocksize / bsize; /* currently this is == 1 */ sfbp->f_bfree = (cnt.freertx * fsgeom.rtextsize) * factor; return 0; } int fsrprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (gflag) { static int didopenlog; if (!didopenlog) { openlog("fsr", LOG_PID, LOG_USER); didopenlog = 1; } vsyslog(LOG_INFO, fmt, ap); } else vprintf(fmt, ap); va_end(ap); return 0; } /* * Initialize a directory for tmp file use. This is used * by the full filesystem defragmentation when we're walking * the inodes and do not know the path for the individual * files. Multiple directories are used to spread out the * tmp data around to different ag's (since file data is * usually allocated to the same ag as the directory and * directories allocated round robin from the same * parent directory). */ static void tmp_init(char *mnt) { int i; static char buf[SMBUFSZ]; mode_t mask; tmp_agi = 0; sprintf(buf, "%s/.fsr", mnt); mask = umask(0); if (mkdir(buf, 0700) < 0) { if (errno == EEXIST) { if (dflag) fsrprintf(_("tmpdir already exists: %s\n"), buf); } else { fsrprintf(_("could not create tmpdir: %s: %s\n"), buf, strerror(errno)); exit(-1); } } for (i=0; i < fsgeom.agcount; i++) { sprintf(buf, "%s/.fsr/ag%d", mnt, i); if (mkdir(buf, 0700) < 0) { if (errno == EEXIST) { if (dflag) fsrprintf( _("tmpdir already exists: %s\n"), buf); } else { fsrprintf(_("cannot create tmpdir: %s: %s\n"), buf, strerror(errno)); exit(-1); } } } (void)umask(mask); return; } static char * tmp_next(char *mnt) { static char buf[SMBUFSZ]; sprintf(buf, "%s/.fsr/ag%d/tmp%d", ( (strcmp(mnt, "/") == 0) ? "" : mnt), tmp_agi, getpid()); if (++tmp_agi == fsgeom.agcount) tmp_agi = 0; return(buf); } static void tmp_close(char *mnt) { static char buf[SMBUFSZ]; int i; /* No data is ever actually written so we can just do rmdir's */ for (i=0; i < fsgeom.agcount; i++) { sprintf(buf, "%s/.fsr/ag%d", mnt, i); if (rmdir(buf) < 0) { if (errno != ENOENT) { fsrprintf( _("could not remove tmpdir: %s: %s\n"), buf, strerror(errno)); } } } sprintf(buf, "%s/.fsr", mnt); if (rmdir(buf) < 0) { if (errno != ENOENT) { fsrprintf(_("could not remove tmpdir: %s: %s\n"), buf, strerror(errno)); } } } xfsprogs-5.3.0/growfs/Makefile0000644000175000017500000000131113435336036016215 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_growfs CFILES = xfs_growfs.c LLDLIBS = $(LIBXFS) $(LIBXCMD) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) ifeq ($(ENABLE_READLINE),yes) LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP) endif ifeq ($(ENABLE_EDITLINE),yes) LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP) endif LTDEPENDENCIES = $(LIBXFS) $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static-libtool-libs default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/growfs/xfs_growfs.c0000644000175000017500000002354413570057155017126 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" static void usage(void) { fprintf(stderr, _( "Usage: %s [options] mountpoint\n\n\ Options:\n\ -d grow data/metadata section\n\ -l grow log section\n\ -r grow realtime section\n\ -n don't change anything, just show geometry\n\ -i convert log from external to internal format\n\ -t alternate location for mount table (/etc/mtab)\n\ -x convert log from internal to external format\n\ -D size grow data/metadata section to size blks\n\ -L size grow/shrink log section to size blks\n\ -R size grow realtime section to size blks\n\ -e size set realtime extent size to size blks\n\ -m imaxpct set inode max percent to imaxpct\n\ -V print version information\n"), progname); exit(2); } int main(int argc, char **argv) { int aflag; /* fake flag, do all pieces */ int c; /* current option character */ long long ddsize; /* device size in 512-byte blocks */ int dflag; /* -d flag */ long long dlsize; /* device size in 512-byte blocks */ long long drsize; /* device size in 512-byte blocks */ long long dsize; /* new data size in fs blocks */ int error; /* we have hit an error */ long esize; /* new rt extent size */ int ffd; /* mount point file descriptor */ struct xfs_fsop_geom geo; /* current fs geometry */ int iflag; /* -i flag */ int isint; /* log is currently internal */ int lflag; /* -l flag */ long long lsize; /* new log size in fs blocks */ int maxpct; /* -m flag value */ int mflag; /* -m flag */ int nflag; /* -n flag */ struct xfs_fsop_geom ngeo; /* new fs geometry */ int rflag; /* -r flag */ long long rsize; /* new rt size in fs blocks */ int xflag; /* -x flag */ char *fname; /* mount point name */ char *datadev; /* data device name */ char *logdev; /* log device name */ char *rtdev; /* RT device name */ fs_path_t *fs; /* mount point information */ libxfs_init_t xi; /* libxfs structure */ char rpath[PATH_MAX]; int ret; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); maxpct = esize = 0; dsize = lsize = rsize = 0LL; aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0; while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) { switch (c) { case 'D': dsize = strtoll(optarg, NULL, 10); /* fall through */ case 'd': dflag = 1; break; case 'e': esize = atol(optarg); rflag = 1; break; case 'i': lflag = iflag = 1; break; case 'L': lsize = strtoll(optarg, NULL, 10); /* fall through */ case 'l': lflag = 1; break; case 'm': mflag = 1; maxpct = atoi(optarg); break; case 'n': nflag = 1; break; case 'p': progname = optarg; break; case 'R': rsize = strtoll(optarg, NULL, 10); /* fall through */ case 'r': rflag = 1; break; case 't': mtab_file = optarg; break; case 'x': lflag = xflag = 1; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); case '?': default: usage(); } } if (argc - optind != 1) usage(); if (iflag && xflag) usage(); if (dflag + lflag + rflag + mflag == 0) aflag = 1; fs_table_initialise(0, NULL, 0, NULL); if (!realpath(argv[optind], rpath)) { fprintf(stderr, _("%s: path resolution failed for %s: %s\n"), progname, argv[optind], strerror(errno)); return 1; } fs = fs_table_lookup_mount(rpath); if (!fs) fs = fs_table_lookup_blkdev(rpath); if (!fs) { fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"), progname, argv[optind]); return 1; } fname = fs->fs_dir; datadev = fs->fs_name; logdev = fs->fs_log; rtdev = fs->fs_rt; ffd = open(fname, O_RDONLY); if (ffd < 0) { perror(fname); return 1; } if (!platform_test_xfs_fd(ffd)) { fprintf(stderr, _("%s: specified file " "[\"%s\"] is not on an XFS filesystem\n"), progname, fname); exit(1); } /* get the current filesystem size & geometry */ ret = -xfrog_geometry(ffd, &geo); if (ret) { fprintf(stderr, _("%s: cannot determine geometry of filesystem mounted at %s: %s\n"), progname, fname, strerror(ret)); exit(1); } isint = geo.logstart > 0; /* * Need root access from here on (using raw devices)... */ memset(&xi, 0, sizeof(xi)); xi.dname = datadev; xi.logname = logdev; xi.rtname = rtdev; xi.isreadonly = LIBXFS_ISREADONLY; if (!libxfs_init(&xi)) usage(); /* check we got the info for all the sections we are trying to modify */ if (!xi.ddev) { fprintf(stderr, _("%s: failed to access data device for %s\n"), progname, fname); exit(1); } if (lflag && !isint && !xi.logdev) { fprintf(stderr, _("%s: failed to access external log for %s\n"), progname, fname); exit(1); } if (rflag && !xi.rtdev) { fprintf(stderr, _("%s: failed to access realtime device for %s\n"), progname, fname); exit(1); } xfs_report_geom(&geo, datadev, logdev, rtdev); ddsize = xi.dsize; dlsize = ( xi.logBBsize? xi.logBBsize : geo.logblocks * (geo.blocksize / BBSIZE) ); drsize = xi.rtsize; /* * Ok, Linux only has a 1024-byte resolution on device _size_, * and the sizes below are in basic 512-byte blocks, * so if we have (size % 2), on any partition, we can't get * to the last 512 bytes. Just chop it down by a block. */ ddsize -= (ddsize % 2); dlsize -= (dlsize % 2); drsize -= (drsize % 2); error = 0; if (dflag | mflag | aflag) { xfs_growfs_data_t in; if (!mflag) maxpct = geo.imaxpct; if (!dflag && !aflag) /* Only mflag, no data size change */ dsize = geo.datablocks; else if (!dsize) dsize = ddsize / (geo.blocksize / BBSIZE); else if (dsize > ddsize / (geo.blocksize / BBSIZE)) { fprintf(stderr, _( "data size %lld too large, maximum is %lld\n"), (long long)dsize, (long long)(ddsize/(geo.blocksize/BBSIZE))); error = 1; } if (!error && dsize < geo.datablocks) { fprintf(stderr, _("data size %lld too small," " old size is %lld\n"), (long long)dsize, (long long)geo.datablocks); error = 1; } else if (!error && dsize == geo.datablocks && maxpct == geo.imaxpct) { if (dflag) fprintf(stderr, _( "data size unchanged, skipping\n")); if (mflag) fprintf(stderr, _( "inode max pct unchanged, skipping\n")); } else if (!error && !nflag) { in.newblocks = (__u64)dsize; in.imaxpct = (__u32)maxpct; if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) { if (errno == EWOULDBLOCK) fprintf(stderr, _( "%s: growfs operation in progress already\n"), progname); else fprintf(stderr, _( "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"), progname, strerror(errno)); error = 1; } } } if (!error && (rflag | aflag)) { xfs_growfs_rt_t in; if (!esize) esize = (__u32)geo.rtextsize; if (!rsize) rsize = drsize / (geo.blocksize / BBSIZE); else if (rsize > drsize / (geo.blocksize / BBSIZE)) { fprintf(stderr, _( "realtime size %lld too large, maximum is %lld\n"), rsize, drsize / (geo.blocksize / BBSIZE)); error = 1; } if (!error && rsize < geo.rtblocks) { fprintf(stderr, _( "realtime size %lld too small, old size is %lld\n"), (long long)rsize, (long long)geo.rtblocks); error = 1; } else if (!error && rsize == geo.rtblocks) { if (rflag) fprintf(stderr, _( "realtime size unchanged, skipping\n")); } else if (!error && !nflag) { in.newblocks = (__u64)rsize; in.extsize = (__u32)esize; if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) { if (errno == EWOULDBLOCK) fprintf(stderr, _( "%s: growfs operation in progress already\n"), progname); else if (errno == ENOSYS) fprintf(stderr, _( "%s: realtime growth not implemented\n"), progname); else fprintf(stderr, _( "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"), progname, strerror(errno)); error = 1; } } } if (!error && (lflag | aflag)) { xfs_growfs_log_t in; if (!lsize) lsize = dlsize / (geo.blocksize / BBSIZE); if (iflag) in.isint = 1; else if (xflag) in.isint = 0; else in.isint = xi.logBBsize == 0; if (lsize == geo.logblocks && (in.isint == isint)) { if (lflag) fprintf(stderr, _("log size unchanged, skipping\n")); } else if (!nflag) { in.newblocks = (__u32)lsize; if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) { if (errno == EWOULDBLOCK) fprintf(stderr, _("%s: growfs operation in progress already\n"), progname); else if (errno == ENOSYS) fprintf(stderr, _("%s: log growth not supported yet\n"), progname); else fprintf(stderr, _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"), progname, strerror(errno)); error = 1; } } } ret = -xfrog_geometry(ffd, &ngeo); if (ret) { fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"), progname, strerror(ret)); exit(1); } if (geo.datablocks != ngeo.datablocks) printf(_("data blocks changed from %lld to %lld\n"), (long long)geo.datablocks, (long long)ngeo.datablocks); if (geo.imaxpct != ngeo.imaxpct) printf(_("inode max percent changed from %d to %d\n"), geo.imaxpct, ngeo.imaxpct); if (geo.logblocks != ngeo.logblocks) printf(_("log blocks changed from %d to %d\n"), geo.logblocks, ngeo.logblocks); if ((geo.logstart == 0) != (ngeo.logstart == 0)) printf(_("log changed from %s to %s\n"), geo.logstart ? _("internal") : _("external"), ngeo.logstart ? _("internal") : _("external")); if (geo.rtblocks != ngeo.rtblocks) printf(_("realtime blocks changed from %lld to %lld\n"), (long long)geo.rtblocks, (long long)ngeo.rtblocks); if (geo.rtextsize != ngeo.rtextsize) printf(_("realtime extent size changed from %d to %d\n"), geo.rtextsize, ngeo.rtextsize); exit(error); } xfsprogs-5.3.0/include/Makefile0000644000175000017500000000204713570057155016342 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2006 Silicon Graphics, Inc. # All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LIBHFILES = libxfs.h \ libxlog.h \ libxcmd.h \ atomic.h \ bitops.h \ cache.h \ hlist.h \ kmem.h \ list.h \ parent.h \ xfs_btree_trace.h \ xfs_inode.h \ xfs_log_recover.h \ xfs_metadump.h \ xfs_mount.h \ xfs_quota_defs.h \ xfs_sb.h \ xfs_shared.h \ xfs_trace.h \ xfs_trans.h \ command.h \ input.h \ platform_defs.h HFILES = handle.h \ jdm.h \ linux.h \ xfs.h \ xqm.h \ xfs_arch.h LSRCFILES = platform_defs.h.in builddefs.in buildmacros buildrules install-sh LSRCFILES += $(DKHFILES) $(LIBHFILES) LDIRT = disk LDIRDIRT = xfs default: disk disk: @echo " [LN] $@" $(Q)$(LN_S) . $@ include $(BUILDRULES) # set up include/xfs header directory install-headers: $(addsuffix -hdrs, $(DKHFILES) $(HFILES)) %-hdrs: $(Q)$(LN_S) -f $(CURDIR)/$* xfs/$* install: default $(INSTALL) -m 755 -d $(PKG_INC_DIR) install-dev: install $(INSTALL) -m 644 $(HFILES) $(PKG_INC_DIR) xfsprogs-5.3.0/include/atomic.h0000644000175000017500000000117613435336036016327 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2011 RedHat, Inc. * All Rights Reserved. */ #ifndef __ATOMIC_H__ #define __ATOMIC_H__ /* * Warning: These are not really atomic at all. They are wrappers around the * kernel atomic variable interface. If we do need these variables to be atomic * (due to multithreading of the code that uses them) we need to add some * pthreads magic here. */ typedef int32_t atomic_t; typedef int64_t atomic64_t; #define atomic_inc_return(x) (++(*(x))) #define atomic_dec_return(x) (--(*(x))) #define atomic64_read(x) *(x) #define atomic64_set(x, v) (*(x) = v) #endif /* __ATOMIC_H__ */ xfsprogs-5.3.0/include/bitops.h0000644000175000017500000000376513435336036016361 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #ifndef __BITOPS_H__ #define __BITOPS_H__ /* * fls: find last bit set. */ #ifndef HAVE_FLS static inline int fls(int x) { int r = 32; if (!x) return 0; if (!(x & 0xffff0000u)) { x = (x & 0xffffu) << 16; r -= 16; } if (!(x & 0xff000000u)) { x = (x & 0xffffffu) << 8; r -= 8; } if (!(x & 0xf0000000u)) { x = (x & 0xfffffffu) << 4; r -= 4; } if (!(x & 0xc0000000u)) { x = (x & 0x3fffffffu) << 2; r -= 2; } if (!(x & 0x80000000u)) { r -= 1; } return r; } #endif /* HAVE_FLS */ static inline int fls64(__u64 x) { __u32 h = x >> 32; if (h) return fls(h) + 32; return fls(x); } static inline unsigned fls_long(unsigned long l) { if (sizeof(l) == 4) return fls(l); return fls64(l); } /* * ffz: find first zero bit. * Result is undefined if no zero bit exists. */ #define ffz(x) ffs(~(x)) /* * XFS bit manipulation routines. Repeated here so that some programs * don't have to link in all of libxfs just to have bit manipulation. */ /* * masks with n high/low bits set, 64-bit values */ static inline uint64_t mask64hi(int n) { return (uint64_t)-1 << (64 - (n)); } static inline uint32_t mask32lo(int n) { return ((uint32_t)1 << (n)) - 1; } static inline uint64_t mask64lo(int n) { return ((uint64_t)1 << (n)) - 1; } /* Get high bit set out of 32-bit argument, -1 if none set */ static inline int highbit32(uint32_t v) { return fls(v) - 1; } /* Get high bit set out of 64-bit argument, -1 if none set */ static inline int highbit64(uint64_t v) { return fls64(v) - 1; } /* Get low bit set out of 32-bit argument, -1 if none set */ static inline int lowbit32(uint32_t v) { return ffs(v) - 1; } /* Get low bit set out of 64-bit argument, -1 if none set */ static inline int lowbit64(uint64_t v) { uint32_t w = (uint32_t)v; int n = 0; if (w) { /* lower bits */ n = ffs(w); } else { /* upper bits */ w = (uint32_t)(v >> 32); if (w) { n = ffs(w); if (n) n += 32; } } return n - 1; } #endif xfsprogs-5.3.0/include/builddefs.in0000644000175000017500000001112213570057155017165 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2004-2006 Silicon Graphics, Inc. # All Rights Reserved. # # @configure_input@ # ifndef _BUILDDEFS_INCLUDED_ _BUILDDEFS_INCLUDED_ = 1 DEBUG = @debug_build@ OPTIMIZER = @opt_build@ MALLOCLIB = @malloc_lib@ LOADERFLAGS = @LDFLAGS@ LTLDFLAGS = @LDFLAGS@ CFLAGS = @CFLAGS@ -D_FILE_OFFSET_BITS=64 BUILD_CFLAGS = @BUILD_CFLAGS@ -D_FILE_OFFSET_BITS=64 LIBRT = @librt@ LIBUUID = @libuuid@ LIBPTHREAD = @libpthread@ LIBTERMCAP = @libtermcap@ LIBEDITLINE = @libeditline@ LIBREADLINE = @libreadline@ LIBBLKID = @libblkid@ LIBDEVMAPPER = @libdevmapper@ LIBXFS = $(TOPDIR)/libxfs/libxfs.la LIBFROG = $(TOPDIR)/libfrog/libfrog.la LIBXCMD = $(TOPDIR)/libxcmd/libxcmd.la LIBXLOG = $(TOPDIR)/libxlog/libxlog.la LIBHANDLE = $(TOPDIR)/libhandle/libhandle.la PKG_NAME = @pkg_name@ PKG_USER = @pkg_user@ PKG_GROUP = @pkg_group@ PKG_RELEASE = @pkg_release@ PKG_VERSION = @pkg_version@ PKG_DISTRIBUTION= @pkg_distribution@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ top_builddir = @top_builddir@ PKG_SBIN_DIR = @sbindir@ PKG_ROOT_SBIN_DIR = @root_sbindir@ PKG_ROOT_LIB_DIR= @root_libdir@@libdirsuffix@ PKG_LIB_DIR = @libdir@@libdirsuffix@ PKG_INC_DIR = @includedir@/xfs DK_INC_DIR = @includedir@/disk PKG_MAN_DIR = @mandir@ PKG_DOC_DIR = @datadir@/doc/@pkg_name@ PKG_LOCALE_DIR = @datadir@/locale CC = @cc@ BUILD_CC = @BUILD_CC@ AWK = @awk@ SED = @sed@ TAR = @tar@ ZIP = @zip@ MAKE = @make@ ECHO = @echo@ SORT = @sort@ LN_S = @LN_S@ SHELL = @SHELL@ LIBTOOL = @LIBTOOL@ MAKEDEPEND = @makedepend@ MSGFMT = @msgfmt@ MSGMERGE = @msgmerge@ XGETTEXT = @xgettext@ LOCALIZED_FILES = @LOCALIZED_FILES@ RPM = @rpm@ RPMBUILD = @rpmbuild@ RPM_VERSION = @rpm_version@ ENABLE_SHARED = @enable_shared@ ENABLE_GETTEXT = @enable_gettext@ ENABLE_EDITLINE = @enable_editline@ ENABLE_READLINE = @enable_readline@ ENABLE_BLKID = @enable_blkid@ ENABLE_SCRUB = @enable_scrub@ HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ HAVE_FADVISE = @have_fadvise@ HAVE_MADVISE = @have_madvise@ HAVE_MINCORE = @have_mincore@ HAVE_SENDFILE = @have_sendfile@ HAVE_GETMNTENT = @have_getmntent@ HAVE_FALLOCATE = @have_fallocate@ HAVE_FIEMAP = @have_fiemap@ HAVE_PREADV = @have_preadv@ HAVE_PWRITEV2 = @have_pwritev2@ HAVE_COPY_FILE_RANGE = @have_copy_file_range@ HAVE_SYNC_FILE_RANGE = @have_sync_file_range@ HAVE_SYNCFS = @have_syncfs@ HAVE_READDIR = @have_readdir@ HAVE_MNTENT = @have_mntent@ HAVE_FLS = @have_fls@ HAVE_FSETXATTR = @have_fsetxattr@ HAVE_MREMAP = @have_mremap@ NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@ HAVE_GETFSMAP = @have_getfsmap@ HAVE_STATFS_FLAGS = @have_statfs_flags@ HAVE_MAP_SYNC = @have_map_sync@ HAVE_DEVMAPPER = @have_devmapper@ HAVE_MALLINFO = @have_mallinfo@ HAVE_LIBATTR = @have_libattr@ HAVE_LIBICU = @have_libicu@ HAVE_OPENAT = @have_openat@ HAVE_FSTATAT = @have_fstatat@ HAVE_SG_IO = @have_sg_io@ HAVE_HDIO_GETGEO = @have_hdio_getgeo@ HAVE_SYSTEMD = @have_systemd@ SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@ HAVE_CROND = @have_crond@ CROND_DIR = @crond_dir@ GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall # -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl PCFLAGS = -D_GNU_SOURCE $(GCCFLAGS) ifeq ($(HAVE_UMODE_T),yes) PCFLAGS += -DHAVE_UMODE_T endif DEPENDFLAGS = -D__linux__ ifeq ($(HAVE_FLS),yes) LCFLAGS+= -DHAVE_FLS endif ifeq ($(HAVE_MNTENT),yes) PCFLAGS+= -DHAVE_MNTENT endif ifeq ($(HAVE_FSETXATTR),yes) PCFLAGS+= -DHAVE_FSETXATTR endif ifeq ($(ENABLE_BLKID),yes) PCFLAGS+= -DENABLE_BLKID endif ifeq ($(NEED_INTERNAL_FSXATTR),yes) PCFLAGS+= -DOVERRIDE_SYSTEM_FSXATTR endif ifeq ($(HAVE_GETFSMAP),yes) PCFLAGS+= -DHAVE_GETFSMAP endif LIBICU_LIBS = @libicu_LIBS@ LIBICU_CFLAGS = @libicu_CFLAGS@ SANITIZER_CFLAGS += @addrsan_cflags@ @threadsan_cflags@ @ubsan_cflags@ SANITIZER_LDFLAGS += @addrsan_ldflags@ @threadsan_ldflags@ @ubsan_ldflags@ # Use special ar/ranlib wrappers if we have lto HAVE_LTO = @have_lto@ ifeq ($(HAVE_LTO),yes) OPTIMIZER += @lto_cflags@ LOADERFLAGS += @lto_ldflags@ AR = @gcc_ar@ RANLIB = @gcc_ranlib@ endif GCFLAGS = $(DEBUG) \ -DVERSION=\"$(PKG_VERSION)\" -DLOCALEDIR=\"$(PKG_LOCALE_DIR)\" \ -DPACKAGE=\"$(PKG_NAME)\" -I$(TOPDIR)/include -I$(TOPDIR)/libxfs \ -I$(TOPDIR) ifeq ($(ENABLE_GETTEXT),yes) GCFLAGS += -DENABLE_GETTEXT endif BUILD_CFLAGS += $(GCFLAGS) $(PCFLAGS) # First, Sanitizer, Global, Platform, Local CFLAGS CFLAGS += $(FCFLAGS) $(SANITIZER_CFLAGS) $(OPTIMIZER) $(GCFLAGS) $(PCFLAGS) $(LCFLAGS) include $(TOPDIR)/include/buildmacros endif # # For targets that should always be rebuilt, # define a target that is never up-to-date. # Targets needing this should depend on $(_FORCE) _FORCE = __force_build xfsprogs-5.3.0/include/buildmacros0000644000175000017500000001043113435336036017123 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. # BUILDRULES = $(TOPDIR)/include/buildrules # LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in # user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) # $(CXXFILES), or $(HFILES) and is used to construct the manifest list # during the "dist" phase (packaging). LDFLAGS += $(SANITIZER_LDFLAGS) $(LOADERFLAGS) $(LLDFLAGS) LTLDFLAGS += $(LOADERFLAGS) LDLIBS = $(LLDLIBS) $(PLDLIBS) $(MALLOCLIB) MAKEOPTS = --no-print-directory Q=$(Q) SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) SRCFILES += $(QAHFILES) DEPDIRT = dep dep.bak MANDIRT = *.[1-9].gz PODIRT = *.tmpo *.mo CDIRT = $(OBJECTS) $(LTOBJECTS) $(LTCOMMAND) $(LTLIBRARY) DIRT = $(LDIRT) $(DEPDIRT) $(MANDIRT) $(PODIRT) $(CDIRT) LIBDIRT = .libs DIRDIRT = $(LDIRDIRT) $(LIBDIRT) OBJECTS = $(ASFILES:.s=.o) \ $(CFILES:.c=.o) \ $(LFILES:.l=.o) \ $(YFILES:%.y=%.tab.o) INSTALL = $(TOPDIR)/install-sh -o $(PKG_USER) -g $(PKG_GROUP) IMAGES_DIR = $(TOPDIR)/all-images DIST_DIR = $(TOPDIR)/dist CCF = $(CC) $(CFLAGS) $(CPPFLAGS) MAKEF = $(MAKE) $(MAKEOPTS) CXXF = $(CXX) $(CXXFLAGS) # For libtool. LIBNAME = $(basename $(LTLIBRARY)) LTOBJECTS = $(OBJECTS:.o=.lo) LTVERSION = $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) LTLINK = $(LIBTOOL) --quiet --tag=CC --mode=link $(CC) LTEXEC = $(LIBTOOL) --quiet --mode=execute LTINSTALL = $(LIBTOOL) --quiet --mode=install $(INSTALL) LTCOMPILE = $(LIBTOOL) --quiet --tag=CC --mode=compile $(CCF) ifeq ($(ENABLE_SHARED),yes) LTLDFLAGS += -rpath $(PKG_ROOT_LIB_DIR) LTLDFLAGS += -version-info $(LTVERSION) endif ifeq ($(ENABLE_SHARED),yes) INSTALL_LTLIB = \ cd $(TOPDIR)/$(LIBNAME)/.libs; \ ../$(INSTALL) -m 755 -d $(PKG_ROOT_LIB_DIR); \ ../$(INSTALL) -m 755 -T so_dot_version $(LIBNAME).lai $(PKG_ROOT_LIB_DIR); \ ../$(INSTALL) -T so_dot_current $(LIBNAME).lai $(PKG_ROOT_LIB_DIR) endif # Libtool thinks the static and shared libs should be in the same dir, so # make the static lib appear in the place we chose as rpath (using the two # symlinks below). # Other things want the shared libs to appear in /usr/lib, else they'll # link with the static libs there. So, another symlink to get the .so into # /usr/lib. ifeq ($(ENABLE_SHARED),yes) INSTALL_LTLIB_DEV = \ cd $(TOPDIR)/$(LIBNAME)/.libs; \ ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \ ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_LIB_DIR); \ ../$(INSTALL) -m 644 $(LIBNAME).lai $(PKG_LIB_DIR)/$(LIBNAME).la ; \ ../$(INSTALL) -m 755 -d $(PKG_ROOT_LIB_DIR); \ ../$(INSTALL) -T so_base $(LIBNAME).lai $(PKG_ROOT_LIB_DIR); \ if [ "x$(shell readlink -f $(PKG_LIB_DIR))" != \ "x$(shell readlink -f $(PKG_ROOT_LIB_DIR))" ]; then \ ../$(INSTALL) -S $(PKG_LIB_DIR)/$(LIBNAME).a $(PKG_ROOT_LIB_DIR)/$(LIBNAME).a; \ ../$(INSTALL) -S $(PKG_LIB_DIR)/$(LIBNAME).la $(PKG_ROOT_LIB_DIR)/$(LIBNAME).la; \ ../$(INSTALL) -S $(PKG_ROOT_LIB_DIR)/$(LIBNAME).so $(PKG_LIB_DIR)/$(LIBNAME).so; \ fi else INSTALL_LTLIB_DEV = $(INSTALL_LTLIB_STATIC) endif INSTALL_LTLIB_STATIC = \ cd $(TOPDIR)/$(LIBNAME)/.libs; \ ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \ ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_LIB_DIR) INSTALL_MAN = \ @for d in $(MAN_PAGES); do \ first=true; \ for m in `$(AWK) \ '/^\.S[h|H] NAME/ {ok=1; next} ok {print; exit}' $$d \ | $(SED) \ -e 's/^\.Nm //' -e 's/,/ /g' -e 's/\\-.*//' \ -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ do \ [ -z "$$m" -o "$$m" = "\\" ] && continue; \ t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ if $$first; then \ if $(HAVE_ZIPPED_MANPAGES); then \ $(ZIP) -9 -c $$d > $$d.gz; _sfx=.gz; \ fi; \ u=$$m.$(MAN_SECTION)$$_sfx; \ echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx;\ $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ else \ echo $(INSTALL) -S $$u $${t}$$_sfx; \ $(INSTALL) -S $$u $${t}$$_sfx; \ fi; \ first=false; \ done; \ done ifeq ($(ENABLE_GETTEXT),yes) INSTALL_LINGUAS = \ @for l in $(LINGUAS) ""; do \ if test -f "$$l.mo" ; then \ ldir=$(PKG_LOCALE_DIR)/$$l/LC_MESSAGES; \ $(INSTALL) -m 755 -d $$ldir; \ $(INSTALL) -m 644 $$l.mo $$ldir/$(PKG_NAME).mo; \ fi; \ done endif MAN_MAKERULE = \ @for f in *.[12345678] ""; do \ if test ! -z "$$f"; then \ $(ZIP) --best -c < $$f > $$f.gz; \ fi; \ done xfsprogs-5.3.0/include/buildrules0000644000175000017500000000622413435336036016776 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 1999, 2001-2003 Silicon Graphics, Inc. All Rights Reserved. # ifndef _BUILDRULES_INCLUDED_ _BUILDRULES_INCLUDED_ = 1 include $(TOPDIR)/include/builddefs clean clobber : $(addsuffix -clean,$(SUBDIRS)) @rm -f $(DIRT) .ltdep .dep @rm -fr $(DIRDIRT) %-clean: @echo "Cleaning $*" $(Q)$(MAKE) $(MAKEOPTS) -C $* clean ifdef HDR_SUBDIRS .PHONY: .xfs headers: $(addsuffix -headers, $(HDR_SUBDIRS)) %-headers: .xfs @echo " [HEADERS] $*" $(Q)$(MAKE) $(MAKEOPTS) -C $* NODEP=1 install-headers .xfs: @mkdir -p include/xfs endif # Never blow away subdirs ifdef SUBDIRS .PRECIOUS: $(SUBDIRS) .PHONY: $(SUBDIRS) $(SUBDIRS): @echo "Building $@" $(Q)$(MAKE) $(MAKEOPTS) -q -C $@ || $(MAKE) $(MAKEOPTS) -C $@ endif ifndef CHECK_CMD CHECK_CMD = @true endif # # Standard targets # ifeq ($(CHECKSRC),2) # Check every .c file with sparse CHECK_CMD, do not call compiler $(LTCOMMAND) $(LTLIBRARY) : $(SUBDIRS) $(OBJECTS) .PHONY: $(LTCOMMAND) $(LTLIBRARY) %.lo %.o : %.c FORCE @echo " [CHECK] $<" $(Q)$(CHECK_CMD) $(CFLAGS) $< FORCE: else # Regular build, possibly calling sparse CHECK_CMD as well ifdef LTCOMMAND $(LTCOMMAND) : $(SUBDIRS) $(OBJECTS) $(LTDEPENDENCIES) @echo " [LD] $@" $(Q)$(LTLINK) -o $@ $(LDFLAGS) $(OBJECTS) $(LDLIBS) endif ifdef LTLIBRARY $(LTLIBRARY) : $(SUBDIRS) $(LTOBJECTS) @echo " [LD] $@" $(Q)$(LTLINK) $(LTLDFLAGS) -o $(LTLIBRARY) $(LTOBJECTS) $(LTLIBS) %.lo: %.c @echo " [CC] $@" $(Q)$(LTCOMPILE) -c $< $(Q)$(CHECK_CMD) $(CFLAGS) $< else %.o: %.c @echo " [CC] $@" $(Q)$(CC) $(CFLAGS) -c $< $(Q)$(CHECK_CMD) $(CFLAGS) $< endif endif ifdef POTHEAD $(POTHEAD): $(XGETTEXTFILES) @echo " [GETTXT] $@" $(Q)$(XGETTEXT) --language=C --keyword=_ --keyword=N_ -o $@ $(XGETTEXTFILES) # Update translations update-po: $(POTHEAD) $(wildcard $(TOPDIR)/po/*.po) catalogs="$(wildcard $(TOPDIR)/po/*.po)"; \ for cat in $$catalogs; do \ lang=`basename $$cat .po`; \ mv $$lang.po $$lang.old.po; \ echo "$$lang:"; \ if $(MSGMERGE) $$lang.old.po $(POTHEAD) -o $$lang.po; then \ rm -f $$lang.old.po; \ else \ echo "msgmerge for $$lang failed!"; \ rm -f $$lang.po; \ mv $$lang.old.po $$lang.po; \ fi; \ done %.mo: %.po @echo " [MSGFMT] $@" $(Q)$(MSGFMT) -c --statistics -o $@ $< endif endif # _BUILDRULES_INCLUDED_ $(_FORCE): # dependency build is automatic, relies on gcc -MM to generate. # # This is a bit messy. It regenerates the dependencies on each build so # that we catch files being added and removed. There are other ways of doing # this (e.g. per-file dependency files) but that requires more in-depth changes # to the build system. Compile time is not an issue for us, so the # rebuild on every make invocation isn't a problem we need to care about. Just # do it silently so it doesn't make the build unnecessarily noisy. .PHONY : depend ltdepend MAKEDEP := $(MAKEDEPEND) $(CFLAGS) ltdepend: rmltdep .ltdep rmltdep: $(Q)rm -f .ltdep .ltdep: $(CFILES) $(HFILES) $(Q)$(MAKEDEP) $(CFILES) | $(SED) -e 's,^\([^:]*\)\.o,\1.lo,' > .ltdep depend: rmdep .dep rmdep: $(Q)rm -f .dep .dep: $(CFILES) $(HFILES) $(Q)$(MAKEDEP) $(CFILES) > .dep xfsprogs-5.3.0/include/cache.h0000644000175000017500000001042413435336036016112 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2006 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __CACHE_H__ #define __CACHE_H__ /* * initialisation flags */ /* * xfs_db always writes changes immediately, and so we need to purge buffers * when we get a buffer lookup mismatch due to reading the same block with a * different buffer configuration. */ #define CACHE_MISCOMPARE_PURGE (1 << 0) /* * cache object campare return values */ enum { CACHE_HIT, CACHE_MISS, CACHE_PURGE, }; #define HASH_CACHE_RATIO 8 /* * Cache priorities range from BASE to MAX. * * For prefetch support, the top half of the range starts at * CACHE_PREFETCH_PRIORITY and everytime the buffer is fetched and is at or * above this priority level, it is reduced to below this level (refer to * libxfs_getbuf). * * If we have dirty nodes, we can't recycle them until they've been cleaned. To * keep these out of the reclaimable lists (as there can be lots of them) give * them their own priority that the shaker doesn't attempt to walk. */ #define CACHE_BASE_PRIORITY 0 #define CACHE_PREFETCH_PRIORITY 8 #define CACHE_MAX_PRIORITY 15 #define CACHE_DIRTY_PRIORITY (CACHE_MAX_PRIORITY + 1) #define CACHE_NR_PRIORITIES CACHE_DIRTY_PRIORITY /* * Simple, generic implementation of a cache (arbitrary data). * Provides a hash table with a capped number of cache entries. */ struct cache; struct cache_node; typedef void *cache_key_t; typedef void (*cache_walk_t)(struct cache_node *); typedef struct cache_node * (*cache_node_alloc_t)(cache_key_t); typedef int (*cache_node_flush_t)(struct cache_node *); typedef void (*cache_node_relse_t)(struct cache_node *); typedef unsigned int (*cache_node_hash_t)(cache_key_t, unsigned int, unsigned int); typedef int (*cache_node_compare_t)(struct cache_node *, cache_key_t); typedef unsigned int (*cache_bulk_relse_t)(struct cache *, struct list_head *); struct cache_operations { cache_node_hash_t hash; cache_node_alloc_t alloc; cache_node_flush_t flush; cache_node_relse_t relse; cache_node_compare_t compare; cache_bulk_relse_t bulkrelse; /* optional */ }; struct cache_hash { struct list_head ch_list; /* hash chain head */ unsigned int ch_count; /* hash chain length */ pthread_mutex_t ch_mutex; /* hash chain mutex */ }; struct cache_mru { struct list_head cm_list; /* MRU head */ unsigned int cm_count; /* MRU length */ pthread_mutex_t cm_mutex; /* MRU lock */ }; struct cache_node { struct list_head cn_hash; /* hash chain */ struct list_head cn_mru; /* MRU chain */ unsigned int cn_count; /* reference count */ unsigned int cn_hashidx; /* hash chain index */ int cn_priority; /* priority, -1 = free list */ int cn_old_priority;/* saved pre-dirty prio */ pthread_mutex_t cn_mutex; /* node mutex */ }; struct cache { int c_flags; /* behavioural flags */ unsigned int c_maxcount; /* max cache nodes */ unsigned int c_count; /* count of nodes */ pthread_mutex_t c_mutex; /* node count mutex */ cache_node_hash_t hash; /* node hash function */ cache_node_alloc_t alloc; /* allocation function */ cache_node_flush_t flush; /* flush dirty data function */ cache_node_relse_t relse; /* memory free function */ cache_node_compare_t compare; /* comparison routine */ cache_bulk_relse_t bulkrelse; /* bulk release routine */ unsigned int c_hashsize; /* hash bucket count */ unsigned int c_hashshift; /* hash key shift */ struct cache_hash *c_hash; /* hash table buckets */ struct cache_mru c_mrus[CACHE_DIRTY_PRIORITY + 1]; unsigned long long c_misses; /* cache misses */ unsigned long long c_hits; /* cache hits */ unsigned int c_max; /* max nodes ever used */ }; struct cache *cache_init(int, unsigned int, struct cache_operations *); void cache_destroy(struct cache *); void cache_walk(struct cache *, cache_walk_t); void cache_purge(struct cache *); void cache_flush(struct cache *); int cache_node_get(struct cache *, cache_key_t, struct cache_node **); void cache_node_put(struct cache *, struct cache_node *); void cache_node_set_priority(struct cache *, struct cache_node *, int); int cache_node_get_priority(struct cache_node *); int cache_node_purge(struct cache *, cache_key_t, struct cache_node *); void cache_report(FILE *fp, const char *, struct cache *); int cache_overflowed(struct cache *); #endif /* __CACHE_H__ */ xfsprogs-5.3.0/include/command.h0000644000175000017500000000324113435336036016464 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __COMMAND_H__ #define __COMMAND_H__ #include /* * A "oneshot" command ony runs once per command execution. It does * not iterate the command args function callout and so can be used * for functions like "help" that should only ever be run once. */ #define CMD_FLAG_ONESHOT (1u << 31) #define CMD_FLAG_FOREIGN_OK (1u << 30) /* command not restricted to XFS */ #define CMD_FLAG_LIBRARY (1u << 29) /* command provided by libxcmd */ typedef int (*cfunc_t)(int argc, char **argv); typedef void (*helpfunc_t)(void); typedef struct cmdinfo { const char *name; const char *altname; cfunc_t cfunc; int argmin; int argmax; int canpush; int flags; const char *args; const char *oneline; helpfunc_t help; } cmdinfo_t; extern cmdinfo_t *cmdtab; extern int ncmds; extern void help_init(void); extern void quit_init(void); typedef int (*iterfunc_t)(int index); typedef int (*checkfunc_t)(const cmdinfo_t *ci); extern void add_command(const cmdinfo_t *ci); extern void add_user_command(char *optarg); extern void add_oneshot_user_command(char *optarg); extern void add_command_iterator(iterfunc_t func); extern void add_check_command(checkfunc_t cf); extern const cmdinfo_t *find_command(const char *cmd); extern void command_loop(void); extern int command_usage(const cmdinfo_t *ci); extern int command(const cmdinfo_t *ci, int argc, char **argv); extern void report_io_times(const char *verb, struct timeval *t2, long long offset, long long count, long long total, int ops, int compact); #endif /* __COMMAND_H__ */ xfsprogs-5.3.0/include/handle.h0000644000175000017500000000310313435336036016276 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __HANDLE_H__ #define __HANDLE_H__ #ifdef __cplusplus extern "C" { #endif struct fsdmidata; struct attrlist_cursor; struct parent; extern int path_to_handle (char *__path, void **__hanp, size_t *__hlen); extern int path_to_fshandle (char *__path, void **__fshanp, size_t *__fshlen); extern int fd_to_handle (int fd, void **hanp, size_t *hlen); extern int handle_to_fshandle (void *__hanp, size_t __hlen, void **__fshanp, size_t *__fshlen); extern void free_handle (void *__hanp, size_t __hlen); extern int open_by_fshandle (void *__fshanp, size_t __fshlen, int __rw); extern int open_by_handle (void *__hanp, size_t __hlen, int __rw); extern int readlink_by_handle (void *__hanp, size_t __hlen, void *__buf, size_t __bs); extern int attr_multi_by_handle (void *__hanp, size_t __hlen, void *__buf, int __rtrvcnt, int __flags); extern int attr_list_by_handle (void *__hanp, size_t __hlen, void *__buf, size_t __bufsize, int __flags, struct attrlist_cursor *__cursor); extern int parents_by_handle(void *__hanp, size_t __hlen, struct parent *__buf, size_t __bufsize, unsigned int *__count); extern int parentpaths_by_handle(void *__hanp, size_t __hlen, struct parent *__buf, size_t __bufsize, unsigned int *__count); extern int fssetdm_by_handle (void *__hanp, size_t __hlen, struct fsdmidata *__fsdmi); void fshandle_destroy(void); #ifdef __cplusplus } #endif #endif /* __HANDLE_H__ */ xfsprogs-5.3.0/include/hlist.h0000644000175000017500000000266613435336036016203 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * double-linked hash list with single head implementation taken from linux * kernel headers as of 2.6.38-rc1. */ #ifndef __HLIST_H__ #define __HLIST_H__ struct hlist_node { struct hlist_node *next; struct hlist_node **pprev; }; struct hlist_head { struct hlist_node *first; }; #define HLIST_HEAD_INIT { .first = NULL } static inline void INIT_HLIST_NODE(struct hlist_node *h) { h->next = NULL; h->pprev = NULL; } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } static inline void __hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static inline void hlist_del(struct hlist_node *n) { __hlist_del(n); } #define hlist_entry(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos; pos = pos->next) #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) #endif /* __LIST_H__ */ xfsprogs-5.3.0/include/input.h0000644000175000017500000000220113570057155016202 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __INPUT_H__ #define __INPUT_H__ #include #include #include #include "libfrog/projects.h" #include "libfrog/convert.h" #include extern char **breakline(char *input, int *count); extern void doneline(char *input, char **vec); extern char *fetchline(void); extern size_t numlen(uint64_t val, size_t base); extern struct timeval tsub(struct timeval t1, struct timeval t2); extern double tdiv(double value, struct timeval tv); enum { DEFAULT_TIME = 0x0, TERSE_FIXED_TIME = 0x1, VERBOSE_FIXED_TIME = 0x2 }; extern void timestr(struct timeval *tv, char *str, size_t sz, int flags); extern bool isdigits_only(const char *str); extern int timespec_from_string(const char *sec, const char *nsec, struct timespec *ts); #define HAVE_FTW_H 1 /* TODO: configure me */ #ifdef HAVE_FTW_H #include #else struct FTW; struct stat; extern int nftw( char *dir, int (*fn)(const char *, const struct stat *, int, struct FTW *), int depth, int flags); #endif #endif /* __INPUT_H__ */ xfsprogs-5.3.0/include/install-sh0000755000175000017500000001550613435336036016710 0ustar nathansnathans#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # # This script emulates bsd install and also recognises # two environment variables, with the following semantics :- # # $DIST_MANIFEST - if set, the name of the file to append manifest # information in the following format: # File : f mode owner group src target # Directory: d mode owner group target # Symlink : l linkval target # # $DIST_ROOT - if set, prepend to target # # The sematics of all combinations of these two variables # are as follows: # # $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? # -----------------------------+-------------------------- # not set not set | yes no # not set set | yes no # set not set | no yes # set set | yes yes # _usage() { echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" echo "or $prog -S file target (creates \"target\" symlink)" echo "or $prog -T lt_arg [-o owner] [-g group] [-m mode] libtool.lai directory" echo "" echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" echo "behaviour of this command - see comments in the script." echo "The -D flag is only available for the second usage, and causes" echo "the target directory to be created before installing the file." echo "" exit 1 } _chown () { _st=255 if [ $# -eq 3 ] ; then chown $1:$2 $3 _st=$? if [ $_st -ne 0 ] ; then if [ $REAL_UID != '0' ] ; then if [ ! -f $DIST_ROOT/.chown.quiet ] ; then echo '===============================================' echo Ownership of files under ${DIST_ROOT:-/} echo cannot be changed echo '===============================================' if [ -n "$DIST_ROOT" ] ; then touch $DIST_ROOT/.chown.quiet fi fi _st=0 fi fi fi return $_st } _manifest () { echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} } prog=`basename $0` HERE=`pwd` dflag=false Dflag=false Sflag=false Tflag=false DIRMODE=755 FILEMODE=644 OWNER=`id -u` GROUP=`id -g` REAL_UID=$OWNER # default is to install and don't append manifest INSTALL=true MANIFEST=: : ${DIST_ROOT:=${DESTDIR}} [ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false [ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" [ $# -eq 0 ] && _usage if $INSTALL then CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown else CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true fi [ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true while getopts "Dcm:d:S:o:g:T:" c $* do case $c in c) ;; g) GROUP=$OPTARG ;; o) OWNER=$OPTARG ;; m) DIRMODE=`expr $OPTARG` FILEMODE=$DIRMODE ;; D) Dflag=true ;; S) symlink=$OPTARG Sflag=true ;; d) dir=$DIST_ROOT/$OPTARG dflag=true ;; T) lt_install=$OPTARG Tflag=true ;; *) _usage ;; esac done shift `expr $OPTIND - 1` status=0 if $dflag then # # first usage # $MKDIR -p $dir status=$? if [ $status -eq 0 ] then $CHMOD $DIRMODE $dir status=$? fi if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir status=$? fi $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} elif $Sflag then # # fourth usage (symlink) # if [ $# -ne 1 ] then _usage else target=$DIST_ROOT/$1 fi $LN -s -f $symlink $target status=$? $MANIFEST l $symlink ${target#$DIST_ROOT} elif $Tflag then # # -T (install libs built by libtool) # if [ $# -ne 2 ] then _usage else libtool_lai=$1 # source the libtool variables if [ ! -f $libtool_lai ] then echo "$prog: Unable to find libtool library file $libtool_lai" exit 2 fi . ./$libtool_lai target=$DIST_ROOT/$2 fi case $lt_install in so_dot_version) # Loop until we find libfoo.so.x.y.z, then break out. for solib in $library_names do # does it have enough parts? libfoo.so.x.y.z == 5 cnt=`echo "$solib" | sed -e 's/\./ /g' | wc -w` if [ $cnt -eq 5 ] then install_name=$target/$solib $CP $solib $install_name status=$? $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$solib ${install_name#$DIST_ROOT} break fi done ;; so_*) case $lt_install in so_dot_current) # ln -s libfoo.so.x.y.z to libfoo.so.x from_parts=5 # libfoo.so.x.y.z to_parts=3 # libfoo.so.x ;; so_base) # ln -s libfoo.so.x to libfoo.so from_parts=3 # libfoo.so.x to_parts=2 # libfoo.so ;; *) echo "$prog: -T $lt_install invalid" exit 2 ;; esac # Loop until we find the names, then break out. for solib in $library_names do # does it have enough parts? cnt=`echo "$solib" | sed -e 's/\./ /g' | wc -w` if [ $cnt -eq $from_parts ] then from_name=$solib elif [ $cnt -eq $to_parts ] then to_name=$solib fi if [ -n "$from_name" ] && [ -n "$to_name" ] then install_name=$target/$to_name $LN -s -f $from_name $install_name status=$? $MANIFEST l $from_name ${install_name#$DIST_ROOT} break fi done ;; old_lib) install_name=$target/$old_library $CP $old_library $install_name status=$? $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$old_library ${install_name#$DIST_ROOT} ;; *) echo "$prog: -T $lt_install invalid" exit 2 ;; esac case $lt_install in old_lib|so_dot_version) if [ $status -eq 0 ] then $CHMOD $FILEMODE $install_name $CHOWN $OWNER $GROUP $install_name fi ;; esac else list="" dir="" if [ $# -eq 2 ] then # # second usage # f=$1 dir=$DIST_ROOT/$2 if $Dflag then mkdir -p `dirname $dir` fi $CP $f $dir status=$? if [ $status -eq 0 ] then if [ -f $dir/$f ] then $CHMOD $FILEMODE $dir/$f status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir/$f status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f else $CHMOD $FILEMODE $dir status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} fi fi else # # third usage # n=1 while [ $# -gt 0 ] do if [ $# -gt 1 ] then list="$list $1" else dir=$DIST_ROOT/$1 fi shift done # echo DIR=$dir list=\"$list\" for f in $list do $CP $f $dir status=$? if [ $status -eq 0 ] then $CHMOD $FILEMODE $dir/$f status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir/$f status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f fi [ $status -ne 0 ] && break done fi fi exit $status xfsprogs-5.3.0/include/jdm.h0000644000175000017500000000344513570057155015630 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 2000-2002, 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __JDM_H__ #define __JDM_H__ typedef int intgen_t; typedef void jdm_fshandle_t; /* filesystem handle */ typedef void jdm_filehandle_t; /* filehandle */ struct xfs_bstat; struct attrlist_cursor; struct parent; extern jdm_fshandle_t * jdm_getfshandle( char *mntpnt); extern void jdm_new_filehandle( jdm_filehandle_t **handlep, /* new filehandle */ size_t *hlen, /* new filehandle size */ jdm_fshandle_t *fshandlep, /* filesystem filehandle */ struct xfs_bstat *sp); /* bulkstat info */ extern void jdm_delete_filehandle( jdm_filehandle_t *handlep,/* filehandle to delete */ size_t hlen); /* filehandle size */ extern intgen_t jdm_open( jdm_fshandle_t *fshandlep, struct xfs_bstat *sp, intgen_t oflags); extern intgen_t jdm_readlink( jdm_fshandle_t *fshandlep, struct xfs_bstat *sp, char *bufp, size_t bufsz); extern intgen_t jdm_attr_multi( jdm_fshandle_t *fshp, struct xfs_bstat *statp, char *bufp, int rtrvcnt, int flags); extern intgen_t jdm_attr_list( jdm_fshandle_t *fshp, struct xfs_bstat *statp, char *bufp, size_t bufsz, int flags, struct attrlist_cursor *cursor); extern int jdm_parents( jdm_fshandle_t *fshp, struct xfs_bstat *statp, struct parent *bufp, size_t bufsz, unsigned int *count); extern int jdm_parentpaths( jdm_fshandle_t *fshp, struct xfs_bstat *statp, struct parent *bufp, size_t bufsz, unsigned int *count); /* macro for determining the size of a structure member */ #define sizeofmember( t, m ) sizeof( ( ( t * )0 )->m ) /* macro for calculating the offset of a structure member */ #define offsetofmember( t, m ) ( ( size_t )( char * )&( ( ( t * )0 )->m ) ) #endif /* __JDM_H__ */ xfsprogs-5.3.0/include/kmem.h0000644000175000017500000000174313435336036016004 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2008 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __KMEM_H__ #define __KMEM_H__ #define KM_SLEEP 0x0001u #define KM_NOSLEEP 0x0002u #define KM_NOFS 0x0004u #define KM_MAYFAIL 0x0008u #define KM_LARGE 0x0010u typedef struct kmem_zone { int zone_unitsize; /* Size in bytes of zone unit */ char *zone_name; /* tag name */ int allocated; /* debug: How many currently allocated */ } kmem_zone_t; extern kmem_zone_t *kmem_zone_init(int, char *); extern void *kmem_zone_alloc(kmem_zone_t *, int); extern void *kmem_zone_zalloc(kmem_zone_t *, int); extern int kmem_zone_destroy(kmem_zone_t *); static inline void kmem_zone_free(kmem_zone_t *zone, void *ptr) { zone->allocated--; free(ptr); } extern void *kmem_alloc(size_t, int); extern void *kmem_zalloc(size_t, int); static inline void kmem_free(void *ptr) { free(ptr); } extern void *kmem_realloc(void *, size_t, int); #endif xfsprogs-5.3.0/include/libxcmd.h0000644000175000017500000000035113570057155016471 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBXCMD_H__ #define __LIBXCMD_H__ #include "libxfs.h" #include #endif /* __LIBXCMD_H__ */ xfsprogs-5.3.0/include/libxfs.h0000644000175000017500000001525413570057155016346 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBXFS_H__ #define __LIBXFS_H__ #include "libxfs_api_defs.h" #include "platform_defs.h" #include "xfs.h" #include "list.h" #include "hlist.h" #include "cache.h" #include "bitops.h" #include "kmem.h" #include "libfrog/radix-tree.h" #include "atomic.h" #include "xfs_types.h" #include "xfs_fs.h" #include "xfs_arch.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_quota_defs.h" #include "xfs_trans_resv.h" /* CRC stuff, buffer API dependent on it */ extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len); #define crc32c(c,p,l) crc32c_le((c),(unsigned char const *)(p),(l)) #include "xfs_cksum.h" /* * This mirrors the kernel include for xfs_buf.h - it's implicitly included in * every files via a similar include in the kernel xfs_linux.h. */ #include "libxfs_io.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_errortag.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2.h" #include "xfs_bmap_btree.h" #include "xfs_alloc_btree.h" #include "xfs_ialloc_btree.h" #include "xfs_attr_sf.h" #include "xfs_inode_fork.h" #include "xfs_inode_buf.h" #include "xfs_inode.h" #include "xfs_alloc.h" #include "xfs_btree.h" #include "xfs_btree_trace.h" #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_ag.h" #include "xfs_rmap_btree.h" #include "xfs_rmap.h" #include "xfs_refcount_btree.h" #include "xfs_refcount.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #ifndef XFS_SUPER_MAGIC #define XFS_SUPER_MAGIC 0x58465342 #endif #define xfs_isset(a,i) ((a)[(i)/(sizeof(*(a))*NBBY)] & (1ULL<<((i)%(sizeof(*(a))*NBBY)))) /* * Argument structure for libxfs_init(). */ typedef struct libxfs_xinit { /* input parameters */ char *volname; /* pathname of volume */ char *dname; /* pathname of data "subvolume" */ char *logname; /* pathname of log "subvolume" */ char *rtname; /* pathname of realtime "subvolume" */ int isreadonly; /* filesystem is only read in applic */ int isdirect; /* we can attempt to use direct I/O */ int disfile; /* data "subvolume" is a regular file */ int dcreat; /* try to create data subvolume */ int lisfile; /* log "subvolume" is a regular file */ int lcreat; /* try to create log subvolume */ int risfile; /* realtime "subvolume" is a reg file */ int rcreat; /* try to create realtime subvolume */ int setblksize; /* attempt to set device blksize */ int usebuflock; /* lock xfs_buf_t's - for MT usage */ /* output results */ dev_t ddev; /* device for data subvolume */ dev_t logdev; /* device for log subvolume */ dev_t rtdev; /* device for realtime subvolume */ long long dsize; /* size of data subvolume (BBs) */ long long logBBsize; /* size of log subvolume (BBs) */ /* (blocks allocated for use as * log is stored in mount structure) */ long long logBBstart; /* start block of log subvolume (BBs) */ long long rtsize; /* size of realtime subvolume (BBs) */ int dbsize; /* data subvolume device blksize */ int lbsize; /* log subvolume device blksize */ int rtbsize; /* realtime subvolume device blksize */ int dfd; /* data subvolume file descriptor */ int logfd; /* log subvolume file descriptor */ int rtfd; /* realtime subvolume file descriptor */ int icache_flags; /* cache init flags */ int bcache_flags; /* cache init flags */ } libxfs_init_t; #define LIBXFS_EXIT_ON_FAILURE 0x0001 /* exit the program if a call fails */ #define LIBXFS_ISREADONLY 0x0002 /* disallow all mounted filesystems */ #define LIBXFS_ISINACTIVE 0x0004 /* allow mounted only if mounted ro */ #define LIBXFS_DANGEROUSLY 0x0008 /* repairing a device mounted ro */ #define LIBXFS_EXCLUSIVELY 0x0010 /* disallow other accesses (O_EXCL) */ #define LIBXFS_DIRECT 0x0020 /* can use direct I/O, not buffered */ extern char *progname; extern xfs_lsn_t libxfs_max_lsn; extern int libxfs_init (libxfs_init_t *); extern void libxfs_destroy (void); extern int libxfs_device_to_fd (dev_t); extern dev_t libxfs_device_open (char *, int, int, int); extern void libxfs_device_close (dev_t); extern int libxfs_device_alignment (void); extern void libxfs_report(FILE *); /* check or write log footer: specify device, log size in blocks & uuid */ typedef char *(libxfs_get_block_t)(char *, int, void *); /* * Helpers to clear the log to a particular log cycle. */ #define XLOG_INIT_CYCLE 1 extern int libxfs_log_clear(struct xfs_buftarg *, char *, xfs_daddr_t, uint, uuid_t *, int, int, int, int, bool); extern int libxfs_log_header(char *, uuid_t *, int, int, int, xfs_lsn_t, xfs_lsn_t, libxfs_get_block_t *, void *); /* Shared utility routines */ extern int libxfs_alloc_file_space (struct xfs_inode *, xfs_off_t, xfs_off_t, int, int); /* XXX: this is messy and needs fixing */ #ifndef __LIBXFS_INTERNAL_XFS_H__ extern void cmn_err(int, char *, ...); enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; #endif #include "xfs_ialloc.h" #include "xfs_attr_leaf.h" #include "xfs_attr_remote.h" #include "xfs_trans_space.h" #define XFS_INOBT_IS_FREE_DISK(rp,i) \ ((be64_to_cpu((rp)->ir_free) & XFS_INOBT_MASK(i)) != 0) static inline bool xfs_inobt_is_sparse_disk( struct xfs_inobt_rec *rp, int offset) { int spshift; uint16_t holemask; holemask = be16_to_cpu(rp->ir_u.sp.ir_holemask); spshift = offset / XFS_INODES_PER_HOLEMASK_BIT; if ((1 << spshift) & holemask) return true; return false; } static inline void libxfs_bmbt_disk_get_all( struct xfs_bmbt_rec *rec, struct xfs_bmbt_irec *irec) { uint64_t l0 = get_unaligned_be64(&rec->l0); uint64_t l1 = get_unaligned_be64(&rec->l1); irec->br_startoff = (l0 & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; irec->br_startblock = ((l0 & xfs_mask64lo(9)) << 43) | (l1 >> 21); irec->br_blockcount = l1 & xfs_mask64lo(21); if (l0 >> (64 - BMBT_EXNTFLAG_BITLEN)) irec->br_state = XFS_EXT_UNWRITTEN; else irec->br_state = XFS_EXT_NORM; } /* XXX: this is clearly a bug - a shared header needs to export this */ /* xfs_rtalloc.c */ int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t); bool libxfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno); #include "xfs_attr.h" #endif /* __LIBXFS_H__ */ xfsprogs-5.3.0/include/libxlog.h0000644000175000017500000001003413466663244016514 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc.All Rights Reserved. */ #ifndef LIBXLOG_H #define LIBXLOG_H /* * define the userlevel xlog_t to be the subset of the kernel's * xlog_t that we actually need to get our work done, avoiding * the need to define any exotic kernel types in userland. */ struct xlog { xfs_lsn_t l_tail_lsn; /* lsn of 1st LR w/ unflush buffers */ xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ xfs_mount_t *l_mp; /* mount point */ struct xfs_buftarg *l_dev; /* dev_t of log */ xfs_daddr_t l_logBBstart; /* start block of log */ int l_logBBsize; /* size of log in 512 byte chunks */ int l_curr_cycle; /* Cycle number of log writes */ int l_prev_cycle; /* Cycle # b4 last block increment */ int l_curr_block; /* current logical block of log */ int l_prev_block; /* previous logical block of log */ int l_iclog_size; /* size of log in bytes */ int l_iclog_size_log;/* log power size of log */ int l_iclog_bufs; /* number of iclog buffers */ atomic64_t l_grant_reserve_head; atomic64_t l_grant_write_head; uint l_sectbb_log; /* log2 of sector size in bbs */ uint l_sectbb_mask; /* sector size (in BBs) * alignment mask */ int l_sectBBsize; /* size of log sector in 512 byte chunks */ }; #include "xfs_log_recover.h" /* * macros mapping kernel code to user code * * XXX: this is duplicated stuff - should be shared with libxfs. */ #ifndef EFSCORRUPTED #define EFSCORRUPTED 990 #endif #define STATIC static #define XFS_ERROR(e) (e) #ifdef DEBUG #define XFS_ERROR_REPORT(e,l,mp) fprintf(stderr, "ERROR: %s\n", e) #else #define XFS_ERROR_REPORT(e,l,mp) ((void) 0) #endif #define XFS_CORRUPTION_ERROR(e,l,mp,m) ((void) 0) #define XFS_MOUNT_WAS_CLEAN 0x1 #define unlikely(x) (x) #define xfs_alert(mp,fmt,args...) cmn_err(CE_ALERT,fmt, ## args) #define xfs_warn(mp,fmt,args...) cmn_err(CE_WARN,fmt, ## args) #define xfs_hex_dump(d,n) ((void) 0) #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) extern void xlog_warn(char *fmt,...); extern void xlog_exit(char *fmt,...); extern void xlog_panic(char *fmt,...); /* exports */ extern int print_exit; extern int print_skip_uuid; extern int print_record_header; /* libxfs parameters */ extern libxfs_init_t x; extern int xlog_is_dirty(struct xfs_mount *, struct xlog *, libxfs_init_t *, int); extern struct xfs_buf *xlog_get_bp(struct xlog *, int); extern void xlog_put_bp(struct xfs_buf *); extern int xlog_bread(struct xlog *log, xfs_daddr_t blk_no, int nbblks, xfs_buf_t *bp, char **offset); extern int xlog_bread_noalign(struct xlog *log, xfs_daddr_t blk_no, int nbblks, xfs_buf_t *bp); extern int xlog_find_zeroed(struct xlog *log, xfs_daddr_t *blk_no); extern int xlog_find_cycle_start(struct xlog *log, xfs_buf_t *bp, xfs_daddr_t first_blk, xfs_daddr_t *last_blk, uint cycle); extern int xlog_find_tail(struct xlog *log, xfs_daddr_t *head_blk, xfs_daddr_t *tail_blk); extern int xlog_recover(struct xlog *log, int readonly); extern void xlog_recover_print_data(char *p, int len); extern void xlog_recover_print_logitem(xlog_recover_item_t *item); extern void xlog_recover_print_trans_head(xlog_recover_t *tr); extern int xlog_print_find_oldest(struct xlog *log, xfs_daddr_t *last_blk); /* for transactional view */ extern void xlog_recover_print_trans_head(xlog_recover_t *tr); extern void xlog_recover_print_trans(xlog_recover_t *trans, struct list_head *itemq, int print); extern int xlog_do_recovery_pass(struct xlog *log, xfs_daddr_t head_blk, xfs_daddr_t tail_blk, int pass); extern int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *trans, int pass); extern int xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head); extern int xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head); #define xlog_assign_atomic_lsn(l,a,b) ((void) 0) #define xlog_assign_grant_head(l,a,b) ((void) 0) #endif /* LIBXLOG_H */ xfsprogs-5.3.0/include/linux.h0000644000175000017500000002325613435336036016215 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef __XFS_LINUX_H__ #define __XFS_LINUX_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef OVERRIDE_SYSTEM_FSXATTR # define fsxattr sys_fsxattr #endif #include /* fsxattr defintion for new kernels */ #ifdef OVERRIDE_SYSTEM_FSXATTR # undef fsxattr #endif static __inline__ int xfsctl(const char *path, int fd, int cmd, void *p) { return ioctl(fd, cmd, p); } /* * platform_test_xfs_*() implies that xfsctl will succeed on the file; * on Linux, at least, special files don't get xfs file ops, * so return 0 for those */ static __inline__ int platform_test_xfs_fd(int fd) { struct statfs statfsbuf; struct stat statbuf; if (fstatfs(fd, &statfsbuf) < 0) return 0; if (fstat(fd, &statbuf) < 0) return 0; if (!S_ISREG(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) return 0; return (statfsbuf.f_type == 0x58465342); /* XFSB */ } static __inline__ int platform_test_xfs_path(const char *path) { struct statfs statfsbuf; struct stat statbuf; if (statfs(path, &statfsbuf) < 0) return 0; if (stat(path, &statbuf) < 0) return 0; if (!S_ISREG(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) return 0; return (statfsbuf.f_type == 0x58465342); /* XFSB */ } static __inline__ int platform_fstatfs(int fd, struct statfs *buf) { return fstatfs(fd, buf); } static __inline__ void platform_getoptreset(void) { extern int optind; optind = 0; } static __inline__ int platform_uuid_compare(uuid_t *uu1, uuid_t *uu2) { return uuid_compare(*uu1, *uu2); } static __inline__ void platform_uuid_unparse(uuid_t *uu, char *buffer) { uuid_unparse(*uu, buffer); } static __inline__ int platform_uuid_parse(char *buffer, uuid_t *uu) { return uuid_parse(buffer, *uu); } static __inline__ int platform_uuid_is_null(uuid_t *uu) { return uuid_is_null(*uu); } static __inline__ void platform_uuid_generate(uuid_t *uu) { uuid_generate(*uu); } static __inline__ void platform_uuid_clear(uuid_t *uu) { uuid_clear(*uu); } static __inline__ void platform_uuid_copy(uuid_t *dst, uuid_t *src) { uuid_copy(*dst, *src); } #ifndef BLKDISCARD #define BLKDISCARD _IO(0x12,119) #endif static __inline__ int platform_discard_blocks(int fd, uint64_t start, uint64_t len) { uint64_t range[2] = { start, len }; if (ioctl(fd, BLKDISCARD, &range) < 0) return errno; return 0; } #define ENOATTR ENODATA /* Attribute not found */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ #define EFSBADCRC EBADMSG /* Bad CRC detected */ typedef off_t xfs_off_t; typedef uint64_t xfs_ino_t; typedef uint32_t xfs_dev_t; typedef int64_t xfs_daddr_t; typedef __u32 xfs_nlink_t; /** * Abstraction of mountpoints. */ struct mntent_cursor { FILE *mtabp; }; static inline int platform_mntent_open(struct mntent_cursor * cursor, char *mtab) { cursor->mtabp = setmntent(mtab, "r"); if (!cursor->mtabp) { fprintf(stderr, "Error: cannot read %s\n", mtab); return 1; } return 0; } static inline struct mntent * platform_mntent_next(struct mntent_cursor * cursor) { return getmntent(cursor->mtabp); } static inline void platform_mntent_close(struct mntent_cursor * cursor) { endmntent(cursor->mtabp); } /* * Check whether we have to define FS_IOC_FS[GS]ETXATTR ourselves. These * are a copy of the definitions moved to linux/uapi/fs.h in the 4.5 kernel, * so this is purely for supporting builds against old kernel headers. */ #if !defined FS_IOC_FSGETXATTR || defined OVERRIDE_SYSTEM_FSXATTR struct fsxattr { __u32 fsx_xflags; /* xflags field value (get/set) */ __u32 fsx_extsize; /* extsize field value (get/set)*/ __u32 fsx_nextents; /* nextents field value (get) */ __u32 fsx_projid; /* project identifier (get/set) */ __u32 fsx_cowextsize; /* cow extsize field value (get/set) */ unsigned char fsx_pad[8]; }; #endif #ifndef FS_IOC_FSGETXATTR /* * Flags for the fsx_xflags field */ #define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ #define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ #define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ #define FS_XFLAG_APPEND 0x00000010 /* all writes append */ #define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ #define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ #define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ #define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ #define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ #define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ #define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ #define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ #define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ #define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ #define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */ #define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ #define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) #define FS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) #endif #ifndef FS_XFLAG_COWEXTSIZE #define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */ #endif #ifdef HAVE_GETFSMAP # include #else /* * Structure for FS_IOC_GETFSMAP. * * The memory layout for this call are the scalar values defined in * struct fsmap_head, followed by two struct fsmap that describe * the lower and upper bound of mappings to return, followed by an * array of struct fsmap mappings. * * fmh_iflags control the output of the call, whereas fmh_oflags report * on the overall record output. fmh_count should be set to the * length of the fmh_recs array, and fmh_entries will be set to the * number of entries filled out during each call. If fmh_count is * zero, the number of reverse mappings will be returned in * fmh_entries, though no mappings will be returned. fmh_reserved * must be set to zero. * * The two elements in the fmh_keys array are used to constrain the * output. The first element in the array should represent the * lowest disk mapping ("low key") that the user wants to learn * about. If this value is all zeroes, the filesystem will return * the first entry it knows about. For a subsequent call, the * contents of fsmap_head.fmh_recs[fsmap_head.fmh_count - 1] should be * copied into fmh_keys[0] to have the kernel start where it left off. * * The second element in the fmh_keys array should represent the * highest disk mapping ("high key") that the user wants to learn * about. If this value is all ones, the filesystem will not stop * until it runs out of mapping to return or runs out of space in * fmh_recs. * * fmr_device can be either a 32-bit cookie representing a device, or * a 32-bit dev_t if the FMH_OF_DEV_T flag is set. fmr_physical, * fmr_offset, and fmr_length are expressed in units of bytes. * fmr_owner is either an inode number, or a special value if * FMR_OF_SPECIAL_OWNER is set in fmr_flags. */ struct fsmap { __u32 fmr_device; /* device id */ __u32 fmr_flags; /* mapping flags */ __u64 fmr_physical; /* device offset of segment */ __u64 fmr_owner; /* owner id */ __u64 fmr_offset; /* file offset of segment */ __u64 fmr_length; /* length of segment */ __u64 fmr_reserved[3]; /* must be zero */ }; struct fsmap_head { __u32 fmh_iflags; /* control flags */ __u32 fmh_oflags; /* output flags */ __u32 fmh_count; /* # of entries in array incl. input */ __u32 fmh_entries; /* # of entries filled in (output). */ __u64 fmh_reserved[6]; /* must be zero */ struct fsmap fmh_keys[2]; /* low and high keys for the mapping search */ struct fsmap fmh_recs[]; /* returned records */ }; /* Size of an fsmap_head with room for nr records. */ static inline size_t fsmap_sizeof( unsigned int nr) { return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap); } /* Start the next fsmap query at the end of the current query results. */ static inline void fsmap_advance( struct fsmap_head *head) { head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1]; } /* fmh_iflags values - set by XFS_IOC_GETFSMAP caller in the header. */ /* no flags defined yet */ #define FMH_IF_VALID 0 /* fmh_oflags values - returned in the header segment only. */ #define FMH_OF_DEV_T 0x1 /* fmr_device values will be dev_t */ /* fmr_flags values - returned for each non-header segment */ #define FMR_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ #define FMR_OF_ATTR_FORK 0x2 /* segment = attribute fork */ #define FMR_OF_EXTENT_MAP 0x4 /* segment = extent map */ #define FMR_OF_SHARED 0x8 /* segment = shared with another file */ #define FMR_OF_SPECIAL_OWNER 0x10 /* owner is a special value */ #define FMR_OF_LAST 0x20 /* segment is the last in the FS */ /* Each FS gets to define its own special owner codes. */ #define FMR_OWNER(type, code) (((__u64)type << 32) | \ ((__u64)code & 0xFFFFFFFFULL)) #define FMR_OWNER_TYPE(owner) ((__u32)((__u64)owner >> 32)) #define FMR_OWNER_CODE(owner) ((__u32)(((__u64)owner & 0xFFFFFFFFULL))) #define FMR_OWN_FREE FMR_OWNER(0, 1) /* free space */ #define FMR_OWN_UNKNOWN FMR_OWNER(0, 2) /* unknown owner */ #define FMR_OWN_METADATA FMR_OWNER(0, 3) /* metadata */ #define FS_IOC_GETFSMAP _IOWR('X', 59, struct fsmap_head) #define HAVE_GETFSMAP #endif /* HAVE_GETFSMAP */ #ifndef HAVE_MAP_SYNC #define MAP_SYNC 0 #define MAP_SHARED_VALIDATE 0 #else #include #include #endif /* HAVE_MAP_SYNC */ #endif /* __XFS_LINUX_H__ */ xfsprogs-5.3.0/include/list.h0000644000175000017500000001304213435336036016021 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2006 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIST_H__ #define __LIST_H__ /* * This undef is here because BSD 4.4 added some LIST_ macros into system * header file sys/queue.h. This header is included in many other system * headers and thus causes "macro redefined" warnings. * * As OS X is kind of a derivate of BSD, this affects OS X too. * * To use our own LIST_ macros (copied from kernel code), we have to * at first undefine the conflicting system macros. * */ #undef LIST_HEAD #undef LIST_HEAD_INIT /* * Simple, generic doubly-linked list implementation. */ struct list_head { struct list_head *next; struct list_head *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(list) list_head_init(list) static inline void list_head_init(struct list_head *list) { list->next = list->prev = list; } static inline void list_head_destroy(struct list_head *list) { list->next = list->prev = NULL; } static inline void __list_add(struct list_head *add, struct list_head *prev, struct list_head *next) { next->prev = add; add->next = next; add->prev = prev; prev->next = add; } static inline void list_add(struct list_head *add, struct list_head *head) { __list_add(add, head, head->next); } static inline void list_add_tail(struct list_head *add, struct list_head *head) { __list_add(add, head->prev, head); } static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); list_head_init(entry); } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } static inline int list_empty(const struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *prev, struct list_head *next) { struct list_head *first = list->next; struct list_head *last = list->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head, head->next); } static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head, head->next); list_head_init(list); } } #define list_entry(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, struct list_head *a, struct list_head *b)); #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /** * list_splice_tail_init - join two lists and reinitialise the emptied list * @list: the new list to add. * @head: the place to add it in the first list. * * Each of the lists is a queue. * The list at @list is reinitialised */ static inline void list_splice_tail_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head->prev, head); INIT_LIST_HEAD(list); } } /** * list_last_entry - get the last element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_head within the struct. * * Note, that list is expected to be not empty. */ #define list_last_entry(ptr, type, member) \ list_entry((ptr)->prev, type, member) /** * list_prev_entry - get the prev element in list * @pos: the type * to cursor * @member: the name of the list_head within the struct. */ #define list_prev_entry(pos, member) \ list_entry((pos)->member.prev, typeof(*(pos)), member) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_head within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_last_entry(head, typeof(*pos), member); \ &pos->member != (head); \ pos = list_prev_entry(pos, member)) #endif /* __LIST_H__ */ xfsprogs-5.3.0/include/parent.h0000644000175000017500000000054713435336036016345 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __PARENT_H__ #define __PARENT_H__ typedef struct parent { __u64 p_ino; __u32 p_gen; __u16 p_reclen; char p_name[1]; } parent_t; typedef struct parent_cursor { __u32 opaque[4]; /* an opaque cookie */ } parent_cursor_t; #endif xfsprogs-5.3.0/include/platform_defs.h.in0000644000175000017500000000375613570057155020315 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_PLATFORM_DEFS_H__ #define __XFS_PLATFORM_DEFS_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct filldir filldir_t; /* long and pointer must be either 32 bit or 64 bit */ #undef SIZEOF_LONG #undef SIZEOF_CHAR_P #define BITS_PER_LONG (SIZEOF_LONG * CHAR_BIT) /* Check whether to define umode_t ourselves. */ #ifndef HAVE_UMODE_T typedef unsigned short umode_t; #endif /* Define if you want gettext (I18N) support */ #undef ENABLE_GETTEXT #ifdef ENABLE_GETTEXT # include # define _(x) gettext(x) # define N_(x) x #else # define _(x) (x) # define N_(x) x # define textdomain(d) do { } while (0) # define bindtextdomain(d,dir) do { } while (0) #endif #include #define IRIX_DEV_BITSMAJOR 14 #define IRIX_DEV_BITSMINOR 18 #define IRIX_DEV_MAXMAJ 0x1ff #define IRIX_DEV_MAXMIN 0x3ffff #define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev) >> IRIX_DEV_BITSMINOR) \ & IRIX_DEV_MAXMAJ)) #define IRIX_DEV_MINOR(dev) ((int)((dev) & IRIX_DEV_MAXMIN)) #define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major) << IRIX_DEV_BITSMINOR) \ | (minor&IRIX_DEV_MAXMIN))) #define IRIX_DEV_TO_KDEVT(dev) makedev(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev)) #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #define max(a,b) (((a)>(b))?(a):(b)) #endif /* If param.h doesn't provide it, i.e. for Android */ #ifndef NBBY #define NBBY 8 #endif #ifdef DEBUG # define ASSERT(EX) assert(EX) #else # define ASSERT(EX) ((void) 0) #endif extern int platform_nproc(void); #endif /* __XFS_PLATFORM_DEFS_H__ */ xfsprogs-5.3.0/include/xfs.h0000644000175000017500000000135313435336036015650 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef __XFS_H__ #define __XFS_H__ #if defined(__linux__) #include #else # error unknown platform... have fun porting! #endif /* * make sure that any user of the xfs headers has a 64bit off_t type */ extern int xfs_assert_largefile[sizeof(off_t)-8]; /* * sparse kernel source annotations */ #ifndef __user #define __user #endif /* * kernel struct packing shortcut */ #ifndef __packed #define __packed __attribute__((packed)) #endif #ifndef BUILD_BUG_ON #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #endif #include #include #endif /* __XFS_H__ */ xfsprogs-5.3.0/include/xfs_arch.h0000644000175000017500000001660613435336036016654 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_ARCH_H__ #define __XFS_ARCH_H__ #if __BYTE_ORDER == __BIG_ENDIAN #define XFS_NATIVE_HOST 1 #else #undef XFS_NATIVE_HOST #endif #ifdef __CHECKER__ # ifndef __bitwise # define __bitwise __attribute__((bitwise)) # endif #define __force __attribute__((force)) #else # ifndef __bitwise # define __bitwise # endif #define __force #endif typedef __u16 __bitwise __le16; typedef __u32 __bitwise __le32; typedef __u64 __bitwise __le64; typedef __u16 __bitwise __be16; typedef __u32 __bitwise __be32; typedef __u64 __bitwise __be64; /* * Casts are necessary for constants, because we never know how for sure * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way. */ #define ___swab16(x) \ ({ \ __u16 __x = (x); \ ((__u16)( \ (((__u16)(__x) & (__u16)0x00ffU) << 8) | \ (((__u16)(__x) & (__u16)0xff00U) >> 8) )); \ }) #define ___swab32(x) \ ({ \ __u32 __x = (x); \ ((__u32)( \ (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \ (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | \ (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | \ (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \ }) #define ___swab64(x) \ ({ \ __u64 __x = (x); \ ((__u64)( \ (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \ }) #define ___constant_swab16(x) \ ((__u16)( \ (((__u16)(x) & (__u16)0x00ffU) << 8) | \ (((__u16)(x) & (__u16)0xff00U) >> 8) )) #define ___constant_swab32(x) \ ((__u32)( \ (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) #define ___constant_swab64(x) \ ((__u64)( \ (__u64)(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \ (__u64)(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \ (__u64)(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \ (__u64)(((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \ (__u64)(((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \ (__u64)(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ (__u64)(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \ (__u64)(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56) )) /* * provide defaults when no architecture-specific optimization is detected */ #ifndef __arch__swab16 # define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); }) #endif #ifndef __arch__swab32 # define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); }) #endif #ifndef __arch__swab64 # define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); }) #endif #ifndef __arch__swab16p # define __arch__swab16p(x) __arch__swab16(*(x)) #endif #ifndef __arch__swab32p # define __arch__swab32p(x) __arch__swab32(*(x)) #endif #ifndef __arch__swab64p # define __arch__swab64p(x) __arch__swab64(*(x)) #endif #ifndef __arch__swab16s # define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0) #endif #ifndef __arch__swab32s # define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0) #endif #ifndef __arch__swab64s # define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0) #endif /* * Allow constant folding */ # define __swab16(x) \ (__builtin_constant_p((__u16)(x)) ? \ ___constant_swab16((x)) : \ __fswab16((x))) # define __swab32(x) \ (__builtin_constant_p((__u32)(x)) ? \ ___constant_swab32((x)) : \ __fswab32((x))) # define __swab64(x) \ (__builtin_constant_p((__u64)(x)) ? \ ___constant_swab64((x)) : \ __fswab64((x))) static __inline__ __u16 __fswab16(__u16 x) { return (__extension__ __arch__swab16(x)); } static __inline__ __u16 __swab16p(__u16 *x) { return (__extension__ __arch__swab16p(x)); } static __inline__ void __swab16s(__u16 *addr) { (__extension__ ({__arch__swab16s(addr);})); } static __inline__ __u32 __fswab32(__u32 x) { return (__extension__ __arch__swab32(x)); } static __inline__ __u32 __swab32p(__u32 *x) { return (__extension__ __arch__swab32p(x)); } static __inline__ void __swab32s(__u32 *addr) { (__extension__ ({__arch__swab32s(addr);})); } static __inline__ __u64 __fswab64(__u64 x) { # ifdef __SWAB_64_THRU_32__ __u32 h = x >> 32; __u32 l = x & ((1ULL<<32)-1); return (((__u64)__swab32(l)) << 32) | ((__u64)(__swab32(h))); # else return (__extension__ __arch__swab64(x)); # endif } static __inline__ __u64 __swab64p(__u64 *x) { return (__extension__ __arch__swab64p(x)); } static __inline__ void __swab64s(__u64 *addr) { (__extension__ ({__arch__swab64s(addr);})); } #ifdef XFS_NATIVE_HOST #define cpu_to_be16(val) ((__force __be16)(__u16)(val)) #define cpu_to_be32(val) ((__force __be32)(__u32)(val)) #define cpu_to_be64(val) ((__force __be64)(__u64)(val)) #define be16_to_cpu(val) ((__force __u16)(__be16)(val)) #define be32_to_cpu(val) ((__force __u32)(__be32)(val)) #define be64_to_cpu(val) ((__force __u64)(__be64)(val)) #define cpu_to_le32(val) ((__force __be32)__swab32((__u32)(val))) #define le32_to_cpu(val) (__swab32((__force __u32)(__le32)(val))) #define __constant_cpu_to_le32(val) \ ((__force __le32)___constant_swab32((__u32)(val))) #define __constant_cpu_to_be32(val) \ ((__force __be32)(__u32)(val)) #else #define cpu_to_be16(val) ((__force __be16)__swab16((__u16)(val))) #define cpu_to_be32(val) ((__force __be32)__swab32((__u32)(val))) #define cpu_to_be64(val) ((__force __be64)__swab64((__u64)(val))) #define be16_to_cpu(val) (__swab16((__force __u16)(__be16)(val))) #define be32_to_cpu(val) (__swab32((__force __u32)(__be32)(val))) #define be64_to_cpu(val) (__swab64((__force __u64)(__be64)(val))) #define cpu_to_le32(val) ((__force __le32)(__u32)(val)) #define le32_to_cpu(val) ((__force __u32)(__le32)(val)) #define __constant_cpu_to_le32(val) \ ((__force __le32)(__u32)(val)) #define __constant_cpu_to_be32(val) \ ((__force __be32)___constant_swab32((__u32)(val))) #endif static inline void be16_add_cpu(__be16 *a, __s16 b) { *a = cpu_to_be16(be16_to_cpu(*a) + b); } static inline void be32_add_cpu(__be32 *a, __s32 b) { *a = cpu_to_be32(be32_to_cpu(*a) + b); } static inline void be64_add_cpu(__be64 *a, __s64 b) { *a = cpu_to_be64(be64_to_cpu(*a) + b); } static inline uint16_t get_unaligned_be16(void *p) { uint8_t *__p = p; return __p[0] << 8 | __p[1]; } static inline uint32_t get_unaligned_be32(void *p) { uint8_t *__p = p; return (uint32_t)__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3]; } static inline uint64_t get_unaligned_be64(void *p) { return (uint64_t)get_unaligned_be32(p) << 32 | get_unaligned_be32(p + 4); } static inline void put_unaligned_be16(uint16_t val, void *p) { uint8_t *__p = p; *__p++ = val >> 8; *__p++ = val; } static inline void put_unaligned_be32(uint32_t val, void *p) { uint8_t *__p = p; put_unaligned_be16(val >> 16, __p); put_unaligned_be16(val, __p + 2); } static inline void put_unaligned_be64(uint64_t val, void *p) { put_unaligned_be32(val >> 32, p); put_unaligned_be32(val, p + 4); } #endif /* __XFS_ARCH_H__ */ xfsprogs-5.3.0/include/xfs_btree_trace.h0000644000175000017500000000532513435336036020212 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2008 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_BTREE_TRACE_H__ #define __XFS_BTREE_TRACE_H__ struct xfs_btree_cur; struct xfs_buf; /* * Trace hooks. * i,j = integer (32 bit) * b = btree block buffer (xfs_buf_t) * p = btree ptr * r = btree record * k = btree key */ #ifdef XFS_BTREE_TRACE /* * Trace buffer entry types. */ #define XFS_BTREE_KTRACE_ARGBI 1 #define XFS_BTREE_KTRACE_ARGBII 2 #define XFS_BTREE_KTRACE_ARGFFFI 3 #define XFS_BTREE_KTRACE_ARGI 4 #define XFS_BTREE_KTRACE_ARGIPK 5 #define XFS_BTREE_KTRACE_ARGIPR 6 #define XFS_BTREE_KTRACE_ARGIK 7 #define XFS_BTREE_KTRACE_ARGR 8 #define XFS_BTREE_KTRACE_CUR 9 /* * Sub-types for cursor traces. */ #define XBT_ARGS 0 #define XBT_ENTRY 1 #define XBT_ERROR 2 #define XBT_EXIT 3 void xfs_btree_trace_argbi(const char *, struct xfs_btree_cur *, struct xfs_buf *, int, int); void xfs_btree_trace_argbii(const char *, struct xfs_btree_cur *, struct xfs_buf *, int, int, int); void xfs_btree_trace_argi(const char *, struct xfs_btree_cur *, int, int); void xfs_btree_trace_argipk(const char *, struct xfs_btree_cur *, int, union xfs_btree_ptr, union xfs_btree_key *, int); void xfs_btree_trace_argipr(const char *, struct xfs_btree_cur *, int, union xfs_btree_ptr, union xfs_btree_rec *, int); void xfs_btree_trace_argik(const char *, struct xfs_btree_cur *, int, union xfs_btree_key *, int); void xfs_btree_trace_argr(const char *, struct xfs_btree_cur *, union xfs_btree_rec *, int); void xfs_btree_trace_cursor(const char *, struct xfs_btree_cur *, int, int); #define XFS_BTREE_TRACE_ARGBI(c, b, i) \ xfs_btree_trace_argbi(__func__, c, b, i, __LINE__) #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) \ xfs_btree_trace_argbii(__func__, c, b, i, j, __LINE__) #define XFS_BTREE_TRACE_ARGI(c, i) \ xfs_btree_trace_argi(__func__, c, i, __LINE__) #define XFS_BTREE_TRACE_ARGIPK(c, i, p, k) \ xfs_btree_trace_argipk(__func__, c, i, p, k, __LINE__) #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) \ xfs_btree_trace_argipr(__func__, c, i, p, r, __LINE__) #define XFS_BTREE_TRACE_ARGIK(c, i, k) \ xfs_btree_trace_argik(__func__, c, i, k, __LINE__) #define XFS_BTREE_TRACE_ARGR(c, r) \ xfs_btree_trace_argr(__func__, c, r, __LINE__) #define XFS_BTREE_TRACE_CURSOR(c, t) \ xfs_btree_trace_cursor(__func__, c, t, __LINE__) #else #define XFS_BTREE_TRACE_ARGBI(c, b, i) #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) #define XFS_BTREE_TRACE_ARGI(c, i) #define XFS_BTREE_TRACE_ARGIPK(c, i, p, s) #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) #define XFS_BTREE_TRACE_ARGIK(c, i, k) #define XFS_BTREE_TRACE_ARGR(c, r) #define XFS_BTREE_TRACE_CURSOR(c, t) #endif /* XFS_BTREE_TRACE */ #endif /* __XFS_BTREE_TRACE_H__ */ xfsprogs-5.3.0/include/xfs_inode.h0000644000175000017500000001127113570057155017030 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_INODE_H__ #define __XFS_INODE_H__ /* These match kernel side includes */ #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" struct xfs_trans; struct xfs_mount; struct xfs_inode_log_item; struct xfs_dir_ops; /* * These are not actually used, they are only for userspace build * compatibility in code that looks at i_state */ #define I_DIRTY_TIME 0 #define I_DIRTY_TIME_EXPIRED 0 #define IS_I_VERSION(inode) (0) #define inode_maybe_inc_iversion(inode,flags) (0) /* * Inode interface. This fakes up a "VFS inode" to make the xfs_inode appear * similar to the kernel which now is used tohold certain parts of the on-disk * metadata. */ struct inode { mode_t i_mode; uint32_t i_nlink; xfs_dev_t i_rdev; /* This actually holds xfs_dev_t */ unsigned long i_state; /* Not actually used in userspace */ uint32_t i_generation; uint64_t i_version; struct timespec i_atime; struct timespec i_mtime; struct timespec i_ctime; }; typedef struct xfs_inode { struct cache_node i_node; struct xfs_mount *i_mount; /* fs mount struct ptr */ xfs_ino_t i_ino; /* inode number (agno/agino) */ struct xfs_imap i_imap; /* location for xfs_imap() */ struct xfs_buftarg i_dev; /* dev for this inode */ struct xfs_ifork *i_afp; /* attribute fork pointer */ struct xfs_ifork *i_cowfp; /* copy on write extents */ struct xfs_ifork i_df; /* data fork */ struct xfs_inode_log_item *i_itemp; /* logging information */ unsigned int i_delayed_blks; /* count of delay alloc blks */ struct xfs_icdinode i_d; /* most of ondisk inode */ xfs_extnum_t i_cnextents; /* # of extents in cow fork */ unsigned int i_cformat; /* format of cow fork */ xfs_fsize_t i_size; /* in-memory size */ const struct xfs_dir_ops *d_ops; /* directory ops vector */ struct xfs_ifork_ops *i_fork_ops; /* fork verifiers */ struct inode i_vnode; } xfs_inode_t; /* Convert from vfs inode to xfs inode */ static inline struct xfs_inode *XFS_I(struct inode *inode) { return container_of(inode, struct xfs_inode, i_vnode); } /* convert from xfs inode to vfs inode */ static inline struct inode *VFS_I(struct xfs_inode *ip) { return &ip->i_vnode; } /* We only have i_size in the xfs inode in userspace */ static inline loff_t i_size_read(struct inode *inode) { return XFS_I(inode)->i_size; } /* * wrappers around the mode checks to simplify code */ static inline bool XFS_ISREG(struct xfs_inode *ip) { return S_ISREG(VFS_I(ip)->i_mode); } static inline bool XFS_ISDIR(struct xfs_inode *ip) { return S_ISDIR(VFS_I(ip)->i_mode); } /* * For regular files we only update the on-disk filesize when actually * writing data back to disk. Until then only the copy in the VFS inode * is uptodate. */ static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip) { if (XFS_ISREG(ip)) return ip->i_size; return ip->i_d.di_size; } #define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) /* inode link counts */ static inline void set_nlink(struct inode *inode, uint32_t nlink) { inode->i_nlink = nlink; } static inline void inc_nlink(struct inode *inode) { inode->i_nlink++; } /* * Project quota id helpers (previously projid was 16bit only and using two * 16bit values to hold new 32bit projid was chosen to retain compatibility with * "old" filesystems). * * Copied here from xfs_inode.h because it has to be defined after the struct * xfs_inode... */ static inline prid_t xfs_get_projid(struct xfs_icdinode *id) { return (prid_t)id->di_projid_hi << 16 | id->di_projid_lo; } static inline void xfs_set_projid(struct xfs_icdinode *id, prid_t projid) { id->di_projid_hi = (uint16_t) (projid >> 16); id->di_projid_lo = (uint16_t) (projid & 0xffff); } static inline bool xfs_is_reflink_inode(struct xfs_inode *ip) { return ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK; } typedef struct cred { uid_t cr_uid; gid_t cr_gid; } cred_t; extern int libxfs_inode_alloc (struct xfs_trans **, struct xfs_inode *, mode_t, nlink_t, xfs_dev_t, struct cred *, struct fsxattr *, struct xfs_inode **); extern void libxfs_trans_inode_alloc_buf (struct xfs_trans *, struct xfs_buf *); extern void libxfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *); #define timespec64 timespec extern struct timespec64 current_time(struct inode *inode); /* Inode Cache Interfaces */ extern bool libxfs_inode_verify_forks(struct xfs_inode *ip); extern int libxfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, uint, struct xfs_inode **, struct xfs_ifork_ops *); extern void libxfs_irele(struct xfs_inode *ip); #endif /* __XFS_INODE_H__ */ xfsprogs-5.3.0/include/xfs_log_recover.h0000644000175000017500000000255613435336036020244 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_LOG_RECOVER_H__ #define __XFS_LOG_RECOVER_H__ /* * Macros, structures, prototypes for internal log manager use. */ #define XLOG_RHASH_BITS 4 #define XLOG_RHASH_SIZE 16 #define XLOG_RHASH_SHIFT 2 #define XLOG_RHASH(tid) \ ((((uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1)) #define XLOG_MAX_REGIONS_IN_ITEM (XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK / 2 + 1) /* * item headers are in ri_buf[0]. Additional buffers follow. */ typedef struct xlog_recover_item { struct list_head ri_list; int ri_type; int ri_cnt; /* count of regions found */ int ri_total; /* total regions */ xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ } xlog_recover_item_t; typedef struct xlog_recover { struct hlist_node r_list; xlog_tid_t r_log_tid; /* log's transaction id */ xfs_trans_header_t r_theader; /* trans header for partial */ int r_state; /* not needed */ xfs_lsn_t r_lsn; /* xact lsn */ struct list_head r_itemq; /* q for items */ } xlog_recover_t; #define ITEM_TYPE(i) (*(unsigned short *)(i)->ri_buf[0].i_addr) /* * This is the number of entries in the l_buf_cancel_table used during * recovery. */ #define XLOG_BC_TABLE_SIZE 64 #define XLOG_RECOVER_PASS1 1 #define XLOG_RECOVER_PASS2 2 #endif /* __XFS_LOG_RECOVER_H__ */ xfsprogs-5.3.0/include/xfs_metadump.h0000644000175000017500000000125413435336036017544 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2007 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XFS_METADUMP_H_ #define _XFS_METADUMP_H_ #define XFS_MD_MAGIC 0x5846534d /* 'XFSM' */ typedef struct xfs_metablock { __be32 mb_magic; __be16 mb_count; uint8_t mb_blocklog; uint8_t mb_info; /* followed by an array of xfs_daddr_t */ } xfs_metablock_t; /* These flags are informational only, not backwards compatible */ #define XFS_METADUMP_INFO_FLAGS (1 << 0) /* This image has informative flags */ #define XFS_METADUMP_OBFUSCATED (1 << 1) #define XFS_METADUMP_FULLBLOCKS (1 << 2) #define XFS_METADUMP_DIRTYLOG (1 << 3) #endif /* _XFS_METADUMP_H_ */ xfsprogs-5.3.0/include/xfs_mount.h0000644000175000017500000001530413570057155017075 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_MOUNT_H__ #define __XFS_MOUNT_H__ struct xfs_inode; struct xfs_buftarg; struct xfs_dir_ops; struct xfs_da_geometry; /* * Define a user-level mount structure with all we need * in order to make use of the numerous XFS_* macros. */ typedef struct xfs_mount { xfs_sb_t m_sb; /* copy of fs superblock */ #define m_icount m_sb.sb_icount #define m_ifree m_sb.sb_ifree #define m_fdblocks m_sb.sb_fdblocks /* * Bitsets of per-fs metadata that have been checked and/or are sick. * Callers must hold m_sb_lock to access these two fields. */ uint8_t m_fs_checked; uint8_t m_fs_sick; char *m_fsname; /* filesystem name */ int m_bsize; /* fs logical block size */ xfs_agnumber_t m_agfrotor; /* last ag where space found */ xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ xfs_agnumber_t m_maxagi; /* highest inode alloc group */ struct xfs_ino_geometry m_ino_geo; /* inode geometry */ uint m_rsumlevels; /* rt summary levels */ uint m_rsumsize; /* size of rt summary, bytes */ /* * Optional cache of rt summary level per bitmap block with the * invariant that m_rsum_cache[bbno] <= the minimum i for which * rsum[i][bbno] != 0. Reads and writes are serialized by the rsumip * inode lock. */ uint8_t *m_rsum_cache; struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ struct xfs_inode *m_rsumip; /* pointer to summary inode */ struct xfs_buftarg *m_ddev_targp; struct xfs_buftarg *m_logdev_targp; struct xfs_buftarg *m_rtdev_targp; #define m_dev m_ddev_targp #define m_logdev m_logdev_targp #define m_rtdev m_rtdev_targp uint8_t m_dircook_elog; /* log d-cookie entry bits */ uint8_t m_blkbit_log; /* blocklog + NBBY */ uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ uint8_t m_sectbb_log; /* sectorlog - BBSHIFT */ uint8_t m_agno_log; /* log #ag's */ uint m_blockmask; /* sb_blocksize-1 */ uint m_blockwsize; /* sb_blocksize in words */ uint m_blockwmask; /* blockwsize-1 */ uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */ uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */ uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */ uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */ uint m_rmap_mxr[2]; /* max rmap btree records */ uint m_rmap_mnr[2]; /* min rmap btree records */ uint m_refc_mxr[2]; /* max refc btree records */ uint m_refc_mnr[2]; /* min refc btree records */ uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ uint m_rmap_maxlevels; /* max rmap btree levels */ uint m_refc_maxlevels; /* max refc btree levels */ xfs_extlen_t m_ag_prealloc_blocks; /* reserved ag blocks */ uint m_alloc_set_aside; /* space we can't use */ uint m_ag_max_usable; /* max space per AG */ struct radix_tree_root m_perag_tree; uint m_flags; /* global mount flags */ bool m_finobt_nores; /* no per-AG finobt resv. */ uint m_qflags; /* quota status flags */ uint m_attroffset; /* inode attribute offset */ struct xfs_trans_resv m_resv; /* precomputed res values */ int m_dalign; /* stripe unit */ int m_swidth; /* stripe width */ const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */ struct xfs_da_geometry *m_dir_geo; /* directory block geometry */ struct xfs_da_geometry *m_attr_geo; /* attribute block geometry */ const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */ const struct xfs_dir_ops *m_nondir_inode_ops; /* !dir inode ops */ #define M_DIROPS(mp) ((mp)->m_dir_inode_ops) /* * anonymous struct to allow xfs_dquot_buf.c to compile. * Pointer is always null in userspace, so code does not use it at all */ struct { int qi_dqperchunk; } *m_quotainfo; /* * xlog is defined in libxlog and thus is not intialized by libxfs. This * allows an application to initialize and store a reference to the log * if warranted. */ struct xlog *m_log; /* log specific stuff */ } xfs_mount_t; #define M_IGEO(mp) (&(mp)->m_ino_geo) /* per-AG block reservation data structures*/ enum xfs_ag_resv_type { XFS_AG_RESV_NONE = 0, XFS_AG_RESV_AGFL, XFS_AG_RESV_METADATA, XFS_AG_RESV_RMAPBT, }; struct xfs_ag_resv { /* number of blocks originally reserved here */ xfs_extlen_t ar_orig_reserved; /* number of blocks reserved here */ xfs_extlen_t ar_reserved; /* number of blocks originally asked for */ xfs_extlen_t ar_asked; }; /* * Per-ag incore structure, copies of information in agf and agi, * to improve the performance of allocation group selection. */ typedef struct xfs_perag { struct xfs_mount *pag_mount; /* owner filesystem */ xfs_agnumber_t pag_agno; /* AG this structure belongs to */ atomic_t pag_ref; /* perag reference count */ char pagf_init; /* this agf's entry is initialized */ char pagi_init; /* this agi's entry is initialized */ char pagf_metadata; /* the agf is preferred to be metadata */ char pagi_inodeok; /* The agi is ok for inodes */ uint8_t pagf_levels[XFS_BTNUM_AGF]; /* # of levels in bno & cnt btree */ bool pagf_agflreset; /* agfl requires reset before use */ uint32_t pagf_flcount; /* count of blocks in freelist */ xfs_extlen_t pagf_freeblks; /* total free blocks */ xfs_extlen_t pagf_longest; /* longest free space */ uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */ xfs_agino_t pagi_freecount; /* number of free inodes */ xfs_agino_t pagi_count; /* number of allocated inodes */ /* * Inode allocation search lookup optimisation. * If the pagino matches, the search for new inodes * doesn't need to search the near ones again straight away */ xfs_agino_t pagl_pagino; xfs_agino_t pagl_leftrec; xfs_agino_t pagl_rightrec; int pagb_count; /* pagb slots in use */ /* Blocks reserved for all kinds of metadata. */ struct xfs_ag_resv pag_meta_resv; /* Blocks reserved for just AGFL-based metadata. */ struct xfs_ag_resv pag_rmapbt_resv; /* reference count */ uint8_t pagf_refcount_level; } xfs_perag_t; static inline struct xfs_ag_resv * xfs_perag_resv( struct xfs_perag *pag, enum xfs_ag_resv_type type) { switch (type) { case XFS_AG_RESV_METADATA: return &pag->pag_meta_resv; case XFS_AG_RESV_RMAPBT: return &pag->pag_rmapbt_resv; default: return NULL; } } #define LIBXFS_MOUNT_DEBUGGER 0x0001 #define LIBXFS_MOUNT_32BITINODES 0x0002 #define LIBXFS_MOUNT_32BITINOOPT 0x0004 #define LIBXFS_MOUNT_COMPAT_ATTR 0x0008 #define LIBXFS_MOUNT_ATTR2 0x0010 #define LIBXFS_MOUNT_WANT_CORRUPTED 0x0020 #define LIBXFS_BHASHSIZE(sbp) (1<<10) extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *, dev_t, dev_t, dev_t, int); extern void libxfs_umount (xfs_mount_t *); extern void libxfs_rtmount_destroy (xfs_mount_t *); #endif /* __XFS_MOUNT_H__ */ xfsprogs-5.3.0/include/xfs_multidisk.h0000644000175000017500000000373613435336036017744 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_MULTIDISK_H__ #define __XFS_MULTIDISK_H__ #define XFS_DFL_SB_VERSION_BITS \ (XFS_SB_VERSION_NLINKBIT | \ XFS_SB_VERSION_EXTFLGBIT | \ XFS_SB_VERSION_DIRV2BIT) #define XFS_DFL_BLOCKSIZE_LOG 12 /* 4096 byte blocks */ #define XFS_DINODE_DFL_LOG 8 /* 256 byte inodes */ #define XFS_DINODE_DFL_CRC_LOG 9 /* 512 byte inodes for CRCs */ #define XFS_MIN_DATA_BLOCKS 100 #define XFS_MIN_INODE_PERBLOCK 2 /* min inodes per block */ #define XFS_DFL_IMAXIMUM_PCT 25 /* max % of space for inodes */ #define XFS_MIN_REC_DIRSIZE 12 /* 4096 byte dirblocks (V2) */ #define XFS_DFL_LOG_FACTOR 5 /* default log size, factor */ /* with max trans reservation */ #define XFS_MAX_INODE_SIG_BITS 32 /* most significant bits in an * inode number that we'll * accept w/o warnings */ #define XFS_AG_BYTES(bblog) ((long long)BBSIZE << (bblog)) #define XFS_AG_MIN_BYTES ((XFS_AG_BYTES(15))) /* 16 MB */ #define XFS_AG_MAX_BYTES ((XFS_AG_BYTES(31))) /* 1 TB */ #define XFS_AG_MIN_BLOCKS(blog) (XFS_AG_MIN_BYTES >> (blog)) #define XFS_AG_MAX_BLOCKS(blog) ((XFS_AG_MAX_BYTES - 1) >> (blog)) #define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) /* * These values define what we consider a "multi-disk" filesystem. That is, a * filesystem that is likely to be made up of multiple devices, and hence have * some level of parallelism available to it at the IO level. */ #define XFS_MULTIDISK_AGLOG 5 /* 32 AGs */ #define XFS_NOMULTIDISK_AGLOG 2 /* 4 AGs */ #define XFS_MULTIDISK_AGCOUNT (1 << XFS_MULTIDISK_AGLOG) extern long long cvtnum(unsigned int blksize, unsigned int sectsize, const char *str); /* proto.c */ extern char *setup_proto (char *fname); extern void parse_proto (xfs_mount_t *mp, struct fsxattr *fsx, char **pp); extern void res_failed (int err); #endif /* __XFS_MULTIDISK_H__ */ xfsprogs-5.3.0/include/xfs_trace.h0000644000175000017500000003341313570057155017032 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2011 RedHat, Inc. * All Rights Reserved. */ #ifndef __TRACE_H__ #define __TRACE_H__ #define trace_xfs_agfl_reset(a,b,c,d) ((void) 0) #define trace_xfs_agfl_free_defer(a,b,c,d,e) ((void) 0) #define trace_xfs_alloc_exact_done(a) ((void) 0) #define trace_xfs_alloc_exact_notfound(a) ((void) 0) #define trace_xfs_alloc_exact_error(a) ((void) 0) #define trace_xfs_alloc_near_first(a) ((void) 0) #define trace_xfs_alloc_near_greater(a) ((void) 0) #define trace_xfs_alloc_near_lesser(a) ((void) 0) #define trace_xfs_alloc_near_error(a) ((void) 0) #define trace_xfs_alloc_near_noentry(a) ((void) 0) #define trace_xfs_alloc_near_busy(a) ((void) 0) #define trace_xfs_alloc_size_neither(a) ((void) 0) #define trace_xfs_alloc_size_noentry(a) ((void) 0) #define trace_xfs_alloc_size_nominleft(a) ((void) 0) #define trace_xfs_alloc_size_done(a) ((void) 0) #define trace_xfs_alloc_size_error(a) ((void) 0) #define trace_xfs_alloc_size_busy(a) ((void) 0) #define trace_xfs_alloc_small_freelist(a) ((void) 0) #define trace_xfs_alloc_small_notenough(a) ((void) 0) #define trace_xfs_alloc_small_done(a) ((void) 0) #define trace_xfs_alloc_small_error(a) ((void) 0) #define trace_xfs_alloc_vextent_badargs(a) ((void) 0) #define trace_xfs_alloc_vextent_nofix(a) ((void) 0) #define trace_xfs_alloc_vextent_noagbp(a) ((void) 0) #define trace_xfs_alloc_vextent_loopfailed(a) ((void) 0) #define trace_xfs_alloc_vextent_allfailed(a) ((void) 0) #define trace_xfs_log_recover_item_add_cont(a,b,c,d) ((void) 0) #define trace_xfs_log_recover_item_add(a,b,c,d) ((void) 0) #define trace_xfs_da_btree_corrupt(a,b) ((void) 0) #define trace_xfs_btree_corrupt(a,b) ((void) 0) #define trace_xfs_btree_updkeys(a,b,c) ((void) 0) #define trace_xfs_btree_overlapped_query_range(a,b,c) ((void) 0) #define trace_xfs_free_extent(a,b,c,d,e,f,g) ((void) 0) #define trace_xfs_agf(a,b,c,d) ((void) 0) #define trace_xfs_read_agf(a,b) ((void) 0) #define trace_xfs_alloc_read_agf(a,b) ((void) 0) #define trace_xfs_read_agi(a,b) ((void) 0) #define trace_xfs_ialloc_read_agi(a,b) ((void) 0) #define trace_xfs_irec_merge_pre(a,b,c,d,e,f) ((void) 0) #define trace_xfs_irec_merge_post(a,b,c,d) ((void) 0) #define trace_xfs_iext_insert(a,b,c,d) ((void) 0) #define trace_xfs_iext_remove(a,b,c,d) ((void) 0) #define trace_xfs_dir2_grow_inode(a,b) ((void) 0) #define trace_xfs_dir2_shrink_inode(a,b) ((void) 0) #define trace_xfs_dir2_leaf_to_node(a) ((void) 0) #define trace_xfs_dir2_leaf_to_block(a) ((void) 0) #define trace_xfs_dir2_leaf_addname(a) ((void) 0) #define trace_xfs_dir2_leaf_lookup(a) ((void) 0) #define trace_xfs_dir2_leaf_removename(a) ((void) 0) #define trace_xfs_dir2_leaf_replace(a) ((void) 0) #define trace_xfs_dir2_block_addname(a) ((void) 0) #define trace_xfs_dir2_block_to_leaf(a) ((void) 0) #define trace_xfs_dir2_block_to_sf(a) ((void) 0) #define trace_xfs_dir2_block_lookup(a) ((void) 0) #define trace_xfs_dir2_block_removename(a) ((void) 0) #define trace_xfs_dir2_block_replace(a) ((void) 0) #define trace_xfs_dir2_leafn_add(a,b) ((void) 0) #define trace_xfs_dir2_leafn_remove(a,b) ((void) 0) #define trace_xfs_dir2_leafn_moveents(a,b,c,d) ((void) 0) #define trace_xfs_dir2_node_to_leaf(a) ((void) 0) #define trace_xfs_dir2_node_addname(a) ((void) 0) #define trace_xfs_dir2_node_lookup(a) ((void) 0) #define trace_xfs_dir2_node_removename(a) ((void) 0) #define trace_xfs_dir2_node_replace(a) ((void) 0) #define trace_xfs_dir2_sf_to_block(a) ((void) 0) #define trace_xfs_dir2_sf_addname(a) ((void) 0) #define trace_xfs_dir2_sf_create(a) ((void) 0) #define trace_xfs_dir2_sf_lookup(a) ((void) 0) #define trace_xfs_dir2_sf_removename(a) ((void) 0) #define trace_xfs_dir2_sf_replace(a) ((void) 0) #define trace_xfs_dir2_sf_toino4(a) ((void) 0) #define trace_xfs_dir2_sf_toino8(a) ((void) 0) #define trace_xfs_da_node_create(a) ((void) 0) #define trace_xfs_da_split(a) ((void) 0) #define trace_xfs_attr_leaf_split_before(a) ((void) 0) #define trace_xfs_attr_leaf_split_after(a) ((void) 0) #define trace_xfs_da_root_split(a) ((void) 0) #define trace_xfs_da_node_split(a) ((void) 0) #define trace_xfs_da_node_rebalance(a) ((void) 0) #define trace_xfs_da_node_add(a) ((void) 0) #define trace_xfs_da_join(a) ((void) 0) #define trace_xfs_da_root_join(a) ((void) 0) #define trace_xfs_da_node_toosmall(a) ((void) 0) #define trace_xfs_da_fixhashpath(a) ((void) 0) #define trace_xfs_da_node_remove(a) ((void) 0) #define trace_xfs_da_node_unbalance(a) ((void) 0) #define trace_xfs_da_link_before(a) ((void) 0) #define trace_xfs_da_link_after(a) ((void) 0) #define trace_xfs_da_unlink_back(a) ((void) 0) #define trace_xfs_da_unlink_forward(a) ((void) 0) #define trace_xfs_da_path_shift(a) ((void) 0) #define trace_xfs_da_grow_inode(a) ((void) 0) #define trace_xfs_da_swap_lastblock(a) ((void) 0) #define trace_xfs_da_shrink_inode(a) ((void) 0) #define trace_xfs_attr_sf_create(a) ((void) 0) #define trace_xfs_attr_sf_add(a) ((void) 0) #define trace_xfs_attr_sf_remove(a) ((void) 0) #define trace_xfs_attr_sf_lookup(a) ((void) 0) #define trace_xfs_attr_sf_to_leaf(a) ((void) 0) #define trace_xfs_attr_leaf_to_sf(a) ((void) 0) #define trace_xfs_attr_leaf_to_node(a) ((void) 0) #define trace_xfs_attr_leaf_create(a) ((void) 0) #define trace_xfs_attr_leaf_split(a) ((void) 0) #define trace_xfs_attr_leaf_add_old(a) ((void) 0) #define trace_xfs_attr_leaf_add_new(a) ((void) 0) #define trace_xfs_attr_leaf_add(a) ((void) 0) #define trace_xfs_attr_leaf_add_work(a) ((void) 0) #define trace_xfs_attr_leaf_compact(a) ((void) 0) #define trace_xfs_attr_leaf_rebalance(a) ((void) 0) #define trace_xfs_attr_leaf_toosmall(a) ((void) 0) #define trace_xfs_attr_leaf_remove(a) ((void) 0) #define trace_xfs_attr_leaf_unbalance(a) ((void) 0) #define trace_xfs_attr_leaf_lookup(a) ((void) 0) #define trace_xfs_attr_leaf_clearflag(a) ((void) 0) #define trace_xfs_attr_leaf_setflag(a) ((void) 0) #define trace_xfs_attr_leaf_flipflags(a) ((void) 0) #define trace_xfs_attr_sf_addname(a) ((void) 0) #define trace_xfs_attr_leaf_addname(a) ((void) 0) #define trace_xfs_attr_leaf_replace(a) ((void) 0) #define trace_xfs_attr_leaf_removename(a) ((void) 0) #define trace_xfs_attr_leaf_get(a) ((void) 0) #define trace_xfs_attr_node_addname(a) ((void) 0) #define trace_xfs_attr_node_replace(a) ((void) 0) #define trace_xfs_attr_node_removename(a) ((void) 0) #define trace_xfs_attr_fillstate(a) ((void) 0) #define trace_xfs_attr_refillstate(a) ((void) 0) #define trace_xfs_attr_node_get(a) ((void) 0) #define trace_xfs_attr_rmtval_get(a) ((void) 0) #define trace_xfs_attr_rmtval_set(a) ((void) 0) #define trace_xfs_attr_rmtval_remove(a) ((void) 0) #define trace_xfs_bmap_pre_update(a,b,c,d) ((void) 0) #define trace_xfs_bmap_post_update(a,b,c,d) ((void) 0) #define trace_xfs_bunmap(a,b,c,d,e) ((void) 0) /* set c = c to avoid unused var warnings */ #define trace_xfs_read_extent(a,b,c,d) ((c) = (c)) #define trace_xfs_write_extent(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_get(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_get_tag(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_put(a,b,c,d) ((c) = (c)) #define trace_xfs_trans_alloc(a,b) ((void) 0) #define trace_xfs_trans_cancel(a,b) ((void) 0) #define trace_xfs_trans_brelse(a) ((void) 0) #define trace_xfs_trans_binval(a) ((void) 0) #define trace_xfs_trans_bjoin(a) ((void) 0) #define trace_xfs_trans_bhold(a) ((void) 0) #define trace_xfs_trans_bhold_release(a) ((void) 0) #define trace_xfs_trans_get_buf(a) ((void) 0) #define trace_xfs_trans_get_buf_recur(a) ((void) 0) #define trace_xfs_trans_log_buf(a) ((void) 0) #define trace_xfs_trans_getsb_recur(a) ((void) 0) #define trace_xfs_trans_getsb(a) ((void) 0) #define trace_xfs_trans_read_buf_recur(a) ((void) 0) #define trace_xfs_trans_read_buf(a) ((void) 0) #define trace_xfs_trans_commit(a,b) ((void) 0) #define trace_xfs_defer_cancel(a,b) ((void) 0) #define trace_xfs_defer_pending_commit(a,b) ((void) 0) #define trace_xfs_defer_pending_abort(a,b) ((void) 0) #define trace_xfs_defer_pending_finish(a,b) ((void) 0) #define trace_xfs_defer_trans_abort(a,b) ((void) 0) #define trace_xfs_defer_trans_roll(a,b) ((void) 0) #define trace_xfs_defer_trans_roll_error(a,b) ((void) 0) #define trace_xfs_defer_finish(a,b) ((void) 0) #define trace_xfs_defer_finish_error(a,b) ((void) 0) #define trace_xfs_defer_finish_done(a,b) ((void) 0) #define trace_xfs_defer_cancel_list(a,b) ((void) 0) #define trace_xfs_defer_create_intent(a,b) ((void) 0) #define trace_xfs_bmap_free_defer(...) ((void) 0) #define trace_xfs_bmap_free_deferred(...) ((void) 0) #define trace_xfs_rmap_map(...) ((void) 0) #define trace_xfs_rmap_map_error(...) ((void) 0) #define trace_xfs_rmap_map_done(...) ((void) 0) #define trace_xfs_rmap_unmap(...) ((void) 0) #define trace_xfs_rmap_unmap_error(...) ((void) 0) #define trace_xfs_rmap_unmap_done(...) ((void) 0) #define trace_xfs_rmap_insert(...) ((void) 0) #define trace_xfs_rmap_insert_error(...) ((void) 0) #define trace_xfs_rmap_delete(...) ((void) 0) #define trace_xfs_rmap_convert(...) ((void) 0) #define trace_xfs_rmap_convert_state(...) ((void) 0) #define trace_xfs_rmap_convert_done(...) ((void) 0) #define trace_xfs_rmap_convert_error(...) ((void) 0) #define trace_xfs_rmap_update(...) ((void) 0) #define trace_xfs_rmap_update_error(...) ((void) 0) #define trace_xfs_rmap_defer(...) ((void) 0) #define trace_xfs_rmap_deferred(...) ((void) 0) #define trace_xfs_rmap_find_right_neighbor_result(...) ((void) 0) #define trace_xfs_rmap_find_left_neighbor_result(...) ((void) 0) #define trace_xfs_rmap_lookup_le_range_result(...) ((void) 0) #define trace_xfs_rmapbt_free_block(...) ((void) 0) #define trace_xfs_rmapbt_alloc_block(...) ((void) 0) #define trace_xfs_ag_resv_critical(...) ((void) 0) #define trace_xfs_ag_resv_needed(...) ((void) 0) #define trace_xfs_ag_resv_free(...) ((void) 0) #define trace_xfs_ag_resv_free_error(...) ((void) 0) #define trace_xfs_ag_resv_init(...) ((void) 0) #define trace_xfs_ag_resv_init_error(...) ((void) 0) #define trace_xfs_ag_resv_alloc_extent(...) ((void) 0) #define trace_xfs_ag_resv_free_extent(...) ((void) 0) #define trace_xfs_refcount_lookup(...) ((void) 0) #define trace_xfs_refcount_get(...) ((void) 0) #define trace_xfs_refcount_update(...) ((void) 0) #define trace_xfs_refcount_update_error(...) ((void) 0) #define trace_xfs_refcount_insert(...) ((void) 0) #define trace_xfs_refcount_insert_error(...) ((void) 0) #define trace_xfs_refcount_delete(...) ((void) 0) #define trace_xfs_refcount_delete_error(...) ((void) 0) #define trace_xfs_refcountbt_free_block(...) ((void) 0) #define trace_xfs_refcountbt_alloc_block(...) ((void) 0) #define trace_xfs_refcount_rec_order_error(...) ((void) 0) #define trace_xfs_refcount_lookup(...) ((void) 0) #define trace_xfs_refcount_get(...) ((void) 0) #define trace_xfs_refcount_update(...) ((void) 0) #define trace_xfs_refcount_update_error(...) ((void) 0) #define trace_xfs_refcount_insert(...) ((void) 0) #define trace_xfs_refcount_insert_error(...) ((void) 0) #define trace_xfs_refcount_delete(...) ((void) 0) #define trace_xfs_refcount_delete_error(...) ((void) 0) #define trace_xfs_refcountbt_free_block(...) ((void) 0) #define trace_xfs_refcountbt_alloc_block(...) ((void) 0) #define trace_xfs_refcount_rec_order_error(...) ((void) 0) #define trace_xfs_refcount_split_extent(...) ((void) 0) #define trace_xfs_refcount_split_extent_error(...) ((void) 0) #define trace_xfs_refcount_merge_center_extents_error(...) ((void) 0) #define trace_xfs_refcount_merge_left_extent_error(...) ((void) 0) #define trace_xfs_refcount_merge_right_extent_error(...) ((void) 0) #define trace_xfs_refcount_find_left_extent(...) ((void) 0) #define trace_xfs_refcount_find_left_extent_error(...) ((void) 0) #define trace_xfs_refcount_find_right_extent(...) ((void) 0) #define trace_xfs_refcount_find_right_extent_error(...) ((void) 0) #define trace_xfs_refcount_merge_center_extents(...) ((void) 0) #define trace_xfs_refcount_merge_left_extent(...) ((void) 0) #define trace_xfs_refcount_merge_right_extent(...) ((void) 0) #define trace_xfs_refcount_modify_extent(...) ((void) 0) #define trace_xfs_refcount_modify_extent_error(...) ((void) 0) #define trace_xfs_refcount_adjust_error(...) ((void) 0) #define trace_xfs_refcount_increase(...) ((void) 0) #define trace_xfs_refcount_decrease(...) ((void) 0) #define trace_xfs_refcount_deferred(...) ((void) 0) #define trace_xfs_refcount_defer(...) ((void) 0) #define trace_xfs_refcount_finish_one_leftover(...) ((void) 0) #define trace_xfs_refcount_find_shared(...) ((void) 0) #define trace_xfs_refcount_find_shared_result(...) ((void) 0) #define trace_xfs_refcount_find_shared_error(...) ((void) 0) #define trace_xfs_bmap_remap_alloc(...) ((void) 0) #define trace_xfs_bmap_deferred(...) ((void) 0) #define trace_xfs_bmap_defer(...) ((void) 0) #define trace_xfs_refcount_adjust_cow_error(...) ((void) 0) #define trace_xfs_refcount_cow_increase(...) ((void) 0) #define trace_xfs_refcount_cow_decrease(...) ((void) 0) #define trace_xfs_refcount_recover_extent(...) ((void) 0) #define trace_xfs_rmap_find_left_neighbor_candidate(...) ((void) 0) #define trace_xfs_rmap_find_left_neighbor_query(...) ((void) 0) #define trace_xfs_rmap_find_left_neighbor_result(...) ((void) 0) #define trace_xfs_rmap_lookup_le_range_candidate(...) ((void) 0) #define trace_xfs_rmap_lookup_le_range(...) ((void) 0) #define trace_xfs_rmap_unmap(...) ((void) 0) #define trace_xfs_rmap_unmap_done(...) ((void) 0) #define trace_xfs_rmap_unmap_error(...) ((void) 0) #define trace_xfs_rmap_map(...) ((void) 0) #define trace_xfs_rmap_map_done(...) ((void) 0) #define trace_xfs_rmap_map_error(...) ((void) 0) #define trace_xfs_rmap_delete_error(...) ((void) 0) #define trace_xfs_fs_mark_healthy(a,b) ((void) 0) /* set c = c to avoid unused var warnings */ #define trace_xfs_perag_get(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_get_tag(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_put(a,b,c,d) ((c) = (c)) #endif /* __TRACE_H__ */ xfsprogs-5.3.0/include/xfs_trans.h0000644000175000017500000001166613570057155017071 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_TRANS_H__ #define __XFS_TRANS_H__ struct xfs_mount; struct xfs_buftarg; struct xfs_buf; struct xfs_buf_map; /* * Userspace Transaction interface */ typedef struct xfs_log_item { struct list_head li_trans; /* transaction list */ xfs_lsn_t li_lsn; /* last on-disk lsn */ struct xfs_mount *li_mountp; /* ptr to fs mount */ uint li_type; /* item type */ unsigned long li_flags; /* misc flags */ } xfs_log_item_t; #define XFS_LI_DIRTY 3 /* log item dirty in transaction */ typedef struct xfs_inode_log_item { xfs_log_item_t ili_item; /* common portion */ struct xfs_inode *ili_inode; /* inode pointer */ unsigned short ili_lock_flags; /* lock flags */ unsigned int ili_last_fields; /* fields when flushed*/ unsigned int ili_fields; /* fields to be logged */ unsigned int ili_fsync_fields; /* ignored by userspace */ } xfs_inode_log_item_t; typedef struct xfs_buf_log_item { xfs_log_item_t bli_item; /* common item structure */ struct xfs_buf *bli_buf; /* real buffer pointer */ unsigned int bli_flags; /* misc flags */ unsigned int bli_recur; /* recursion count */ xfs_buf_log_format_t __bli_format; /* in-log header */ } xfs_buf_log_item_t; #define XFS_BLI_DIRTY (1<<0) #define XFS_BLI_HOLD (1<<1) #define XFS_BLI_STALE (1<<2) #define XFS_BLI_INODE_ALLOC_BUF (1<<3) typedef struct xfs_qoff_logitem { xfs_log_item_t qql_item; /* common portion */ struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */ xfs_qoff_logformat_t qql_format; /* logged structure */ } xfs_qoff_logitem_t; #define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */ #define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */ typedef struct xfs_trans { unsigned int t_log_res; /* amt of log space resvd */ unsigned int t_log_count; /* count for perm log res */ unsigned int t_blk_res; /* # of blocks resvd */ xfs_fsblock_t t_firstblock; /* first block allocated */ struct xfs_mount *t_mountp; /* ptr to fs mount struct */ unsigned int t_blk_res_used; /* # of resvd blocks used */ unsigned int t_flags; /* misc flags */ long t_icount_delta; /* superblock icount change */ long t_ifree_delta; /* superblock ifree change */ long t_fdblocks_delta; /* superblock fdblocks chg */ long t_frextents_delta; /* superblock freextents chg */ struct list_head t_items; /* first log item desc chunk */ struct list_head t_dfops; /* deferred operations */ } xfs_trans_t; void xfs_trans_init(struct xfs_mount *); int xfs_trans_roll(struct xfs_trans **); int libxfs_trans_alloc(struct xfs_mount *mp, struct xfs_trans_res *resp, uint blocks, uint rtextents, uint flags, struct xfs_trans **tpp); int libxfs_trans_alloc_rollable(struct xfs_mount *mp, uint blocks, struct xfs_trans **tpp); int libxfs_trans_alloc_empty(struct xfs_mount *mp, struct xfs_trans **tpp); int libxfs_trans_commit(struct xfs_trans *); void libxfs_trans_cancel(struct xfs_trans *); /* cancel dfops associated with a transaction */ void xfs_defer_cancel(struct xfs_trans *); struct xfs_buf *libxfs_trans_getsb(struct xfs_trans *, struct xfs_mount *); void libxfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); void libxfs_trans_log_inode (struct xfs_trans *, struct xfs_inode *, uint); int libxfs_trans_roll_inode (struct xfs_trans **, struct xfs_inode *); void libxfs_trans_brelse(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_binval(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_bjoin(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_bhold(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_bhold_release(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint, uint); bool libxfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *); struct xfs_buf *libxfs_trans_get_buf_map(struct xfs_trans *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, xfs_buf_flags_t flags); int libxfs_trans_read_buf_map(struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, xfs_buf_flags_t flags, struct xfs_buf **bpp, const struct xfs_buf_ops *ops); static inline struct xfs_buf * libxfs_trans_get_buf( struct xfs_trans *tp, struct xfs_buftarg *btp, xfs_daddr_t blkno, int numblks, uint flags) { DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); return libxfs_trans_get_buf_map(tp, btp, &map, 1, flags); } static inline int libxfs_trans_read_buf( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buftarg *btp, xfs_daddr_t blkno, int numblks, xfs_buf_flags_t flags, struct xfs_buf **bpp, const struct xfs_buf_ops *ops) { DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); return libxfs_trans_read_buf_map(mp, tp, btp, &map, 1, flags, bpp, ops); } #endif /* __XFS_TRANS_H__ */ xfsprogs-5.3.0/include/xqm.h0000644000175000017500000001535513435336036015664 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 1995, 2001, 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XQM_H__ #define __XQM_H__ #include /* * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM). */ #define XQM_CMD(x) (('X'<<8)+(x)) /* note: forms first QCMD argument */ #define Q_XQUOTAON XQM_CMD(1) /* enable accounting/enforcement */ #define Q_XQUOTAOFF XQM_CMD(2) /* disable accounting/enforcement */ #define Q_XGETQUOTA XQM_CMD(3) /* get disk limits and usage */ #define Q_XSETQLIM XQM_CMD(4) /* set disk limits */ #define Q_XGETQSTAT XQM_CMD(5) /* get quota subsystem status */ #define Q_XQUOTARM XQM_CMD(6) /* free disk space used by dquots */ #define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */ #define Q_XGETQSTATV XQM_CMD(8) /* newer version of get quota */ #define Q_XGETNEXTQUOTA XQM_CMD(9) /* get disk limits and usage */ /* * fs_disk_quota structure: * * This contains the current quota information regarding a user/proj/group. * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of * 512 bytes. */ #define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ typedef struct fs_disk_quota { __s8 d_version; /* version of this structure */ __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ __u16 d_fieldmask; /* field specifier */ __u32 d_id; /* user, project, or group ID */ __u64 d_blk_hardlimit;/* absolute limit on disk blks */ __u64 d_blk_softlimit;/* preferred limit on disk blks */ __u64 d_ino_hardlimit;/* maximum # allocated inodes */ __u64 d_ino_softlimit;/* preferred inode limit */ __u64 d_bcount; /* # disk blocks owned by the user */ __u64 d_icount; /* # inodes owned by the user */ __s32 d_itimer; /* zero if within inode limits */ /* if not, we refuse service */ __s32 d_btimer; /* similar to above; for disk blocks */ __u16 d_iwarns; /* # warnings issued wrt num inodes */ __u16 d_bwarns; /* # warnings issued wrt disk blocks */ __s32 d_padding2; /* padding2 - for future use */ __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ __u64 d_rtbcount; /* # realtime blocks owned */ __s32 d_rtbtimer; /* similar to above; for RT disk blks */ __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ __s16 d_padding3; /* padding3 - for future use */ char d_padding4[8]; /* yet more padding */ } fs_disk_quota_t; /* * These fields are sent to Q_XSETQLIM to specify fields that need to change. */ #define FS_DQ_ISOFT (1<<0) #define FS_DQ_IHARD (1<<1) #define FS_DQ_BSOFT (1<<2) #define FS_DQ_BHARD (1<<3) #define FS_DQ_RTBSOFT (1<<4) #define FS_DQ_RTBHARD (1<<5) #define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) /* * These timers can only be set in super user's dquot. For others, timers are * automatically started and stopped. Superusers timer values set the limits * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values * defined below are used. * These values also apply only to the d_fieldmask field for Q_XSETQLIM. */ #define FS_DQ_BTIMER (1<<6) #define FS_DQ_ITIMER (1<<7) #define FS_DQ_RTBTIMER (1<<8) #define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) /* * Warning counts are set in both super user's dquot and others. For others, * warnings are set/cleared by the administrators (or automatically by going * below the soft limit). Superusers warning values set the warning limits * for the rest. In case these values are zero, the DQ_{F,B}WARNLIMIT values * defined below are used. * These values also apply only to the d_fieldmask field for Q_XSETQLIM. */ #define FS_DQ_BWARNS (1<<9) #define FS_DQ_IWARNS (1<<10) #define FS_DQ_RTBWARNS (1<<11) #define FS_DQ_WARNS_MASK (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS) /* * Various flags related to quotactl(2). Only relevant to XFS filesystems. */ #define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ #define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ #define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ #define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ #define XFS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */ #define XFS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */ #define XFS_USER_QUOTA (1<<0) /* user quota type */ #define XFS_PROJ_QUOTA (1<<1) /* project quota type */ #define XFS_GROUP_QUOTA (1<<2) /* group quota type */ /* * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. * Provides a centralized way to get meta information about the quota subsystem. * eg. space taken up for user and group quotas, number of dquots currently * incore. */ #define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ /* * Some basic information about 'quota files'. */ typedef struct fs_qfilestat { __u64 qfs_ino; /* inode number */ __u64 qfs_nblks; /* number of BBs 512-byte-blks */ __u32 qfs_nextents; /* number of extents */ } fs_qfilestat_t; typedef struct fs_quota_stat { __s8 qs_version; /* version number for future changes */ __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ __s8 qs_pad; /* unused */ fs_qfilestat_t qs_uquota; /* user quota storage information */ fs_qfilestat_t qs_gquota; /* group quota storage information */ __u32 qs_incoredqs; /* number of dquots incore */ __s32 qs_btimelimit; /* limit for blks timer */ __s32 qs_itimelimit; /* limit for inodes timer */ __s32 qs_rtbtimelimit;/* limit for rt blks timer */ __u16 qs_bwarnlimit; /* limit for num warnings */ __u16 qs_iwarnlimit; /* limit for num warnings */ } fs_quota_stat_t; #ifndef FS_QSTATV_VERSION1 #define FS_QSTATV_VERSION1 1 /* fs_quota_statv.qs_version */ #endif /* * Some basic information about 'quota files' for Q_XGETQSTATV command */ struct fs_qfilestatv { __u64 qfs_ino; /* inode number */ __u64 qfs_nblks; /* number of BBs 512-byte-blks */ __u32 qfs_nextents; /* number of extents */ __u32 qfs_pad; /* pad for 8-byte alignment */ }; struct fs_quota_statv { __s8 qs_version; /* version for future changes */ __u8 qs_pad1; /* pad for 16bit alignment */ __u16 qs_flags; /* FS_QUOTA_.* flags */ __u32 qs_incoredqs; /* number of dquots incore */ struct fs_qfilestatv qs_uquota; /* user quota information */ struct fs_qfilestatv qs_gquota; /* group quota information */ struct fs_qfilestatv qs_pquota; /* project quota information */ __s32 qs_btimelimit; /* limit for blks timer */ __s32 qs_itimelimit; /* limit for inodes timer */ __s32 qs_rtbtimelimit;/* limit for rt blks timer */ __u16 qs_bwarnlimit; /* limit for num warnings */ __u16 qs_iwarnlimit; /* limit for num warnings */ __u64 qs_pad2[8]; /* for future proofing */ }; #endif /* __XQM_H__ */ xfsprogs-5.3.0/io/Makefile0000644000175000017500000000542513570057155015331 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_io LSRCFILES = xfs_bmap.sh xfs_freeze.sh xfs_mkfile.sh HFILES = init.h io.h CFILES = init.c \ attr.c bmap.c bulkstat.c crc32cselftest.c cowextsize.c encrypt.c \ file.c freeze.c fsync.c getrusage.c imap.c inject.c label.c link.c \ mmap.c open.c parent.c pread.c prealloc.c pwrite.c reflink.c \ resblks.c scrub.c seek.c shutdown.c stat.c swapext.c sync.c \ truncate.c utimes.c LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) LLDFLAGS = -static-libtool-libs ifeq ($(HAVE_FADVISE),yes) CFILES += fadvise.c LCFLAGS += -DHAVE_FADVISE else LSRCFILES += fadvise.c endif ifeq ($(HAVE_MADVISE),yes) CFILES += madvise.c LCFLAGS += -DHAVE_MADVISE else LSRCFILES += madvise.c endif ifeq ($(HAVE_MINCORE),yes) CFILES += mincore.c LCFLAGS += -DHAVE_MINCORE else LSRCFILES += mincore.c endif ifeq ($(HAVE_SENDFILE),yes) CFILES += sendfile.c LCFLAGS += -DHAVE_SENDFILE else LSRCFILES += sendfile.c endif ifeq ($(HAVE_FIEMAP),yes) CFILES += fiemap.c LCFLAGS += -DHAVE_FIEMAP else LSRCFILES += fiemap.c endif ifeq ($(HAVE_COPY_FILE_RANGE),yes) CFILES += copy_file_range.c LCFLAGS += -DHAVE_COPY_FILE_RANGE endif ifeq ($(HAVE_SYNC_FILE_RANGE),yes) CFILES += sync_file_range.c LCFLAGS += -DHAVE_SYNC_FILE_RANGE endif ifeq ($(HAVE_SYNCFS),yes) LCFLAGS += -DHAVE_SYNCFS endif ifeq ($(ENABLE_READLINE),yes) LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP) endif ifeq ($(ENABLE_EDITLINE),yes) LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP) endif ifeq ($(HAVE_FALLOCATE),yes) LCFLAGS += -DHAVE_FALLOCATE endif # Also implies PWRITEV ifeq ($(HAVE_PREADV),yes) LCFLAGS += -DHAVE_PREADV -DHAVE_PWRITEV endif ifeq ($(HAVE_PWRITEV2),yes) LCFLAGS += -DHAVE_PWRITEV2 endif ifeq ($(HAVE_READDIR),yes) CFILES += readdir.c LCFLAGS += -DHAVE_READDIR endif ifeq ($(HAVE_MREMAP),yes) LCFLAGS += -DHAVE_MREMAP endif ifeq ($(HAVE_MAP_SYNC),yes) LCFLAGS += -DHAVE_MAP_SYNC endif ifeq ($(HAVE_DEVMAPPER),yes) CFILES += log_writes.c LLDLIBS += $(LIBDEVMAPPER) LCFLAGS += -DHAVE_DEVMAPPER endif # On linux we get fsmap from the system or define it ourselves # so include this unconditionally. If this reverts to only # the autoconf check w/o local definition, test HAVE_GETFSMAP CFILES += fsmap.c ifeq ($(HAVE_STATFS_FLAGS),yes) LCFLAGS += -DHAVE_STATFS_FLAGS endif default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 xfs_bmap.sh $(PKG_SBIN_DIR)/xfs_bmap $(LTINSTALL) -m 755 xfs_freeze.sh $(PKG_SBIN_DIR)/xfs_freeze $(LTINSTALL) -m 755 xfs_mkfile.sh $(PKG_SBIN_DIR)/xfs_mkfile install-dev: -include .dep xfsprogs-5.3.0/io/attr.c0000644000175000017500000002253713570057155015012 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t chattr_cmd; static cmdinfo_t lsattr_cmd; static unsigned int orflags; static unsigned int andflags; unsigned int recurse_all; unsigned int recurse_dir; static struct xflags { uint flag; char *shortname; char *longname; } xflags[] = { { FS_XFLAG_REALTIME, "r", "realtime" }, { FS_XFLAG_PREALLOC, "p", "prealloc" }, { FS_XFLAG_IMMUTABLE, "i", "immutable" }, { FS_XFLAG_APPEND, "a", "append-only" }, { FS_XFLAG_SYNC, "s", "sync" }, { FS_XFLAG_NOATIME, "A", "no-atime" }, { FS_XFLAG_NODUMP, "d", "no-dump" }, { FS_XFLAG_RTINHERIT, "t", "rt-inherit" }, { FS_XFLAG_PROJINHERIT, "P", "proj-inherit" }, { FS_XFLAG_NOSYMLINKS, "n", "nosymlinks" }, { FS_XFLAG_EXTSIZE, "e", "extsize" }, { FS_XFLAG_EXTSZINHERIT, "E", "extsz-inherit" }, { FS_XFLAG_NODEFRAG, "f", "no-defrag" }, { FS_XFLAG_FILESTREAM, "S", "filestream" }, { FS_XFLAG_DAX, "x", "dax" }, { FS_XFLAG_COWEXTSIZE, "C", "cowextsize" }, { FS_XFLAG_HASATTR, "X", "has-xattr" }, { 0, NULL, NULL } }; #define CHATTR_XFLAG_LIST "r"/*p*/"iasAdtPneEfSxC"/*X*/ static void lsattr_help(void) { printf(_( "\n" " displays the set of extended inode flags associated with the current file\n" "\n" " Each individual flag is displayed as a single character, in this order:\n" " r -- file data is stored in the realtime section\n" " p -- file has preallocated extents (cannot be changed using chattr)\n" " i -- immutable, file cannot be modified\n" " a -- append-only, file can only be appended to\n" " s -- all updates are synchronous\n" " A -- the access time is not updated for this inode\n" " d -- do not include this file in a dump of the filesystem\n" " t -- child created in this directory has realtime bit set by default\n" " P -- child created in this directory has parents project ID by default\n" " n -- symbolic links cannot be created in this directory\n" " e -- for non-realtime files, observe the inode extent size value\n" " E -- children created in this directory inherit the extent size value\n" " f -- do not include this file when defragmenting the filesystem\n" " S -- enable filestreams allocator for this directory\n" " x -- Use direct access (DAX) for data in this file\n" " C -- for files with shared blocks, observe the inode CoW extent size value\n" " X -- file has extended attributes (cannot be changed using chattr)\n" "\n" " Options:\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, but only list attributes on directories\n" " -a -- show all flags which can be set alongside those which are set\n" " -v -- verbose mode; show long names of flags, not single characters\n" "\n")); } static void chattr_help(void) { printf(_( "\n" " modifies the set of extended inode flags associated with the current file\n" "\n" " Examples:\n" " 'chattr +a' - sets the append-only flag\n" " 'chattr -a' - clears the append-only flag\n" "\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, only modifying attributes on directories\n" " +/-r -- set/clear the realtime flag\n" " +/-i -- set/clear the immutable flag\n" " +/-a -- set/clear the append-only flag\n" " +/-s -- set/clear the sync flag\n" " +/-A -- set/clear the no-atime flag\n" " +/-d -- set/clear the no-dump flag\n" " +/-t -- set/clear the realtime inheritance flag\n" " +/-P -- set/clear the project ID inheritance flag\n" " +/-n -- set/clear the no-symbolic-links flag\n" " +/-e -- set/clear the extent-size flag\n" " +/-E -- set/clear the extent-size inheritance flag\n" " +/-f -- set/clear the no-defrag flag\n" " +/-S -- set/clear the filestreams allocator flag\n" " +/-x -- set/clear the direct access (DAX) flag\n" " +/-C -- set/clear the CoW extent-size flag\n" " Note1: user must have certain capabilities to modify immutable/append-only.\n" " Note2: immutable/append-only files cannot be deleted; removing these files\n" " requires the immutable/append-only flag to be cleared first.\n" " Note3: the realtime flag can only be set if the filesystem has a realtime\n" " section, and the (regular) file must be empty when the flag is set.\n" "\n")); } void printxattr( uint flags, int verbose, int dofname, const char *fname, int dobraces, int doeol) { struct xflags *p; int first = 1; if (dobraces) fputs("[", stdout); for (p = xflags; p->flag; p++) { if (flags & p->flag) { if (verbose) { if (first) first = 0; else fputs(", ", stdout); fputs(p->longname, stdout); } else { fputs(p->shortname, stdout); } } else if (!verbose) { fputs("-", stdout); } } if (dobraces) fputs("]", stdout); if (dofname) printf(" %s ", fname); if (doeol) fputs("\n", stdout); } static int lsattr_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { struct fsxattr fsx; int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; if ((fd = open(path, O_RDONLY)) == -1) fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); else if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, path, strerror(errno)); else printxattr(fsx.fsx_xflags, 0, 1, path, 0, 1); if (fd != -1) close(fd); return 0; } static int lsattr_f( int argc, char **argv) { struct fsxattr fsx; char *name = file->name; int c, aflag = 0, vflag = 0; recurse_all = recurse_dir = 0; while ((c = getopt(argc, argv, "DRav")) != EOF) { switch (c) { case 'D': recurse_all = 0; recurse_dir = 1; break; case 'R': recurse_all = 1; recurse_dir = 0; break; case 'a': aflag = 1; vflag = 0; break; case 'v': aflag = 0; vflag = 1; break; default: return command_usage(&lsattr_cmd); } } if (recurse_all || recurse_dir) { nftw(name, lsattr_callback, 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); } else if ((xfsctl(name, file->fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, name, strerror(errno)); } else { printxattr(fsx.fsx_xflags, vflag, !aflag, name, vflag, !aflag); if (aflag) { fputs("/", stdout); printxattr(-1, 0, 1, name, 0, 1); } } return 0; } static int chattr_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { struct fsxattr attr; int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; if ((fd = open(path, O_RDONLY)) == -1) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &attr) < 0) { fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, path, strerror(errno)); } else { attr.fsx_xflags |= orflags; attr.fsx_xflags &= ~andflags; if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &attr) < 0) fprintf(stderr, _("%s: cannot set flags on %s: %s\n"), progname, path, strerror(errno)); } if (fd != -1) close(fd); return 0; } static int chattr_f( int argc, char **argv) { struct fsxattr attr; struct xflags *p; unsigned int i = 0; char *c, *name = file->name; orflags = andflags = 0; recurse_all = recurse_dir = 0; while (++i < argc) { if (argv[i][0] == '-' && argv[i][1] == 'R') { recurse_all = 1; } else if (argv[i][0] == '-' && argv[i][1] == 'D') { recurse_dir = 1; } else if (argv[i][0] == '+') { for (c = &argv[i][1]; *c; c++) { for (p = xflags; p->flag; p++) { if (strncmp(p->shortname, c, 1) == 0) { orflags |= p->flag; break; } } if (!p->flag) { fprintf(stderr, _("%s: unknown flag\n"), progname); return 0; } } } else if (argv[i][0] == '-') { for (c = &argv[i][1]; *c; c++) { for (p = xflags; p->flag; p++) { if (strncmp(p->shortname, c, 1) == 0) { andflags |= p->flag; break; } } if (!p->flag) { fprintf(stderr, _("%s: unknown flag\n"), progname); return 0; } } } else { fprintf(stderr, _("%s: bad chattr command, not +/-X\n"), progname); return 0; } } if (recurse_all || recurse_dir) { nftw(name, chattr_callback, 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); } else if (xfsctl(name, file->fd, FS_IOC_FSGETXATTR, &attr) < 0) { fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, name, strerror(errno)); } else { attr.fsx_xflags |= orflags; attr.fsx_xflags &= ~andflags; if (xfsctl(name, file->fd, FS_IOC_FSSETXATTR, &attr) < 0) fprintf(stderr, _("%s: cannot set flags on %s: %s\n"), progname, name, strerror(errno)); } return 0; } void attr_init(void) { chattr_cmd.name = "chattr"; chattr_cmd.cfunc = chattr_f; chattr_cmd.args = _("[-R|-D] [+/-"CHATTR_XFLAG_LIST"]"); chattr_cmd.argmin = 1; chattr_cmd.argmax = -1; chattr_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; chattr_cmd.oneline = _("change extended inode flags on the currently open file"); chattr_cmd.help = chattr_help; lsattr_cmd.name = "lsattr"; lsattr_cmd.cfunc = lsattr_f; lsattr_cmd.args = _("[-R|-D|-a|-v]"); lsattr_cmd.argmin = 0; lsattr_cmd.argmax = 1; lsattr_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; lsattr_cmd.oneline = _("list extended inode flags set on the currently open file"); lsattr_cmd.help = lsattr_help; add_command(&chattr_cmd); add_command(&lsattr_cmd); } xfsprogs-5.3.0/io/bmap.c0000644000175000017500000003116513570057155014754 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include "libfrog/fsgeom.h" static cmdinfo_t bmap_cmd; static void bmap_help(void) { printf(_( "\n" " prints the block mapping for an XFS file's data or attribute forks" "\n" " Example:\n" " 'bmap -vp' - tabular format verbose map, including unwritten extents\n" "\n" " bmap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -c -- prints the copy-on-write fork map instead of the data fork.\n" " This works only if the kernel was compiled in debug mode.\n" " -d -- suppresses a DMAPI read event, offline portions shown as holes.\n" " -e -- print delayed allocation extents.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " -n -- query n extents.\n" " -p -- obtain all unwritten extents as well (w/ -v show which are unwritten.)\n" " -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n" " Note: the bmap for non-regular files can be obtained provided the file\n" " was opened appropriately (in particular, must be opened read-only).\n" "\n")); } static int bmap_f( int argc, char **argv) { struct fsxattr fsx; struct getbmapx *map; struct xfs_fsop_geom fsgeo; int map_size; int loop = 0; int flg = 0; int aflag = 0; int cflag = 0; int lflag = 0; int nflag = 0; int pflag = 0; int vflag = 0; int is_rt = 0; int bmv_iflags = 0; /* flags for XFS_IOC_GETBMAPX */ int i = 0; int c; int egcnt; while ((c = getopt(argc, argv, "acdeln:pv")) != EOF) { switch (c) { case 'a': /* Attribute fork. */ bmv_iflags |= BMV_IF_ATTRFORK; aflag = 1; break; case 'c': /* CoW fork. */ bmv_iflags |= BMV_IF_COWFORK | BMV_IF_DELALLOC; cflag = 1; break; case 'e': bmv_iflags |= BMV_IF_DELALLOC; break; case 'l': /* list number of blocks with each extent */ lflag = 1; break; case 'n': /* number of extents specified */ nflag = atoi(optarg); break; case 'd': /* do not recall possibly offline DMAPI files */ bmv_iflags |= BMV_IF_NO_DMAPI_READ; break; case 'p': /* report unwritten preallocated blocks */ pflag = 1; bmv_iflags |= BMV_IF_PREALLOC; break; case 'v': /* Verbose output */ vflag++; break; default: return command_usage(&bmap_cmd); } } if (aflag || cflag) bmv_iflags &= ~(BMV_IF_PREALLOC|BMV_IF_NO_DMAPI_READ); if (vflag) { c = -xfrog_geometry(file->fd, &fsgeo); if (c) { fprintf(stderr, _("%s: can't get geometry [\"%s\"]: %s\n"), progname, file->name, strerror(c)); exitcode = 1; return 0; } c = xfsctl(file->name, file->fd, FS_IOC_FSGETXATTR, &fsx); if (c < 0) { fprintf(stderr, _("%s: cannot read attrs on \"%s\": %s\n"), progname, file->name, strerror(errno)); exitcode = 1; return 0; } if (fsx.fsx_xflags == FS_XFLAG_REALTIME) { /* * ag info not applicable to rt, continue * without ag output. */ is_rt = 1; } } map_size = nflag ? nflag+2 : 32; /* initial guess - 32 */ map = malloc(map_size*sizeof(*map)); if (map == NULL) { fprintf(stderr, _("%s: malloc of %d bytes failed.\n"), progname, (int)(map_size * sizeof(*map))); exitcode = 1; return 0; } /* Try the xfsctl(XFS_IOC_GETBMAPX) for the number of extents specified * by nflag, or the initial guess number of extents (32). * * If there are more extents than we guessed, use xfsctl * (FS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more * space based on this count, and try again. * * If the initial FGETBMAPX attempt returns EINVAL, this may mean * that we tried the FGETBMAPX on a zero length file. If we get * EINVAL, check the length with fstat() and return "no extents" * if the length == 0. * * Why not do the xfsctl(FS_IOC_FSGETXATTR[A]) first? Two reasons: * (1) The extent count may be wrong for a file with delayed * allocation blocks. The XFS_IOC_GETBMAPX forces the real * allocation and fixes up the extent count. * (2) For XFS_IOC_GETBMAP[X] on a DMAPI file that has been moved * offline by a DMAPI application (e.g., DMF) the * FS_IOC_FSGETXATTR only reflects the extents actually online. * Doing XFS_IOC_GETBMAPX call first forces that data blocks online * and then everything proceeds normally (see PV #545725). * * If you don't want this behavior on a DMAPI offline file, * try the "-d" option which sets the BMV_IF_NO_DMAPI_READ * iflag for XFS_IOC_GETBMAPX. */ do { /* loop a miximum of two times */ memset(map, 0, sizeof(*map)); /* zero header */ map->bmv_length = -1; map->bmv_count = map_size; map->bmv_iflags = bmv_iflags; i = xfsctl(file->name, file->fd, XFS_IOC_GETBMAPX, map); if (i < 0) { if ( errno == EINVAL && !aflag && filesize() == 0) { break; } else { fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETBMAPX)" " iflags=0x%x [\"%s\"]: %s\n"), progname, map->bmv_iflags, file->name, strerror(errno)); free(map); exitcode = 1; return 0; } } if (nflag) break; if (map->bmv_entries < map->bmv_count-1) break; /* Get number of extents from xfsctl FS_IOC_FSGETXATTR[A] * syscall. */ i = xfsctl(file->name, file->fd, aflag ? XFS_IOC_FSGETXATTRA : FS_IOC_FSGETXATTR, &fsx); if (i < 0) { fprintf(stderr, "%s: xfsctl(FS_IOC_FSGETXATTR%s) " "[\"%s\"]: %s\n", progname, aflag ? "A" : "", file->name, strerror(errno)); free(map); exitcode = 1; return 0; } if (2 * fsx.fsx_nextents > map_size) { map_size = 2 * fsx.fsx_nextents + 1; map = realloc(map, map_size*sizeof(*map)); if (map == NULL) { fprintf(stderr, _("%s: cannot realloc %d bytes\n"), progname, (int)(map_size*sizeof(*map))); exitcode = 1; return 0; } } } while (++loop < 2); if (!nflag) { if (map->bmv_entries <= 0) { printf(_("%s: no extents\n"), file->name); free(map); return 0; } } egcnt = nflag ? min(nflag, map->bmv_entries) : map->bmv_entries; printf("%s:\n", file->name); if (!vflag) { for (i = 0; i < egcnt; i++) { printf("\t%d: [%lld..%lld]: ", i, (long long) map[i + 1].bmv_offset, (long long)(map[i + 1].bmv_offset + map[i + 1].bmv_length - 1LL)); if (map[i + 1].bmv_block == -1) printf(_("hole")); else if (map[i + 1].bmv_block == -2) printf(_("delalloc")); else { printf("%lld..%lld", (long long) map[i + 1].bmv_block, (long long)(map[i + 1].bmv_block + map[i + 1].bmv_length - 1LL)); } if (lflag) printf(_(" %lld blocks\n"), (long long)map[i+1].bmv_length); else printf("\n"); } } else { /* * Verbose mode displays: * extent: [startoffset..endoffset]: startblock..endblock \ * ag# (agoffset..agendoffset) totalbbs */ #define MINRANGE_WIDTH 16 #define MINAG_WIDTH 2 #define MINTOT_WIDTH 5 #define NFLG 6 /* count of flags */ #define FLG_NULL 0000000 /* Null flag */ #define FLG_SHARED 0100000 /* shared extent */ #define FLG_PRE 0010000 /* Unwritten extent */ #define FLG_BSU 0001000 /* Not on begin of stripe unit */ #define FLG_ESU 0000100 /* Not on end of stripe unit */ #define FLG_BSW 0000010 /* Not on begin of stripe width */ #define FLG_ESW 0000001 /* Not on end of stripe width */ int agno; off64_t agoff, bbperag; int foff_w, boff_w, aoff_w, tot_w, agno_w; char rbuf[32], bbuf[32], abuf[32]; int sunit, swidth; foff_w = boff_w = aoff_w = MINRANGE_WIDTH; tot_w = MINTOT_WIDTH; if (is_rt) sunit = swidth = bbperag = 0; else { bbperag = (off64_t)fsgeo.agblocks * (off64_t)fsgeo.blocksize / BBSIZE; sunit = (fsgeo.sunit * fsgeo.blocksize) / BBSIZE; swidth = (fsgeo.swidth * fsgeo.blocksize) / BBSIZE; } flg = sunit | pflag; /* * Go through the extents and figure out the width * needed for all columns. */ for (i = 0; i < egcnt; i++) { snprintf(rbuf, sizeof(rbuf), "[%lld..%lld]:", (long long) map[i + 1].bmv_offset, (long long)(map[i + 1].bmv_offset + map[i + 1].bmv_length - 1LL)); if (map[i + 1].bmv_oflags & BMV_OF_PREALLOC) flg = 1; if (map[i + 1].bmv_block == -1) { foff_w = max(foff_w, strlen(rbuf)); tot_w = max(tot_w, numlen(map[i+1].bmv_length, 10)); } else { snprintf(bbuf, sizeof(bbuf), "%lld..%lld", (long long) map[i + 1].bmv_block, (long long)(map[i + 1].bmv_block + map[i + 1].bmv_length - 1LL)); boff_w = max(boff_w, strlen(bbuf)); if (!is_rt) { agno = map[i + 1].bmv_block / bbperag; agoff = map[i + 1].bmv_block - (agno * bbperag); snprintf(abuf, sizeof(abuf), "(%lld..%lld)", (long long)agoff, (long long)(agoff + map[i + 1].bmv_length - 1LL)); aoff_w = max(aoff_w, strlen(abuf)); } else aoff_w = 0; foff_w = max(foff_w, strlen(rbuf)); tot_w = max(tot_w, numlen(map[i+1].bmv_length, 10)); } } agno_w = is_rt ? 0 : max(MINAG_WIDTH, numlen(fsgeo.agcount, 10)); printf("%4s: %-*s %-*s %*s %-*s %*s%s\n", _("EXT"), foff_w, _("FILE-OFFSET"), boff_w, is_rt ? _("RT-BLOCK-RANGE") : _("BLOCK-RANGE"), agno_w, is_rt ? "" : _("AG"), aoff_w, is_rt ? "" : _("AG-OFFSET"), tot_w, _("TOTAL"), flg ? _(" FLAGS") : ""); for (i = 0; i < egcnt; i++) { flg = FLG_NULL; if (map[i + 1].bmv_oflags & BMV_OF_PREALLOC) { flg |= FLG_PRE; } if (map[i + 1].bmv_oflags & BMV_OF_SHARED) flg |= FLG_SHARED; if (map[i + 1].bmv_oflags & BMV_OF_DELALLOC) map[i + 1].bmv_block = -2; /* * If striping enabled, determine if extent starts/ends * on a stripe unit boundary. */ if (sunit) { if (map[i + 1].bmv_block % sunit != 0) { flg |= FLG_BSU; } if (((map[i + 1].bmv_block + map[i + 1].bmv_length ) % sunit ) != 0) { flg |= FLG_ESU; } if (map[i + 1].bmv_block % swidth != 0) { flg |= FLG_BSW; } if (((map[i + 1].bmv_block + map[i + 1].bmv_length ) % swidth ) != 0) { flg |= FLG_ESW; } } snprintf(rbuf, sizeof(rbuf), "[%lld..%lld]:", (long long) map[i + 1].bmv_offset, (long long)(map[i + 1].bmv_offset + map[i + 1].bmv_length - 1LL)); if (map[i + 1].bmv_block == -1) { printf("%4d: %-*s %-*s %*s %-*s %*lld\n", i, foff_w, rbuf, boff_w, _("hole"), agno_w, "", aoff_w, "", tot_w, (long long)map[i+1].bmv_length); } else if (map[i + 1].bmv_block == -2) { printf("%4d: %-*s %-*s %*s %-*s %*lld\n", i, foff_w, rbuf, boff_w, _("delalloc"), agno_w, "", aoff_w, "", tot_w, (long long)map[i+1].bmv_length); } else { snprintf(bbuf, sizeof(bbuf), "%lld..%lld", (long long) map[i + 1].bmv_block, (long long)(map[i + 1].bmv_block + map[i + 1].bmv_length - 1LL)); printf("%4d: %-*s %-*s", i, foff_w, rbuf, boff_w, bbuf); if (!is_rt) { agno = map[i + 1].bmv_block / bbperag; agoff = map[i + 1].bmv_block - (agno * bbperag); snprintf(abuf, sizeof(abuf), "(%lld..%lld)", (long long)agoff, (long long)(agoff + map[i + 1].bmv_length - 1LL)); printf(" %*d %-*s", agno_w, agno, aoff_w, abuf); } else printf(" "); printf(" %*lld", tot_w, (long long)map[i+1].bmv_length); if (flg == FLG_NULL && !pflag) { printf("\n"); } else { printf(" %-*.*o\n", NFLG, NFLG, flg); } } } if ((flg || pflag) && vflag > 1) { printf(_(" FLAG Values:\n")); printf(_(" %*.*o Shared extent\n"), NFLG+1, NFLG+1, FLG_SHARED); printf(_(" %*.*o Unwritten preallocated extent\n"), NFLG+1, NFLG+1, FLG_PRE); printf(_(" %*.*o Doesn't begin on stripe unit\n"), NFLG+1, NFLG+1, FLG_BSU); printf(_(" %*.*o Doesn't end on stripe unit\n"), NFLG+1, NFLG+1, FLG_ESU); printf(_(" %*.*o Doesn't begin on stripe width\n"), NFLG+1, NFLG+1, FLG_BSW); printf(_(" %*.*o Doesn't end on stripe width\n"), NFLG+1, NFLG+1, FLG_ESW); } } free(map); return 0; } void bmap_init(void) { bmap_cmd.name = "bmap"; bmap_cmd.cfunc = bmap_f; bmap_cmd.argmin = 0; bmap_cmd.argmax = -1; bmap_cmd.flags = CMD_NOMAP_OK; bmap_cmd.args = _("[-adlpv] [-n nx]"); bmap_cmd.oneline = _("print block mapping for an XFS file"); bmap_cmd.help = bmap_help; add_command(&bmap_cmd); } xfsprogs-5.3.0/io/bulkstat.c0000644000175000017500000002543413570057155015670 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include "platform_defs.h" #include "command.h" #include "init.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" #include "libfrog/paths.h" #include "io.h" #include "input.h" static void dump_bulkstat_time( const char *tag, uint64_t sec, uint32_t nsec) { printf("\t%s = %"PRIu64".%"PRIu32"\n", tag, sec, nsec); } static void dump_bulkstat( struct xfs_bulkstat *bstat) { printf("bs_ino = %"PRIu64"\n", bstat->bs_ino); printf("\tbs_size = %"PRIu64"\n", bstat->bs_size); printf("\tbs_blocks = %"PRIu64"\n", bstat->bs_blocks); printf("\tbs_xflags = 0x%"PRIx64"\n", bstat->bs_xflags); dump_bulkstat_time("bs_atime", bstat->bs_atime, bstat->bs_atime_nsec); dump_bulkstat_time("bs_ctime", bstat->bs_ctime, bstat->bs_ctime_nsec); dump_bulkstat_time("bs_mtime", bstat->bs_mtime, bstat->bs_mtime_nsec); dump_bulkstat_time("bs_btime", bstat->bs_btime, bstat->bs_btime_nsec); printf("\tbs_gen = 0x%"PRIx32"\n", bstat->bs_gen); printf("\tbs_uid = %"PRIu32"\n", bstat->bs_uid); printf("\tbs_gid = %"PRIu32"\n", bstat->bs_gid); printf("\tbs_projectid = %"PRIu32"\n", bstat->bs_projectid); printf("\tbs_blksize = %"PRIu32"\n", bstat->bs_blksize); printf("\tbs_rdev = %"PRIu32"\n", bstat->bs_rdev); printf("\tbs_cowextsize_blks = %"PRIu32"\n", bstat->bs_cowextsize_blks); printf("\tbs_extsize_blks = %"PRIu32"\n", bstat->bs_extsize_blks); printf("\tbs_nlink = %"PRIu32"\n", bstat->bs_nlink); printf("\tbs_extents = %"PRIu32"\n", bstat->bs_extents); printf("\tbs_aextents = %"PRIu32"\n", bstat->bs_aextents); printf("\tbs_version = %"PRIu16"\n", bstat->bs_version); printf("\tbs_forkoff = %"PRIu16"\n", bstat->bs_forkoff); printf("\tbs_sick = 0x%"PRIx16"\n", bstat->bs_sick); printf("\tbs_checked = 0x%"PRIx16"\n", bstat->bs_checked); printf("\tbs_mode = 0%"PRIo16"\n", bstat->bs_mode); }; static void bulkstat_help(void) { printf(_( "Bulk-queries the filesystem for inode stat information and prints it.\n" "\n" " -a Only iterate this AG.\n" " -d Print debugging output.\n" " -e Stop after this inode.\n" " -n Ask for this many results at once.\n" " -s Inode to start with.\n" " -v Use this version of the ioctl (1 or 5).\n")); } static void set_xfd_flags( struct xfs_fd *xfd, uint32_t ver) { switch (ver) { case 1: xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V1; break; case 5: xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V5; break; default: break; } } static int bulkstat_f( int argc, char **argv) { struct xfs_fd xfd = XFS_FD_INIT(file->fd); struct xfs_bulkstat_req *breq; uint64_t startino = 0; uint64_t endino = -1ULL; uint32_t batch_size = 4096; uint32_t agno = 0; uint32_t ver = 0; bool has_agno = false; bool debug = false; unsigned int i; int c; int ret; while ((c = getopt(argc, argv, "a:de:n:s:v:")) != -1) { switch (c) { case 'a': agno = cvt_u32(optarg, 10); if (errno) { perror(optarg); return 1; } has_agno = true; break; case 'd': debug = true; break; case 'e': endino = cvt_u64(optarg, 10); if (errno) { perror(optarg); return 1; } break; case 'n': batch_size = cvt_u32(optarg, 10); if (errno) { perror(optarg); return 1; } break; case 's': startino = cvt_u64(optarg, 10); if (errno) { perror(optarg); return 1; } break; case 'v': ver = cvt_u32(optarg, 10); if (errno) { perror(optarg); return 1; } if (ver != 1 && ver != 5) { fprintf(stderr, "version must be 1 or 5.\n"); return 1; } break; default: bulkstat_help(); return 0; } } if (optind != argc) { bulkstat_help(); return 0; } ret = -xfd_prepare_geometry(&xfd); if (ret) { xfrog_perror(ret, "xfd_prepare_geometry"); exitcode = 1; return 0; } ret = -xfrog_bulkstat_alloc_req(batch_size, startino, &breq); if (ret) { xfrog_perror(ret, "alloc bulkreq"); exitcode = 1; return 0; } if (has_agno) xfrog_bulkstat_set_ag(breq, agno); set_xfd_flags(&xfd, ver); while ((ret = -xfrog_bulkstat(&xfd, breq)) == 0) { if (debug) printf( _("bulkstat: startino=%lld flags=0x%x agno=%u ret=%d icount=%u ocount=%u\n"), (long long)breq->hdr.ino, (unsigned int)breq->hdr.flags, (unsigned int)breq->hdr.agno, ret, (unsigned int)breq->hdr.icount, (unsigned int)breq->hdr.ocount); if (breq->hdr.ocount == 0) break; for (i = 0; i < breq->hdr.ocount; i++) { if (breq->bulkstat[i].bs_ino > endino) break; dump_bulkstat(&breq->bulkstat[i]); } } if (ret) { xfrog_perror(ret, "xfrog_bulkstat"); exitcode = 1; } free(breq); return 0; } static void bulkstat_single_help(void) { printf(_( "Queries the filesystem for a single inode's stat information and prints it.\n" "If a given inode is not allocated, information about the next allocated \n" "inode will be printed instead.\n" "\n" " -v (ver) Use this version of the ioctl (1 or 5).\n" " -d Print debugging information.\n" "\n" "Pass in inode numbers or a special inode name:\n" " root Root directory.\n")); } struct single_map { const char *tag; uint64_t code; }; struct single_map tags[] = { {"root", XFS_BULK_IREQ_SPECIAL_ROOT}, {NULL, 0}, }; static int bulkstat_single_f( int argc, char **argv) { struct xfs_fd xfd = XFS_FD_INIT(file->fd); struct xfs_bulkstat bulkstat; unsigned long ver = 0; unsigned int i; bool debug = false; int c; int ret; while ((c = getopt(argc, argv, "dv:")) != -1) { switch (c) { case 'd': debug = true; break; case 'v': errno = 0; ver = strtoull(optarg, NULL, 10); if (errno) { perror(optarg); return 1; } if (ver != 1 && ver != 5) { fprintf(stderr, "version must be 1 or 5.\n"); return 1; } break; default: bulkstat_single_help(); return 0; } } ret = -xfd_prepare_geometry(&xfd); if (ret) { xfrog_perror(ret, "xfd_prepare_geometry"); exitcode = 1; return 0; } set_xfd_flags(&xfd, ver); for (i = optind; i < argc; i++) { struct single_map *sm = tags; uint64_t ino; unsigned int flags = 0; /* Try to look up our tag... */ for (sm = tags; sm->tag; sm++) { if (!strcmp(argv[i], sm->tag)) { ino = sm->code; flags |= XFS_BULK_IREQ_SPECIAL; break; } } /* ...or else it's an inode number. */ if (sm->tag == NULL) { errno = 0; ino = strtoull(argv[i], NULL, 10); if (errno) { perror(argv[i]); exitcode = 1; return 0; } } ret = -xfrog_bulkstat_single(&xfd, ino, flags, &bulkstat); if (ret) { xfrog_perror(ret, "xfrog_bulkstat_single"); continue; } if (debug) printf( _("bulkstat_single: startino=%"PRIu64" flags=0x%"PRIx32" ret=%d\n"), ino, flags, ret); dump_bulkstat(&bulkstat); } return 0; } static void dump_inumbers( struct xfs_inumbers *inumbers) { printf("xi_startino = %"PRIu64"\n", inumbers->xi_startino); printf("\txi_allocmask = 0x%"PRIx64"\n", inumbers->xi_allocmask); printf("\txi_alloccount = %"PRIu8"\n", inumbers->xi_alloccount); printf("\txi_version = %"PRIu8"\n", inumbers->xi_version); } static void inumbers_help(void) { printf(_( "Queries the filesystem for inode group information and prints it.\n" "\n" " -a Only iterate this AG.\n" " -d Print debugging output.\n" " -e Stop after this inode.\n" " -n Ask for this many results at once.\n" " -s Inode to start with.\n" " -v Use this version of the ioctl (1 or 5).\n")); } static int inumbers_f( int argc, char **argv) { struct xfs_fd xfd = XFS_FD_INIT(file->fd); struct xfs_inumbers_req *ireq; uint64_t startino = 0; uint64_t endino = -1ULL; uint32_t batch_size = 4096; uint32_t agno = 0; uint32_t ver = 0; bool has_agno = false; bool debug = false; unsigned int i; int c; int ret; while ((c = getopt(argc, argv, "a:de:n:s:v:")) != -1) { switch (c) { case 'a': agno = cvt_u32(optarg, 10); if (errno) { perror(optarg); return 1; } has_agno = true; break; case 'd': debug = true; break; case 'e': endino = cvt_u64(optarg, 10); if (errno) { perror(optarg); return 1; } break; case 'n': batch_size = cvt_u32(optarg, 10); if (errno) { perror(optarg); return 1; } break; case 's': startino = cvt_u64(optarg, 10); if (errno) { perror(optarg); return 1; } break; case 'v': ver = cvt_u32(optarg, 10); if (errno) { perror(optarg); return 1; } if (ver != 1 && ver != 5) { fprintf(stderr, "version must be 1 or 5.\n"); return 1; } break; default: bulkstat_help(); return 0; } } if (optind != argc) { bulkstat_help(); return 0; } ret = -xfd_prepare_geometry(&xfd); if (ret) { xfrog_perror(ret, "xfd_prepare_geometry"); exitcode = 1; return 0; } ret = -xfrog_inumbers_alloc_req(batch_size, startino, &ireq); if (ret) { xfrog_perror(ret, "alloc inumbersreq"); exitcode = 1; return 0; } if (has_agno) xfrog_inumbers_set_ag(ireq, agno); set_xfd_flags(&xfd, ver); while ((ret = -xfrog_inumbers(&xfd, ireq)) == 0) { if (debug) printf( _("bulkstat: startino=%"PRIu64" flags=0x%"PRIx32" agno=%"PRIu32" ret=%d icount=%"PRIu32" ocount=%"PRIu32"\n"), ireq->hdr.ino, ireq->hdr.flags, ireq->hdr.agno, ret, ireq->hdr.icount, ireq->hdr.ocount); if (ireq->hdr.ocount == 0) break; for (i = 0; i < ireq->hdr.ocount; i++) { if (ireq->inumbers[i].xi_startino > endino) break; dump_inumbers(&ireq->inumbers[i]); } } if (ret) { xfrog_perror(ret, "xfrog_inumbers"); exitcode = 1; } free(ireq); return 0; } static cmdinfo_t bulkstat_cmd = { .name = "bulkstat", .cfunc = bulkstat_f, .argmin = 0, .argmax = -1, .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT, .help = bulkstat_help, }; static cmdinfo_t bulkstat_single_cmd = { .name = "bulkstat_single", .cfunc = bulkstat_single_f, .argmin = 1, .argmax = -1, .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT, .help = bulkstat_single_help, }; static cmdinfo_t inumbers_cmd = { .name = "inumbers", .cfunc = inumbers_f, .argmin = 0, .argmax = -1, .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT, .help = inumbers_help, }; void bulkstat_init(void) { bulkstat_cmd.args = _("[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]"); bulkstat_cmd.oneline = _("Bulk stat of inodes in a filesystem"); bulkstat_single_cmd.args = _("[-d] [-v version] inum..."); bulkstat_single_cmd.oneline = _("Stat one inode in a filesystem"); inumbers_cmd.args = _("[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]"); inumbers_cmd.oneline = _("Query inode groups in a filesystem"); add_command(&bulkstat_cmd); add_command(&bulkstat_single_cmd); add_command(&inumbers_cmd); } xfsprogs-5.3.0/io/copy_file_range.c0000644000175000017500000000710113570057155017153 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2016 Netapp, Inc. All rights reserved. */ #include #include #include #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t copy_range_cmd; static void copy_range_help(void) { printf(_("\n\ Copies a range of bytes from a file into the open file, overwriting any data\n\ already there.\n\ \n\ Example:\n\ 'copy_range -s 100 -d 200 -l 300 some_file' - copies 300 bytes from some_file\n\ at offset 100 into the open\n\ file at offset 200\n\ 'copy_range some_file' - copies all bytes from some_file into the open file\n\ at position 0\n\ 'copy_range -f 2' - copies all bytes from open file 2 into the current open file\n\ at position 0\n\ ")); } /* * Issue a raw copy_file_range syscall; for our test program we don't want the * glibc buffered copy fallback. */ static loff_t copy_file_range_cmd(int fd, long long *src_off, long long *dst_off, size_t len) { loff_t ret; do { ret = syscall(__NR_copy_file_range, fd, src_off, file->fd, dst_off, len, 0); if (ret == -1) { perror("copy_range"); return errno; } else if (ret == 0) break; len -= ret; } while (len > 0); return 0; } static off64_t copy_src_filesize(int fd) { struct stat st; if (fstat(fd, &st) < 0) { perror("fstat"); return -1; }; return st.st_size; } static int copy_range_f(int argc, char **argv) { long long src_off = 0; long long dst_off = 0; size_t len = 0; bool len_specified = false; int opt; int ret; int fd; int src_path_arg = 1; int src_file_nr = 0; size_t fsblocksize, fssectsize; init_cvtnum(&fsblocksize, &fssectsize); while ((opt = getopt(argc, argv, "s:d:l:f:")) != -1) { switch (opt) { case 's': src_off = cvtnum(fsblocksize, fssectsize, optarg); if (src_off < 0) { printf(_("invalid source offset -- %s\n"), optarg); return 0; } break; case 'd': dst_off = cvtnum(fsblocksize, fssectsize, optarg); if (dst_off < 0) { printf(_("invalid destination offset -- %s\n"), optarg); return 0; } break; case 'l': len = cvtnum(fsblocksize, fssectsize, optarg); if (len == -1LL) { printf(_("invalid length -- %s\n"), optarg); return 0; } len_specified = true; break; case 'f': src_file_nr = atoi(argv[1]); if (src_file_nr < 0 || src_file_nr >= filecount) { printf(_("file value %d is out of range (0-%d)\n"), src_file_nr, filecount - 1); return 0; } /* Expect no src_path arg */ src_path_arg = 0; break; } } if (optind != argc - src_path_arg) return command_usage(©_range_cmd); if (src_path_arg) { fd = openfile(argv[optind], NULL, IO_READONLY, 0, NULL); if (fd < 0) return 0; } else { fd = filetable[src_file_nr].fd; } if (!len_specified) { off64_t sz; sz = copy_src_filesize(fd); if (sz < 0 || (unsigned long long)sz > SIZE_MAX) { ret = 1; goto out; } if (sz > src_off) len = sz - src_off; } ret = copy_file_range_cmd(fd, &src_off, &dst_off, len); out: close(fd); return ret; } void copy_range_init(void) { copy_range_cmd.name = "copy_range"; copy_range_cmd.cfunc = copy_range_f; copy_range_cmd.argmin = 1; copy_range_cmd.argmax = 7; copy_range_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; copy_range_cmd.args = _("[-s src_off] [-d dst_off] [-l len] src_file | -f N"); copy_range_cmd.oneline = _("Copy a range of data between two files"); copy_range_cmd.help = copy_range_help; add_command(©_range_cmd); } xfsprogs-5.3.0/io/cowextsize.c0000644000175000017500000000766013570057155016244 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ /* * If configure didn't find a struct fsxattr with fsx_cowextsize, * disable the only other source (so far) of struct fsxattr. Thus, * build with the internal definition of struct fsxattr, which has * fsx_cowextsize. */ #include "platform_defs.h" #include "command.h" #include "init.h" #include "io.h" #include "input.h" #include "libfrog/paths.h" static cmdinfo_t cowextsize_cmd; static long cowextsize; static void cowextsize_help(void) { printf(_( "\n" " report or modify preferred CoW extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying cowextsize on directories\n" "\n")); } static int get_cowextsize(const char *path, int fd) { struct fsxattr fsx; if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { printf("%s: XFS_IOC_FSGETXATTR %s: %s\n", progname, path, strerror(errno)); return 0; } printf("[%u] %s\n", fsx.fsx_cowextsize, path); return 0; } static int set_cowextsize(const char *path, int fd, long extsz) { struct fsxattr fsx; struct stat64 stat; if (fstat64(fd, &stat) < 0) { perror("fstat64"); return 0; } if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { printf("%s: XFS_IOC_FSGETXATTR %s: %s\n", progname, path, strerror(errno)); return 0; } if (S_ISREG(stat.st_mode) || S_ISDIR(stat.st_mode)) { fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE; } else { printf(_("invalid target file type - file %s\n"), path); return 0; } fsx.fsx_cowextsize = extsz; if ((xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx)) < 0) { printf("%s: XFS_IOC_FSSETXATTR %s: %s\n", progname, path, strerror(errno)); return 0; } return 0; } static int get_cowextsize_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else { get_cowextsize(path, fd); close(fd); } return 0; } static int set_cowextsize_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else { set_cowextsize(path, fd, cowextsize); close(fd); } return 0; } static int cowextsize_f( int argc, char **argv) { size_t blocksize, sectsize; int c; recurse_all = recurse_dir = 0; init_cvtnum(&blocksize, §size); while ((c = getopt(argc, argv, "DR")) != EOF) { switch (c) { case 'D': recurse_all = 0; recurse_dir = 1; break; case 'R': recurse_all = 1; recurse_dir = 0; break; default: return command_usage(&cowextsize_cmd); } } if (optind < argc) { cowextsize = (long)cvtnum(blocksize, sectsize, argv[optind]); if (cowextsize < 0) { printf(_("non-numeric cowextsize argument -- %s\n"), argv[optind]); return 0; } } else { cowextsize = -1; } if (recurse_all || recurse_dir) nftw(file->name, (cowextsize >= 0) ? set_cowextsize_callback : get_cowextsize_callback, 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); else if (cowextsize >= 0) set_cowextsize(file->name, file->fd, cowextsize); else get_cowextsize(file->name, file->fd); return 0; } void cowextsize_init(void) { cowextsize_cmd.name = "cowextsize"; cowextsize_cmd.cfunc = cowextsize_f; cowextsize_cmd.args = _("[-D | -R] [cowextsize]"); cowextsize_cmd.argmin = 0; cowextsize_cmd.argmax = -1; cowextsize_cmd.flags = CMD_NOMAP_OK; cowextsize_cmd.oneline = _("get/set preferred CoW extent size (in bytes) for the open file"); cowextsize_cmd.help = cowextsize_help; add_command(&cowextsize_cmd); } xfsprogs-5.3.0/io/crc32cselftest.c0000644000175000017500000000127613570057155016666 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018 Oracle, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "init.h" #include "io.h" #include "libfrog/crc32c.h" #include "libfrog/crc32cselftest.h" static int crc32cselftest_f( int argc, char **argv) { return crc32c_test() != 0; } static const cmdinfo_t crc32cselftest_cmd = { .name = "crc32cselftest", .cfunc = crc32cselftest_f, .argmin = 0, .argmax = 0, .canpush = 0, .flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK | CMD_NOFILE_OK | CMD_NOMAP_OK, .oneline = N_("self test of crc32c implementation"), }; void crc32cselftest_init(void) { add_command(&crc32cselftest_cmd); } xfsprogs-5.3.0/io/encrypt.c0000644000175000017500000005604513570057155015525 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2016, 2019 Google LLC * Author: Eric Biggers */ #include "platform_defs.h" #include "command.h" #include "init.h" #include "libfrog/paths.h" #include "io.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif /* * Declare the fscrypt ioctls if needed, since someone may be compiling xfsprogs * with old kernel headers. But has already been included, so be * careful not to declare things twice. */ /* first batch of ioctls (Linux headers v4.6+) */ #ifndef FS_IOC_SET_ENCRYPTION_POLICY #define fscrypt_policy fscrypt_policy_v1 #define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy) #define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) #define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy) #endif /* * Second batch of ioctls (Linux headers v5.4+), plus some renamings from FS_ to * FSCRYPT_. We don't bother defining the old names here. */ #ifndef FS_IOC_GET_ENCRYPTION_POLICY_EX #define FSCRYPT_POLICY_FLAGS_PAD_4 0x00 #define FSCRYPT_POLICY_FLAGS_PAD_8 0x01 #define FSCRYPT_POLICY_FLAGS_PAD_16 0x02 #define FSCRYPT_POLICY_FLAGS_PAD_32 0x03 #define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03 #define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04 #define FSCRYPT_MODE_AES_256_XTS 1 #define FSCRYPT_MODE_AES_256_CTS 4 #define FSCRYPT_MODE_AES_128_CBC 5 #define FSCRYPT_MODE_AES_128_CTS 6 #define FSCRYPT_MODE_ADIANTUM 9 /* * In the headers for Linux v4.6 through v5.3, 'struct fscrypt_policy_v1' is * already defined under its old name, 'struct fscrypt_policy'. But it's fine * to define it under its new name too. * * Note: "v1" policies really are version "0" in the API. */ #define FSCRYPT_POLICY_V1 0 #define FSCRYPT_KEY_DESCRIPTOR_SIZE 8 struct fscrypt_policy_v1 { __u8 version; __u8 contents_encryption_mode; __u8 filenames_encryption_mode; __u8 flags; __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; }; #define FSCRYPT_POLICY_V2 2 #define FSCRYPT_KEY_IDENTIFIER_SIZE 16 struct fscrypt_policy_v2 { __u8 version; __u8 contents_encryption_mode; __u8 filenames_encryption_mode; __u8 flags; __u8 __reserved[4]; __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; }; #define FSCRYPT_MAX_KEY_SIZE 64 #define FS_IOC_GET_ENCRYPTION_POLICY_EX _IOWR('f', 22, __u8[9]) /* size + version */ struct fscrypt_get_policy_ex_arg { __u64 policy_size; /* input/output */ union { __u8 version; struct fscrypt_policy_v1 v1; struct fscrypt_policy_v2 v2; } policy; /* output */ }; #define FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR 1 #define FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER 2 struct fscrypt_key_specifier { __u32 type; /* one of FSCRYPT_KEY_SPEC_TYPE_* */ __u32 __reserved; union { __u8 __reserved[32]; /* reserve some extra space */ __u8 descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; __u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; } u; }; #define FS_IOC_ADD_ENCRYPTION_KEY _IOWR('f', 23, struct fscrypt_add_key_arg) struct fscrypt_add_key_arg { struct fscrypt_key_specifier key_spec; __u32 raw_size; __u32 __reserved[9]; __u8 raw[]; }; #define FS_IOC_REMOVE_ENCRYPTION_KEY _IOWR('f', 24, struct fscrypt_remove_key_arg) #define FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS _IOWR('f', 25, struct fscrypt_remove_key_arg) struct fscrypt_remove_key_arg { struct fscrypt_key_specifier key_spec; #define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY 0x00000001 #define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS 0x00000002 __u32 removal_status_flags; /* output */ __u32 __reserved[5]; }; #define FS_IOC_GET_ENCRYPTION_KEY_STATUS _IOWR('f', 26, struct fscrypt_get_key_status_arg) struct fscrypt_get_key_status_arg { /* input */ struct fscrypt_key_specifier key_spec; __u32 __reserved[6]; /* output */ #define FSCRYPT_KEY_STATUS_ABSENT 1 #define FSCRYPT_KEY_STATUS_PRESENT 2 #define FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED 3 __u32 status; #define FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF 0x00000001 __u32 status_flags; __u32 user_count; __u32 __out_reserved[13]; }; #endif /* !FS_IOC_GET_ENCRYPTION_POLICY_EX */ static const struct { __u8 mode; const char *name; } available_modes[] = { {FSCRYPT_MODE_AES_256_XTS, "AES-256-XTS"}, {FSCRYPT_MODE_AES_256_CTS, "AES-256-CTS"}, {FSCRYPT_MODE_AES_128_CBC, "AES-128-CBC"}, {FSCRYPT_MODE_AES_128_CTS, "AES-128-CTS"}, {FSCRYPT_MODE_ADIANTUM, "Adiantum"}, }; static cmdinfo_t get_encpolicy_cmd; static cmdinfo_t set_encpolicy_cmd; static cmdinfo_t add_enckey_cmd; static cmdinfo_t rm_enckey_cmd; static cmdinfo_t enckey_status_cmd; static void get_encpolicy_help(void) { printf(_( "\n" " display the encryption policy of the current file\n" "\n" " -1 -- Use only the old ioctl to get the encryption policy.\n" " This only works if the file has a v1 encryption policy.\n" " -t -- Test whether v2 encryption policies are supported.\n" " Prints \"supported\", \"unsupported\", or an error message.\n" "\n")); } static void set_encpolicy_help(void) { int i; printf(_( "\n" " assign an encryption policy to the currently open file\n" "\n" " Examples:\n" " 'set_encpolicy' - assign v1 policy with default key descriptor\n" " (0000000000000000)\n" " 'set_encpolicy -v 2' - assign v2 policy with default key identifier\n" " (00000000000000000000000000000000)\n" " 'set_encpolicy 0000111122223333' - assign v1 policy with given key descriptor\n" " 'set_encpolicy 00001111222233334444555566667777' - assign v2 policy with given\n" " key identifier\n" "\n" " -c MODE -- contents encryption mode\n" " -n MODE -- filenames encryption mode\n" " -f FLAGS -- policy flags\n" " -v VERSION -- policy version\n" "\n" " MODE can be numeric or one of the following predefined values:\n")); printf(" "); for (i = 0; i < ARRAY_SIZE(available_modes); i++) { printf("%s", available_modes[i].name); if (i != ARRAY_SIZE(available_modes) - 1) printf(", "); } printf("\n"); printf(_( " FLAGS and VERSION must be numeric.\n" "\n" " Note that it's only possible to set an encryption policy on an empty\n" " directory. It's then inherited by new files and subdirectories.\n" "\n")); } static void add_enckey_help(void) { printf(_( "\n" " add an encryption key to the filesystem\n" "\n" " Examples:\n" " 'add_enckey' - add key for v2 policies\n" " 'add_enckey -d 0000111122223333' - add key for v1 policies w/ given descriptor\n" "\n" "The key in binary is read from standard input.\n" " -d DESCRIPTOR -- master_key_descriptor\n" "\n")); } static void rm_enckey_help(void) { printf(_( "\n" " remove an encryption key from the filesystem\n" "\n" " Examples:\n" " 'rm_enckey 0000111122223333' - remove key for v1 policies w/ given descriptor\n" " 'rm_enckey 00001111222233334444555566667777' - remove key for v2 policies w/ given identifier\n" "\n" " -a -- remove key for all users who have added it (privileged operation)\n" "\n")); } static void enckey_status_help(void) { printf(_( "\n" " get the status of a filesystem encryption key\n" "\n" " Examples:\n" " 'enckey_status 0000111122223333' - get status of v1 policy key\n" " 'enckey_status 00001111222233334444555566667777' - get status of v2 policy key\n" "\n")); } static bool parse_byte_value(const char *arg, __u8 *value_ret) { long value; char *tmp; value = strtol(arg, &tmp, 0); if (value < 0 || value > 255 || tmp == arg || *tmp != '\0') return false; *value_ret = value; return true; } static bool parse_mode(const char *arg, __u8 *mode_ret) { int i; for (i = 0; i < ARRAY_SIZE(available_modes); i++) { if (strcmp(arg, available_modes[i].name) == 0) { *mode_ret = available_modes[i].mode; return true; } } return parse_byte_value(arg, mode_ret); } static const char * mode2str(__u8 mode) { static char buf[32]; int i; for (i = 0; i < ARRAY_SIZE(available_modes); i++) if (mode == available_modes[i].mode) return available_modes[i].name; sprintf(buf, "0x%02x", mode); return buf; } static int hexchar2bin(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); return -1; } static bool hex2bin(const char *hex, __u8 *bin, size_t bin_len) { if (strlen(hex) != 2 * bin_len) return false; while (bin_len--) { int hi = hexchar2bin(*hex++); int lo = hexchar2bin(*hex++); if (hi < 0 || lo < 0) return false; *bin++ = (hi << 4) | lo; } return true; } static const char * keydesc2str(const __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]) { static char buf[2 * FSCRYPT_KEY_DESCRIPTOR_SIZE + 1]; int i; for (i = 0; i < FSCRYPT_KEY_DESCRIPTOR_SIZE; i++) sprintf(&buf[2 * i], "%02x", master_key_descriptor[i]); return buf; } static const char * keyid2str(const __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]) { static char buf[2 * FSCRYPT_KEY_IDENTIFIER_SIZE + 1]; int i; for (i = 0; i < FSCRYPT_KEY_IDENTIFIER_SIZE; i++) sprintf(&buf[2 * i], "%02x", master_key_identifier[i]); return buf; } static const char * keyspectype(const struct fscrypt_key_specifier *key_spec) { switch (key_spec->type) { case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR: return _("descriptor"); case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER: return _("identifier"); } return _("[unknown]"); } static const char * keyspec2str(const struct fscrypt_key_specifier *key_spec) { switch (key_spec->type) { case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR: return keydesc2str(key_spec->u.descriptor); case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER: return keyid2str(key_spec->u.identifier); } return _("[unknown]"); } static bool str2keydesc(const char *str, __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]) { if (!hex2bin(str, master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE)) { fprintf(stderr, _("invalid key descriptor: %s\n"), str); return false; } return true; } static bool str2keyid(const char *str, __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]) { if (!hex2bin(str, master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE)) { fprintf(stderr, _("invalid key identifier: %s\n"), str); return false; } return true; } /* * Parse a key specifier (descriptor or identifier) given as a hex string. * * 8 bytes (16 hex chars) == key descriptor == v1 encryption policy. * 16 bytes (32 hex chars) == key identifier == v2 encryption policy. * * If a policy_version is given (>= 0), then the corresponding type of key * specifier is required. Otherwise the specifier type and policy_version are * determined based on the length of the given hex string. * * Returns the policy version, or -1 on error. */ static int str2keyspec(const char *str, int policy_version, struct fscrypt_key_specifier *key_spec) { if (policy_version < 0) { /* version unspecified? */ size_t len = strlen(str); if (len == 2 * FSCRYPT_KEY_DESCRIPTOR_SIZE) { policy_version = FSCRYPT_POLICY_V1; } else if (len == 2 * FSCRYPT_KEY_IDENTIFIER_SIZE) { policy_version = FSCRYPT_POLICY_V2; } else { fprintf(stderr, _("invalid key specifier: %s\n"), str); return -1; } } if (policy_version == FSCRYPT_POLICY_V2) { if (!str2keyid(str, key_spec->u.identifier)) return -1; key_spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER; } else { if (!str2keydesc(str, key_spec->u.descriptor)) return -1; key_spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR; } return policy_version; } static void test_for_v2_policy_support(void) { struct fscrypt_get_policy_ex_arg arg; arg.policy_size = sizeof(arg.policy); if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg) == 0 || errno == ENODATA /* file unencrypted */) { printf(_("supported\n")); return; } if (errno == ENOTTY) { printf(_("unsupported\n")); return; } fprintf(stderr, _("%s: unexpected error checking for FS_IOC_GET_ENCRYPTION_POLICY_EX support: %s\n"), file->name, strerror(errno)); exitcode = 1; } static void show_v1_encryption_policy(const struct fscrypt_policy_v1 *policy) { printf(_("Encryption policy for %s:\n"), file->name); printf(_("\tPolicy version: %u\n"), policy->version); printf(_("\tMaster key descriptor: %s\n"), keydesc2str(policy->master_key_descriptor)); printf(_("\tContents encryption mode: %u (%s)\n"), policy->contents_encryption_mode, mode2str(policy->contents_encryption_mode)); printf(_("\tFilenames encryption mode: %u (%s)\n"), policy->filenames_encryption_mode, mode2str(policy->filenames_encryption_mode)); printf(_("\tFlags: 0x%02x\n"), policy->flags); } static void show_v2_encryption_policy(const struct fscrypt_policy_v2 *policy) { printf(_("Encryption policy for %s:\n"), file->name); printf(_("\tPolicy version: %u\n"), policy->version); printf(_("\tMaster key identifier: %s\n"), keyid2str(policy->master_key_identifier)); printf(_("\tContents encryption mode: %u (%s)\n"), policy->contents_encryption_mode, mode2str(policy->contents_encryption_mode)); printf(_("\tFilenames encryption mode: %u (%s)\n"), policy->filenames_encryption_mode, mode2str(policy->filenames_encryption_mode)); printf(_("\tFlags: 0x%02x\n"), policy->flags); } static int get_encpolicy_f(int argc, char **argv) { int c; struct fscrypt_get_policy_ex_arg arg; bool only_use_v1_ioctl = false; int res; while ((c = getopt(argc, argv, "1t")) != EOF) { switch (c) { case '1': only_use_v1_ioctl = true; break; case 't': test_for_v2_policy_support(); return 0; default: return command_usage(&get_encpolicy_cmd); } } argc -= optind; argv += optind; if (argc != 0) return command_usage(&get_encpolicy_cmd); /* first try the new ioctl */ if (only_use_v1_ioctl) { res = -1; errno = ENOTTY; } else { arg.policy_size = sizeof(arg.policy); res = ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg); } /* fall back to the old ioctl */ if (res != 0 && errno == ENOTTY) res = ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY, &arg.policy.v1); if (res != 0) { fprintf(stderr, _("%s: failed to get encryption policy: %s\n"), file->name, strerror(errno)); exitcode = 1; return 0; } switch (arg.policy.version) { case FSCRYPT_POLICY_V1: show_v1_encryption_policy(&arg.policy.v1); break; case FSCRYPT_POLICY_V2: show_v2_encryption_policy(&arg.policy.v2); break; default: printf(_("Encryption policy for %s:\n"), file->name); printf(_("\tPolicy version: %u (unknown)\n"), arg.policy.version); break; } return 0; } static int set_encpolicy_f(int argc, char **argv) { int c; __u8 contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS; __u8 filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS; __u8 flags = FSCRYPT_POLICY_FLAGS_PAD_16; int version = -1; /* unspecified */ struct fscrypt_key_specifier key_spec; union { __u8 version; struct fscrypt_policy_v1 v1; struct fscrypt_policy_v2 v2; } policy; while ((c = getopt(argc, argv, "c:n:f:v:")) != EOF) { switch (c) { case 'c': if (!parse_mode(optarg, &contents_encryption_mode)) { fprintf(stderr, _("invalid contents encryption mode: %s\n"), optarg); return 0; } break; case 'n': if (!parse_mode(optarg, &filenames_encryption_mode)) { fprintf(stderr, _("invalid filenames encryption mode: %s\n"), optarg); return 0; } break; case 'f': if (!parse_byte_value(optarg, &flags)) { fprintf(stderr, _("invalid flags: %s\n"), optarg); return 0; } break; case 'v': { __u8 val; if (!parse_byte_value(optarg, &val)) { fprintf(stderr, _("invalid policy version: %s\n"), optarg); return 0; } if (val == 1) /* Just to avoid annoying people... */ val = FSCRYPT_POLICY_V1; version = val; break; } default: return command_usage(&set_encpolicy_cmd); } } argc -= optind; argv += optind; if (argc > 1) return command_usage(&set_encpolicy_cmd); /* * If unspecified, the key descriptor or identifier defaults to all 0's. * If the policy version is additionally unspecified, it defaults to v1. */ memset(&key_spec, 0, sizeof(key_spec)); if (argc > 0) { version = str2keyspec(argv[0], version, &key_spec); if (version < 0) return 0; } if (version < 0) /* version unspecified? */ version = FSCRYPT_POLICY_V1; memset(&policy, 0, sizeof(policy)); policy.version = version; if (version == FSCRYPT_POLICY_V2) { policy.v2.contents_encryption_mode = contents_encryption_mode; policy.v2.filenames_encryption_mode = filenames_encryption_mode; policy.v2.flags = flags; memcpy(policy.v2.master_key_identifier, key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE); } else { /* * xfstests passes .version = 255 for testing. Just use * 'struct fscrypt_policy_v1' for both v1 and unknown versions. */ policy.v1.contents_encryption_mode = contents_encryption_mode; policy.v1.filenames_encryption_mode = filenames_encryption_mode; policy.v1.flags = flags; memcpy(policy.v1.master_key_descriptor, key_spec.u.descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE); } if (ioctl(file->fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) != 0) { fprintf(stderr, _("%s: failed to set encryption policy: %s\n"), file->name, strerror(errno)); exitcode = 1; } return 0; } static ssize_t read_until_limit_or_eof(int fd, void *buf, size_t limit) { size_t bytes_read = 0; ssize_t res; while (limit) { res = read(fd, buf, limit); if (res < 0) return res; if (res == 0) break; buf += res; bytes_read += res; limit -= res; } return bytes_read; } static int add_enckey_f(int argc, char **argv) { int c; struct fscrypt_add_key_arg *arg; ssize_t raw_size; int retval = 0; arg = calloc(1, sizeof(*arg) + FSCRYPT_MAX_KEY_SIZE + 1); if (!arg) { perror("calloc"); exitcode = 1; return 0; } arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER; while ((c = getopt(argc, argv, "d:")) != EOF) { switch (c) { case 'd': arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR; if (!str2keydesc(optarg, arg->key_spec.u.descriptor)) goto out; break; default: retval = command_usage(&add_enckey_cmd); goto out; } } argc -= optind; argv += optind; if (argc != 0) { retval = command_usage(&add_enckey_cmd); goto out; } raw_size = read_until_limit_or_eof(STDIN_FILENO, arg->raw, FSCRYPT_MAX_KEY_SIZE + 1); if (raw_size < 0) { fprintf(stderr, _("Error reading key from stdin: %s\n"), strerror(errno)); exitcode = 1; goto out; } if (raw_size > FSCRYPT_MAX_KEY_SIZE) { fprintf(stderr, _("Invalid key; got > FSCRYPT_MAX_KEY_SIZE (%d) bytes on stdin!\n"), FSCRYPT_MAX_KEY_SIZE); goto out; } arg->raw_size = raw_size; if (ioctl(file->fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) { fprintf(stderr, _("Error adding encryption key: %s\n"), strerror(errno)); exitcode = 1; goto out; } printf(_("Added encryption key with %s %s\n"), keyspectype(&arg->key_spec), keyspec2str(&arg->key_spec)); out: memset(arg->raw, 0, FSCRYPT_MAX_KEY_SIZE + 1); free(arg); return retval; } static int rm_enckey_f(int argc, char **argv) { int c; struct fscrypt_remove_key_arg arg; int ioc = FS_IOC_REMOVE_ENCRYPTION_KEY; memset(&arg, 0, sizeof(arg)); while ((c = getopt(argc, argv, "a")) != EOF) { switch (c) { case 'a': ioc = FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS; break; default: return command_usage(&rm_enckey_cmd); } } argc -= optind; argv += optind; if (argc != 1) return command_usage(&rm_enckey_cmd); if (str2keyspec(argv[0], -1, &arg.key_spec) < 0) return 0; if (ioctl(file->fd, ioc, &arg) != 0) { fprintf(stderr, _("Error removing encryption key: %s\n"), strerror(errno)); exitcode = 1; return 0; } if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) { printf(_("Removed user's claim to encryption key with %s %s\n"), keyspectype(&arg.key_spec), keyspec2str(&arg.key_spec)); } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) { printf(_("Removed encryption key with %s %s, but files still busy\n"), keyspectype(&arg.key_spec), keyspec2str(&arg.key_spec)); } else { printf(_("Removed encryption key with %s %s\n"), keyspectype(&arg.key_spec), keyspec2str(&arg.key_spec)); } return 0; } static int enckey_status_f(int argc, char **argv) { struct fscrypt_get_key_status_arg arg; memset(&arg, 0, sizeof(arg)); if (str2keyspec(argv[1], -1, &arg.key_spec) < 0) return 0; if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_KEY_STATUS, &arg) != 0) { fprintf(stderr, _("Error getting encryption key status: %s\n"), strerror(errno)); exitcode = 1; return 0; } switch (arg.status) { case FSCRYPT_KEY_STATUS_PRESENT: printf(_("Present")); if (arg.user_count || arg.status_flags) { printf(" (user_count=%u", arg.user_count); if (arg.status_flags & FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF) printf(", added_by_self"); arg.status_flags &= ~FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF; if (arg.status_flags) printf(", unknown_flags=0x%08x", arg.status_flags); printf(")"); } printf("\n"); return 0; case FSCRYPT_KEY_STATUS_ABSENT: printf(_("Absent\n")); return 0; case FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED: printf(_("Incompletely removed\n")); return 0; default: printf(_("Unknown status (%u)\n"), arg.status); return 0; } } void encrypt_init(void) { get_encpolicy_cmd.name = "get_encpolicy"; get_encpolicy_cmd.cfunc = get_encpolicy_f; get_encpolicy_cmd.args = _("[-1] [-t]"); get_encpolicy_cmd.argmin = 0; get_encpolicy_cmd.argmax = -1; get_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; get_encpolicy_cmd.oneline = _("display the encryption policy of the current file"); get_encpolicy_cmd.help = get_encpolicy_help; set_encpolicy_cmd.name = "set_encpolicy"; set_encpolicy_cmd.cfunc = set_encpolicy_f; set_encpolicy_cmd.args = _("[-c mode] [-n mode] [-f flags] [-v version] [keyspec]"); set_encpolicy_cmd.argmin = 0; set_encpolicy_cmd.argmax = -1; set_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; set_encpolicy_cmd.oneline = _("assign an encryption policy to the current file"); set_encpolicy_cmd.help = set_encpolicy_help; add_enckey_cmd.name = "add_enckey"; add_enckey_cmd.cfunc = add_enckey_f; add_enckey_cmd.args = _("[-d descriptor]"); add_enckey_cmd.argmin = 0; add_enckey_cmd.argmax = -1; add_enckey_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; add_enckey_cmd.oneline = _("add an encryption key to the filesystem"); add_enckey_cmd.help = add_enckey_help; rm_enckey_cmd.name = "rm_enckey"; rm_enckey_cmd.cfunc = rm_enckey_f; rm_enckey_cmd.args = _("[-a] keyspec"); rm_enckey_cmd.argmin = 0; rm_enckey_cmd.argmax = -1; rm_enckey_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; rm_enckey_cmd.oneline = _("remove an encryption key from the filesystem"); rm_enckey_cmd.help = rm_enckey_help; enckey_status_cmd.name = "enckey_status"; enckey_status_cmd.cfunc = enckey_status_f; enckey_status_cmd.args = _("keyspec"); enckey_status_cmd.argmin = 1; enckey_status_cmd.argmax = 1; enckey_status_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; enckey_status_cmd.oneline = _("get the status of a filesystem encryption key"); enckey_status_cmd.help = enckey_status_help; add_command(&get_encpolicy_cmd); add_command(&set_encpolicy_cmd); add_command(&add_enckey_cmd); add_command(&rm_enckey_cmd); add_command(&enckey_status_cmd); } xfsprogs-5.3.0/io/fadvise.c0000644000175000017500000000575213435336036015457 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t fadvise_cmd; static void fadvise_help(void) { printf(_( "\n" " advise the page cache about expected I/O patterns on the current file\n" "\n" " Modifies kernel page cache behaviour when operating on the current file.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_FADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_FADV_DONTNEED) [*]\n" " -n -- data will be accessed once (POSIX_FADV_NOREUSE) [*]\n" " -r -- expect random page references (POSIX_FADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_FADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_FADV_WILLNEED) [*]\n" " Notes: these interfaces are not supported in Linux kernels before 2.6.\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED and NOREUSE are equivalent, and force the maximum readahead.\n" "\n")); } static int fadvise_f( int argc, char **argv) { off64_t offset = 0, length = 0; int c, range = 0, advise = POSIX_FADV_NORMAL; while ((c = getopt(argc, argv, "dnrsw")) != EOF) { switch (c) { case 'd': /* Don't need these pages */ advise = POSIX_FADV_DONTNEED; range = 1; break; case 'n': /* Data will be accessed once */ advise = POSIX_FADV_NOREUSE; range = 1; break; case 'r': /* Expect random page references */ advise = POSIX_FADV_RANDOM; range = 0; break; case 's': /* Expect sequential page references */ advise = POSIX_FADV_SEQUENTIAL; range = 0; break; case 'w': /* Will need these pages */ advise = POSIX_FADV_WILLNEED; range = 1; break; default: return command_usage(&fadvise_cmd); } } if (range) { size_t blocksize, sectsize; if (optind != argc - 2) return command_usage(&fadvise_cmd); init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; length = cvtnum(blocksize, sectsize, argv[optind]); if (length < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } } else if (optind != argc) { return command_usage(&fadvise_cmd); } if (posix_fadvise(file->fd, offset, length, advise) < 0) { perror("fadvise"); return 0; } return 0; } void fadvise_init(void) { fadvise_cmd.name = "fadvise"; fadvise_cmd.cfunc = fadvise_f; fadvise_cmd.argmin = 0; fadvise_cmd.argmax = -1; fadvise_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fadvise_cmd.args = _("[-dnrsw] [off len]"); fadvise_cmd.oneline = _("advisory commands for sections of a file"); fadvise_cmd.help = fadvise_help; add_command(&fadvise_cmd); } xfsprogs-5.3.0/io/fiemap.c0000644000175000017500000002220213435336036015264 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2010 Red Hat, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "input.h" #include #include "init.h" #include "io.h" #define EXTENT_BATCH 32 static cmdinfo_t fiemap_cmd; static int max_extents = -1; static void fiemap_help(void) { printf(_( "\n" " prints the block mapping for a file's data or attribute forks" "\n" " Example:\n" " 'fiemap -v' - tabular format verbose map\n" "\n" " fiemap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " -n -- query n extents.\n" " -v -- Verbose information\n" " offset is the starting offset to map, and is optional. If offset is\n" " specified, mapping length may (optionally) be specified as well." "\n")); } static void print_hole( int foff_w, int boff_w, int tot_w, int cur_extent, int lflag, bool plain, __u64 llast, __u64 lstart) { char lbuf[48]; if (plain) { printf("\t%d: [%llu..%llu]: hole", cur_extent, (unsigned long long)llast, lstart - 1ULL); if (lflag) printf(_(" %llu blocks\n"), (unsigned long long)lstart - llast); else printf("\n"); } else { snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", (unsigned long long)llast, lstart - 1ULL); printf("%4d: %-*s %-*s %*llu\n", cur_extent, foff_w, lbuf, boff_w, _("hole"), tot_w, (unsigned long long)lstart - llast); } } static int print_verbose( struct fiemap_extent *extent, int foff_w, int boff_w, int tot_w, int flg_w, int cur_extent, __u64 last_logical) { __u64 lstart; __u64 llast; __u64 len; __u64 block; char lbuf[48]; char bbuf[48]; char flgbuf[16]; int num_printed = 0; llast = BTOBBT(last_logical); lstart = BTOBBT(extent->fe_logical); len = BTOBBT(extent->fe_length); block = BTOBBT(extent->fe_physical); memset(lbuf, 0, sizeof(lbuf)); memset(bbuf, 0, sizeof(bbuf)); if (cur_extent == 0) { printf("%4s: %-*s %-*s %*s %*s\n", _("EXT"), foff_w, _("FILE-OFFSET"), boff_w, _("BLOCK-RANGE"), tot_w, _("TOTAL"), flg_w, _("FLAGS")); } if (lstart > llast) { print_hole(foff_w, boff_w, tot_w, cur_extent, 0, false, llast, lstart); cur_extent++; num_printed++; } if (cur_extent == max_extents) return num_printed; snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", (unsigned long long)lstart, lstart + len - 1ULL); snprintf(bbuf, sizeof(bbuf), "%llu..%llu", (unsigned long long)block, block + len - 1ULL); snprintf(flgbuf, sizeof(flgbuf), "0x%x", extent->fe_flags); printf("%4d: %-*s %-*s %*llu %*s\n", cur_extent, foff_w, lbuf, boff_w, bbuf, tot_w, (unsigned long long)len, flg_w, flgbuf); num_printed++; return num_printed; } static int print_plain( struct fiemap_extent *extent, int lflag, int cur_extent, __u64 last_logical) { __u64 lstart; __u64 llast; __u64 block; __u64 len; int num_printed = 0; llast = BTOBBT(last_logical); lstart = BTOBBT(extent->fe_logical); len = BTOBBT(extent->fe_length); block = BTOBBT(extent->fe_physical); if (lstart > llast) { print_hole(0, 0, 0, cur_extent, lflag, true, llast, lstart); cur_extent++; num_printed++; } if (cur_extent == max_extents) return num_printed; printf("\t%d: [%llu..%llu]: %llu..%llu", cur_extent, (unsigned long long)lstart, lstart + len - 1ULL, (unsigned long long)block, block + len - 1ULL); num_printed++; if (lflag) printf(_(" %llu blocks\n"), (unsigned long long)len); else printf("\n"); return num_printed; } /* * Calculate the proper extent table format based on first * set of extents */ static void calc_print_format( struct fiemap *fiemap, int *foff_w, int *boff_w, int *tot_w, int *flg_w) { int i; char lbuf[32]; char bbuf[32]; __u64 logical; __u64 block; __u64 len; struct fiemap_extent *extent; for (i = 0; i < fiemap->fm_mapped_extents; i++) { extent = &fiemap->fm_extents[i]; logical = BTOBBT(extent->fe_logical); len = BTOBBT(extent->fe_length); block = BTOBBT(extent->fe_physical); snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]", (unsigned long long)logical, (unsigned long long)logical + len - 1); snprintf(bbuf, sizeof(bbuf), "%llu..%llu", (unsigned long long)block, (unsigned long long)block + len - 1); *foff_w = max(*foff_w, strlen(lbuf)); *boff_w = max(*boff_w, strlen(bbuf)); *tot_w = max(*tot_w, numlen(len, 10)); *flg_w = max(*flg_w, numlen(extent->fe_flags, 16)); if (extent->fe_flags & FIEMAP_EXTENT_LAST) break; } } static int fiemap_f( int argc, char **argv) { struct fiemap *fiemap; int done = 0; int lflag = 0; int vflag = 0; int fiemap_flags = FIEMAP_FLAG_SYNC; int c; int i; int map_size; int ret; int cur_extent = 0; int foff_w = 16; /* 16 just for a good minimum range */ int boff_w = 16; int tot_w = 5; /* 5 since its just one number */ int flg_w = 5; __u64 last_logical = 0; /* last extent offset handled */ off64_t start_offset = 0; /* mapping start */ off64_t length = -1LL; /* mapping length */ off64_t range_end = -1LL; /* mapping end*/ size_t fsblocksize, fssectsize; struct stat st; init_cvtnum(&fsblocksize, &fssectsize); while ((c = getopt(argc, argv, "aln:v")) != EOF) { switch (c) { case 'a': fiemap_flags |= FIEMAP_FLAG_XATTR; break; case 'l': lflag = 1; break; case 'n': max_extents = atoi(optarg); break; case 'v': vflag++; break; default: return command_usage(&fiemap_cmd); } } /* Range start (optional) */ if (optind < argc) { start_offset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (start_offset < 0) { printf("non-numeric offset argument -- %s\n", argv[optind]); return 0; } last_logical = start_offset; optind++; } /* Range length (optional if range start was specified) */ if (optind < argc) { length = cvtnum(fsblocksize, fssectsize, argv[optind]); if (length < 0) { printf("non-numeric len argument -- %s\n", argv[optind]); return 0; } range_end = start_offset + length; } map_size = sizeof(struct fiemap) + (EXTENT_BATCH * sizeof(struct fiemap_extent)); fiemap = malloc(map_size); if (!fiemap) { fprintf(stderr, _("%s: malloc of %d bytes failed.\n"), progname, map_size); exitcode = 1; return 0; } printf("%s:\n", file->name); while (!done) { memset(fiemap, 0, map_size); fiemap->fm_flags = fiemap_flags; fiemap->fm_start = last_logical; fiemap->fm_length = range_end - last_logical; fiemap->fm_extent_count = EXTENT_BATCH; ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap); if (ret < 0) { fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: " "%s\n", progname, file->name, strerror(errno)); free(fiemap); exitcode = 1; return 0; } /* No more extents to map, exit */ if (!fiemap->fm_mapped_extents) break; for (i = 0; i < fiemap->fm_mapped_extents; i++) { struct fiemap_extent *extent; int num_printed = 0; extent = &fiemap->fm_extents[i]; if (vflag) { if (cur_extent == 0) { calc_print_format(fiemap, &foff_w, &boff_w, &tot_w, &flg_w); } num_printed = print_verbose(extent, foff_w, boff_w, tot_w, flg_w, cur_extent, last_logical); } else num_printed = print_plain(extent, lflag, cur_extent, last_logical); cur_extent += num_printed; last_logical = extent->fe_logical + extent->fe_length; /* Kernel has told us there are no more extents */ if (extent->fe_flags & FIEMAP_EXTENT_LAST) { done = 1; break; } /* We have exhausted the requested range */ if (last_logical >= range_end) { done = 1; break; } /* We have printed requested nr of extents */ if (cur_extent == max_extents) { done = 1; break; } } } if (cur_extent == max_extents) goto out; memset(&st, 0, sizeof(st)); if (fstat(file->fd, &st)) { fprintf(stderr, "%s: fstat failed: %s\n", progname, strerror(errno)); free(fiemap); exitcode = 1; return 0; } /* Print last hole to EOF or to end of requested range */ range_end = min((uint64_t)range_end, st.st_size); if (cur_extent && last_logical < range_end) print_hole(foff_w, boff_w, tot_w, cur_extent, lflag, !vflag, BTOBBT(last_logical), BTOBBT(range_end)); out: free(fiemap); return 0; } void fiemap_init(void) { fiemap_cmd.name = "fiemap"; fiemap_cmd.cfunc = fiemap_f; fiemap_cmd.argmin = 0; fiemap_cmd.argmax = -1; fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fiemap_cmd.args = _("[-alv] [-n nx] [offset [len]]"); fiemap_cmd.oneline = _("print block mapping for a file"); fiemap_cmd.help = fiemap_help; add_command(&fiemap_cmd); } xfsprogs-5.3.0/io/file.c0000644000175000017500000000421113435336036014742 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include "init.h" #include "io.h" static cmdinfo_t file_cmd; static cmdinfo_t print_cmd; fileio_t *filetable; int filecount; fileio_t *file; static void print_fileio( fileio_t *file, int index, int braces) { printf(_("%c%03d%c %-14s (%s,%s,%s,%s%s%s%s%s%s%s)\n"), braces? '[' : ' ', index, braces? ']' : ' ', file->name, file->flags & IO_FOREIGN ? _("foreign") : _("xfs"), file->flags & IO_OSYNC ? _("sync") : _("non-sync"), file->flags & IO_DIRECT ? _("direct") : _("non-direct"), file->flags & IO_READONLY ? _("read-only") : _("read-write"), file->flags & IO_REALTIME ? _(",real-time") : "", file->flags & IO_APPEND ? _(",append-only") : "", file->flags & IO_NONBLOCK ? _(",non-block") : "", file->flags & IO_TMPFILE ? _(",tmpfile") : "", file->flags & IO_PATH ? _(",path") : "", file->flags & IO_NOFOLLOW ? _(",nofollow") : ""); } int filelist_f(void) { int i; for (i = 0; i < filecount; i++) print_fileio(&filetable[i], i, &filetable[i] == file); return 0; } static int print_f( int argc, char **argv) { filelist_f(); maplist_f(); return 0; } static int file_f( int argc, char **argv) { int i; if (argc <= 1) return filelist_f(); i = atoi(argv[1]); if (i < 0 || i >= filecount) { printf(_("value %d is out of range (0-%d)\n"), i, filecount-1); } else { file = &filetable[i]; filelist_f(); } return 0; } void file_init(void) { file_cmd.name = "file"; file_cmd.altname = "f"; file_cmd.args = _("[N]"); file_cmd.cfunc = file_f; file_cmd.argmin = 0; file_cmd.argmax = 1; file_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; file_cmd.oneline = _("set the current file"); print_cmd.name = "print"; print_cmd.altname = "p"; print_cmd.cfunc = print_f; print_cmd.argmin = 0; print_cmd.argmax = 0; print_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; print_cmd.oneline = _("list current open files and memory mappings"); add_command(&file_cmd); add_command(&print_cmd); } xfsprogs-5.3.0/io/freeze.c0000644000175000017500000000256713435336036015317 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2001-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t freeze_cmd; static cmdinfo_t thaw_cmd; static int freeze_f( int argc, char **argv) { int level = 1; if (xfsctl(file->name, file->fd, XFS_IOC_FREEZE, &level) < 0) { fprintf(stderr, _("%s: cannot freeze filesystem at %s: %s\n"), progname, file->name, strerror(errno)); exitcode = 1; return 0; } return 0; } static int thaw_f( int argc, char **argv) { int level = 1; if (xfsctl(file->name, file->fd, XFS_IOC_THAW, &level) < 0) { fprintf(stderr, _("%s: cannot unfreeze filesystem mounted at %s: %s\n"), progname, file->name, strerror(errno)); exitcode = 1; return 0; } return 0; } void freeze_init(void) { freeze_cmd.name = "freeze"; freeze_cmd.cfunc = freeze_f; freeze_cmd.argmin = 0; freeze_cmd.argmax = 0; freeze_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; freeze_cmd.oneline = _("freeze filesystem of current file"); thaw_cmd.name = "thaw"; thaw_cmd.cfunc = thaw_f; thaw_cmd.argmin = 0; thaw_cmd.argmax = 0; thaw_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; thaw_cmd.oneline = _("unfreeze filesystem of current file"); if (expert) { add_command(&freeze_cmd); add_command(&thaw_cmd); } } xfsprogs-5.3.0/io/fsmap.c0000644000175000017500000003664013570057155015146 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "platform_defs.h" #include "command.h" #include "init.h" #include "libfrog/paths.h" #include "io.h" #include "input.h" #include "libfrog/fsgeom.h" static cmdinfo_t fsmap_cmd; static dev_t xfs_data_dev; static void fsmap_help(void) { printf(_( "\n" " Prints the block mapping for the filesystem hosting the current file" "\n" " fsmap prints the map of disk blocks used by the whole filesystem.\n" " When possible, owner and offset information will be included in the\n" " space report.\n" "\n" " By default, each line of the listing takes the following form:\n" " extent: major:minor [startblock..endblock]: owner startoffset..endoffset length\n" " The owner field is either an inode number or a special value.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -d -- query only the data device (default).\n" " -l -- query only the log device.\n" " -r -- query only the realtime device.\n" " -n -- query n extents at a time.\n" " -m -- output machine-readable format.\n" " -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -v\n" "\n" "The optional start and end arguments require one of -d, -l, or -r to be set.\n" "\n")); } #define OWNER_BUF_SZ 32 static const char * special_owner( int64_t owner, char *buf) { switch (owner) { case XFS_FMR_OWN_FREE: return _("free space"); case XFS_FMR_OWN_UNKNOWN: return _("unknown"); case XFS_FMR_OWN_FS: return _("static fs metadata"); case XFS_FMR_OWN_LOG: return _("journalling log"); case XFS_FMR_OWN_AG: return _("per-AG metadata"); case XFS_FMR_OWN_INOBT: return _("inode btree"); case XFS_FMR_OWN_INODES: return _("inodes"); case XFS_FMR_OWN_REFC: return _("refcount btree"); case XFS_FMR_OWN_COW: return _("cow reservation"); case XFS_FMR_OWN_DEFECTIVE: return _("defective"); default: snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"), FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner)); return buf; } } static void dump_map( unsigned long long *nr, struct fsmap_head *head) { unsigned long long i; struct fsmap *p; char owner[OWNER_BUF_SZ]; char *fork; for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { printf("\t%llu: %u:%u [%lld..%lld]: ", i + (*nr), major(p->fmr_device), minor(p->fmr_device), (long long)BTOBBT(p->fmr_physical), (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); fork = (p->fmr_flags & FMR_OF_ATTR_FORK) ? _("attr") : _("data"); if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) printf("%s", special_owner(p->fmr_owner, owner)); else if (p->fmr_flags & FMR_OF_EXTENT_MAP) printf(_("inode %lld %s extent map"), (long long) p->fmr_owner, fork); else printf(_("inode %lld %s %lld..%lld"), (long long)p->fmr_owner, fork, (long long)BTOBBT(p->fmr_offset), (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); printf(_(" %lld\n"), (long long)BTOBBT(p->fmr_length)); } (*nr) += head->fmh_entries; } static void dump_map_machine( unsigned long long *nr, struct fsmap_head *head) { unsigned long long i; struct fsmap *p; char *fork; printf(_("EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n")); for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { printf("%llu,%u,%u,%lld,%lld,", i + (*nr), major(p->fmr_device), minor(p->fmr_device), (long long)BTOBBT(p->fmr_physical), (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); fork = (p->fmr_flags & FMR_OF_ATTR_FORK) ? "attr" : "data"; if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) printf("special_%u:%u,,,", FMR_OWNER_TYPE(p->fmr_owner), FMR_OWNER_CODE(p->fmr_owner)); else if (p->fmr_flags & FMR_OF_EXTENT_MAP) printf(_("inode_%lld_%s_bmbt,,,"), (long long) p->fmr_owner, fork); else printf(_("inode_%lld_%s,%lld,%lld,"), (long long)p->fmr_owner, fork, (long long)BTOBBT(p->fmr_offset), (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); printf("%lld\n", (long long)BTOBBT(p->fmr_length)); } (*nr) += head->fmh_entries; } /* * Verbose mode displays: * extent: major:minor [startblock..endblock]: startoffset..endoffset \ * ag# (agoffset..agendoffset) totalbbs flags */ #define MINRANGE_WIDTH 16 #define MINAG_WIDTH 2 #define MINTOT_WIDTH 5 #define NFLG 7 /* count of flags */ #define FLG_NULL 00000000 /* Null flag */ #define FLG_ATTR_FORK 01000000 /* attribute fork */ #define FLG_SHARED 00100000 /* shared extent */ #define FLG_PRE 00010000 /* Unwritten extent */ #define FLG_BSU 00001000 /* Not on begin of stripe unit */ #define FLG_ESU 00000100 /* Not on end of stripe unit */ #define FLG_BSW 00000010 /* Not on begin of stripe width */ #define FLG_ESW 00000001 /* Not on end of stripe width */ static void dump_map_verbose( unsigned long long *nr, struct fsmap_head *head, bool *dumped_flags, struct xfs_fsop_geom *fsgeo) { unsigned long long i; struct fsmap *p; int agno; off64_t agoff, bperag; int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w; int nr_w, dev_w; char rbuf[40], bbuf[40], abuf[40], obuf[40]; char nbuf[40], dbuf[40], gbuf[40]; char owner[OWNER_BUF_SZ]; int sunit, swidth; int flg = 0; foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH; dev_w = 3; nr_w = 4; tot_w = MINTOT_WIDTH; bperag = (off64_t)fsgeo->agblocks * (off64_t)fsgeo->blocksize; sunit = (fsgeo->sunit * fsgeo->blocksize); swidth = (fsgeo->swidth * fsgeo->blocksize); /* * Go through the extents and figure out the width * needed for all columns. */ for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { if (p->fmr_flags & FMR_OF_PREALLOC || p->fmr_flags & FMR_OF_ATTR_FORK || p->fmr_flags & FMR_OF_SHARED) flg = 1; if (sunit && (p->fmr_physical % sunit != 0 || ((p->fmr_physical + p->fmr_length) % sunit) != 0 || p->fmr_physical % swidth != 0 || ((p->fmr_physical + p->fmr_length) % swidth) != 0)) flg = 1; if (flg) *dumped_flags = true; snprintf(nbuf, sizeof(nbuf), "%llu", (*nr) + i); nr_w = max(nr_w, strlen(nbuf)); if (head->fmh_oflags & FMH_OF_DEV_T) snprintf(dbuf, sizeof(dbuf), "%u:%u", major(p->fmr_device), minor(p->fmr_device)); else snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device); dev_w = max(dev_w, strlen(dbuf)); snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:", (long long)BTOBBT(p->fmr_physical), (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); boff_w = max(boff_w, strlen(bbuf)); if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) own_w = max(own_w, strlen( special_owner(p->fmr_owner, owner))); else { snprintf(obuf, sizeof(obuf), "%lld", (long long)p->fmr_owner); own_w = max(own_w, strlen(obuf)); } if (p->fmr_flags & FMR_OF_EXTENT_MAP) foff_w = max(foff_w, strlen(_("extent_map"))); else if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) ; else { snprintf(rbuf, sizeof(rbuf), "%lld..%lld", (long long)BTOBBT(p->fmr_offset), (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); foff_w = max(foff_w, strlen(rbuf)); } if (p->fmr_device == xfs_data_dev) { agno = p->fmr_physical / bperag; agoff = p->fmr_physical - (agno * bperag); snprintf(abuf, sizeof(abuf), "(%lld..%lld)", (long long)BTOBBT(agoff), (long long)BTOBBT(agoff + p->fmr_length - 1)); } else abuf[0] = 0; aoff_w = max(aoff_w, strlen(abuf)); tot_w = max(tot_w, numlen(BTOBBT(p->fmr_length), 10)); } agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10)); if (*nr == 0) printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n", nr_w, _("EXT"), dev_w, _("DEV"), boff_w, _("BLOCK-RANGE"), own_w, _("OWNER"), foff_w, _("FILE-OFFSET"), agno_w, _("AG"), aoff_w, _("AG-OFFSET"), tot_w, _("TOTAL"), flg ? _(" FLAGS") : ""); for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { flg = FLG_NULL; if (p->fmr_flags & FMR_OF_PREALLOC) flg |= FLG_PRE; if (p->fmr_flags & FMR_OF_ATTR_FORK) flg |= FLG_ATTR_FORK; if (p->fmr_flags & FMR_OF_SHARED) flg |= FLG_SHARED; /* * If striping enabled, determine if extent starts/ends * on a stripe unit boundary. */ if (sunit) { if (p->fmr_physical % sunit != 0) flg |= FLG_BSU; if (((p->fmr_physical + p->fmr_length ) % sunit ) != 0) flg |= FLG_ESU; if (p->fmr_physical % swidth != 0) flg |= FLG_BSW; if (((p->fmr_physical + p->fmr_length ) % swidth ) != 0) flg |= FLG_ESW; } if (head->fmh_oflags & FMH_OF_DEV_T) snprintf(dbuf, sizeof(dbuf), "%u:%u", major(p->fmr_device), minor(p->fmr_device)); else snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device); snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:", (long long)BTOBBT(p->fmr_physical), (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) { snprintf(obuf, sizeof(obuf), "%s", special_owner(p->fmr_owner, owner)); snprintf(rbuf, sizeof(rbuf), " "); } else { snprintf(obuf, sizeof(obuf), "%lld", (long long)p->fmr_owner); snprintf(rbuf, sizeof(rbuf), "%lld..%lld", (long long)BTOBBT(p->fmr_offset), (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); } if (p->fmr_device == xfs_data_dev) { agno = p->fmr_physical / bperag; agoff = p->fmr_physical - (agno * bperag); snprintf(abuf, sizeof(abuf), "(%lld..%lld)", (long long)BTOBBT(agoff), (long long)BTOBBT(agoff + p->fmr_length - 1)); snprintf(gbuf, sizeof(gbuf), "%lld", (long long)agno); } else { abuf[0] = 0; gbuf[0] = 0; } if (p->fmr_flags & FMR_OF_EXTENT_MAP) printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n", nr_w, (*nr) + i, dev_w, dbuf, boff_w, bbuf, own_w, obuf, foff_w, _("extent map"), agno_w, gbuf, aoff_w, abuf, tot_w, (long long)BTOBBT(p->fmr_length)); else { printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i, dev_w, dbuf, boff_w, bbuf, own_w, obuf, foff_w, rbuf); printf(" %-*s %-*s", agno_w, gbuf, aoff_w, abuf); printf(" %*lld", tot_w, (long long)BTOBBT(p->fmr_length)); if (flg == FLG_NULL) printf("\n"); else printf(" %-*.*o\n", NFLG, NFLG, flg); } } (*nr) += head->fmh_entries; } static void dump_verbose_key(void) { printf(_(" FLAG Values:\n")); printf(_(" %*.*o Attribute fork\n"), NFLG+1, NFLG+1, FLG_ATTR_FORK); printf(_(" %*.*o Shared extent\n"), NFLG+1, NFLG+1, FLG_SHARED); printf(_(" %*.*o Unwritten preallocated extent\n"), NFLG+1, NFLG+1, FLG_PRE); printf(_(" %*.*o Doesn't begin on stripe unit\n"), NFLG+1, NFLG+1, FLG_BSU); printf(_(" %*.*o Doesn't end on stripe unit\n"), NFLG+1, NFLG+1, FLG_ESU); printf(_(" %*.*o Doesn't begin on stripe width\n"), NFLG+1, NFLG+1, FLG_BSW); printf(_(" %*.*o Doesn't end on stripe width\n"), NFLG+1, NFLG+1, FLG_ESW); } static int fsmap_f( int argc, char **argv) { struct fsmap *p; struct fsmap_head *nhead; struct fsmap_head *head; struct fsmap *l, *h; struct xfs_fsop_geom fsgeo; long long start = 0; long long end = -1; int nmap_size; int map_size; int nflag = 0; int vflag = 0; int mflag = 0; int i = 0; int c; unsigned long long nr = 0; size_t fsblocksize, fssectsize; struct fs_path *fs; static bool tab_init; bool dumped_flags = false; int dflag, lflag, rflag; init_cvtnum(&fsblocksize, &fssectsize); dflag = lflag = rflag = 0; while ((c = getopt(argc, argv, "dlmn:rv")) != EOF) { switch (c) { case 'd': /* data device */ dflag = 1; break; case 'l': /* log device */ lflag = 1; break; case 'm': /* machine readable format */ mflag++; break; case 'n': /* number of extents specified */ nflag = cvt_u32(optarg, 10); if (errno) return command_usage(&fsmap_cmd); break; case 'r': /* rt device */ rflag = 1; break; case 'v': /* Verbose output */ vflag++; break; default: return command_usage(&fsmap_cmd); } } if ((dflag + lflag + rflag > 1) || (mflag > 0 && vflag > 0) || (argc > optind && dflag + lflag + rflag == 0)) return command_usage(&fsmap_cmd); if (argc > optind) { start = cvtnum(fsblocksize, fssectsize, argv[optind]); if (start < 0) { fprintf(stderr, _("Bad rmap start_bblock %s.\n"), argv[optind]); return 0; } start <<= BBSHIFT; } if (argc > optind + 1) { end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]); if (end < 0) { fprintf(stderr, _("Bad rmap end_bblock %s.\n"), argv[optind + 1]); return 0; } end <<= BBSHIFT; } if (vflag) { c = -xfrog_geometry(file->fd, &fsgeo); if (c) { fprintf(stderr, _("%s: can't get geometry [\"%s\"]: %s\n"), progname, file->name, strerror(c)); exitcode = 1; return 0; } } map_size = nflag ? nflag : 131072 / sizeof(struct fsmap); head = malloc(fsmap_sizeof(map_size)); if (head == NULL) { fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"), progname, fsmap_sizeof(map_size)); exitcode = 1; return 0; } memset(head, 0, sizeof(*head)); l = head->fmh_keys; h = head->fmh_keys + 1; if (dflag) { l->fmr_device = h->fmr_device = file->fs_path.fs_datadev; } else if (lflag) { l->fmr_device = h->fmr_device = file->fs_path.fs_logdev; } else if (rflag) { l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev; } else { l->fmr_device = 0; h->fmr_device = UINT_MAX; } l->fmr_physical = start; h->fmr_physical = end; h->fmr_owner = ULLONG_MAX; h->fmr_flags = UINT_MAX; h->fmr_offset = ULLONG_MAX; /* Count mappings */ if (!nflag) { head->fmh_count = 0; i = ioctl(file->fd, FS_IOC_GETFSMAP, head); if (i < 0) { fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)" " iflags=0x%x [\"%s\"]: %s\n"), progname, head->fmh_iflags, file->name, strerror(errno)); free(head); exitcode = 1; return 0; } if (head->fmh_entries > map_size + 2) { map_size = 11ULL * head->fmh_entries / 10; nmap_size = map_size > (1 << 24) ? (1 << 24) : map_size; nhead = realloc(head, fsmap_sizeof(nmap_size)); if (nhead == NULL) { fprintf(stderr, _("%s: cannot realloc %zu bytes\n"), progname, fsmap_sizeof(nmap_size)); } else { head = nhead; map_size = nmap_size; } } } /* * If this is an XFS filesystem, remember the data device. * (We report AG number/block for data device extents on XFS). */ if (!tab_init) { fs_table_initialise(0, NULL, 0, NULL); tab_init = true; } fs = fs_table_lookup(file->name, FS_MOUNT_POINT); xfs_data_dev = fs ? fs->fs_datadev : 0; head->fmh_count = map_size; do { /* Get some extents */ i = ioctl(file->fd, FS_IOC_GETFSMAP, head); if (i < 0) { fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)" " iflags=0x%x [\"%s\"]: %s\n"), progname, head->fmh_iflags, file->name, strerror(errno)); free(head); exitcode = 1; return 0; } if (head->fmh_entries == 0) break; if (vflag) dump_map_verbose(&nr, head, &dumped_flags, &fsgeo); else if (mflag) dump_map_machine(&nr, head); else dump_map(&nr, head); p = &head->fmh_recs[head->fmh_entries - 1]; if (p->fmr_flags & FMR_OF_LAST) break; fsmap_advance(head); } while (true); if (dumped_flags) dump_verbose_key(); free(head); return 0; } void fsmap_init(void) { fsmap_cmd.name = "fsmap"; fsmap_cmd.cfunc = fsmap_f; fsmap_cmd.argmin = 0; fsmap_cmd.argmax = -1; fsmap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_FOREIGN_OK; fsmap_cmd.args = _("[-d|-l|-r] [-m|-v] [-n nx] [start] [end]"); fsmap_cmd.oneline = _("print filesystem mapping for a range of blocks"); fsmap_cmd.help = fsmap_help; add_command(&fsmap_cmd); } xfsprogs-5.3.0/io/fsync.c0000644000175000017500000000206313435336036015150 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "init.h" #include "io.h" static cmdinfo_t fsync_cmd; static cmdinfo_t fdatasync_cmd; static int fsync_f( int argc, char **argv) { if (fsync(file->fd) < 0) { perror("fsync"); return 0; } return 0; } static int fdatasync_f( int argc, char **argv) { if (fdatasync(file->fd) < 0) { perror("fdatasync"); return 0; } return 0; } void fsync_init(void) { fsync_cmd.name = "fsync"; fsync_cmd.altname = "s"; fsync_cmd.cfunc = fsync_f; fsync_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fsync_cmd.oneline = _("calls fsync(2) to flush all in-core file state to disk"); fdatasync_cmd.name = "fdatasync"; fdatasync_cmd.altname = "ds"; fdatasync_cmd.cfunc = fdatasync_f; fdatasync_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fdatasync_cmd.oneline = _("calls fdatasync(2) to flush the files in-core data to disk"); add_command(&fsync_cmd); add_command(&fdatasync_cmd); } xfsprogs-5.3.0/io/getrusage.c0000644000175000017500000000567013435336036016023 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include #include "init.h" #include "io.h" static cmdinfo_t getrusage_cmd; /* * Report process resource utilisation. Formatting options: * "Shell" format: 0.000u 0.000s 0:00.00 0.0% 0+0k 0+0io 0pf+0w * Verbose format: * 0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k * 0inputs+0outputs (0major+0minor)pagefaults 0swaps * Comma Separated Value format: 0.000,0.000,00:00:00.00,0.0,0,0,0,0,0,0 */ static int getrusage_f( int argc, char **argv) { struct timeval wallclk, timenow; struct rusage rusage; double usrtime, systime, elapsed, pct_cpu; char ts[64]; int Cflag, vflag; int c; Cflag = vflag = 0; while ((c = getopt(argc, argv, "Cv")) != EOF) { switch (c) { case 'C': Cflag = 1; break; case 'v': vflag = 1; break; default: return command_usage(&getrusage_cmd); } } if (optind != argc) return command_usage(&getrusage_cmd); if (getrusage(RUSAGE_SELF, &rusage) < 0) { perror("getrusage"); return 0; } gettimeofday(&timenow, NULL); wallclk = tsub(timenow, stopwatch); elapsed = (double)wallclk.tv_sec + ((double)wallclk.tv_usec / 1000000.0); usrtime = (double)rusage.ru_utime.tv_sec + ((double)rusage.ru_utime.tv_usec / 1000000.0); systime = (double)rusage.ru_stime.tv_sec + ((double)rusage.ru_stime.tv_usec / 1000000.0); if (elapsed < usrtime + systime) pct_cpu = 100.0; else pct_cpu = ((usrtime + systime) / elapsed) * 100; c = Cflag ? VERBOSE_FIXED_TIME : TERSE_FIXED_TIME; timestr(&wallclk, ts, sizeof(ts), c); if (Cflag) printf("%.3f,%.3f,%s,%.1f,%ld,%ld,%ld,%ld,%ld,%ld,%ld\n", usrtime, systime, ts, pct_cpu, rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap, rusage.ru_inblock, rusage.ru_oublock, rusage.ru_nvcsw, rusage.ru_nivcsw); else if (vflag) printf("%.2fuser %.2fsystem %selapsed %.0f%%CPU " "(%ldavgtext+%ldavgdata %ldmaxresident)k\n" "%ldinputs+%ldoutputs " "(%ldmajor+%ldminor)pagefaults %ldswaps\n", usrtime, systime, ts, pct_cpu, rusage.ru_ixrss, rusage.ru_idrss, rusage.ru_maxrss, rusage.ru_inblock, rusage.ru_oublock, rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap); else printf("%.3fu %.3fs %s %.1f%%\t" "%ld+%ldk %ld+%ldio %ldpf+%ldw\n", usrtime, systime, ts, pct_cpu, rusage.ru_maxrss, rusage.ru_ixrss, rusage.ru_inblock, rusage.ru_oublock, rusage.ru_majflt, rusage.ru_nswap); return 0; } void getrusage_init(void) { getrusage_cmd.name = "getrusage"; getrusage_cmd.altname = "g"; getrusage_cmd.argmin = 0; getrusage_cmd.argmax = -1; getrusage_cmd.cfunc = getrusage_f; getrusage_cmd.flags = CMD_NOFILE_OK | CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; getrusage_cmd.oneline = _("report process resource usage"); if (expert) add_command(&getrusage_cmd); } xfsprogs-5.3.0/io/imap.c0000644000175000017500000000255113570057155014760 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2001-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" static cmdinfo_t imap_cmd; static int imap_f(int argc, char **argv) { struct xfs_fd xfd = XFS_FD_INIT(file->fd); struct xfs_inumbers_req *ireq; uint32_t nent; int i; int error; if (argc != 2) nent = 1; else nent = atoi(argv[1]); error = -xfrog_inumbers_alloc_req(nent, 0, &ireq); if (error) { xfrog_perror(error, "alloc req"); return 0; } while ((error = -xfrog_inumbers(&xfd, ireq)) == 0 && ireq->hdr.ocount > 0) { for (i = 0; i < ireq->hdr.ocount; i++) { printf(_("ino %10"PRIu64" count %2d mask %016"PRIx64"\n"), ireq->inumbers[i].xi_startino, ireq->inumbers[i].xi_alloccount, ireq->inumbers[i].xi_allocmask); } } if (error) { xfrog_perror(error, "xfsctl(XFS_IOC_FSINUMBERS)"); exitcode = 1; } free(ireq); return 0; } void imap_init(void) { imap_cmd.name = "imap"; imap_cmd.cfunc = imap_f; imap_cmd.argmin = 0; imap_cmd.argmax = 1; imap_cmd.args = _("[nentries]"); imap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT; imap_cmd.oneline = _("inode map for filesystem of current file"); if (expert) add_command(&imap_cmd); } xfsprogs-5.3.0/io/init.c0000644000175000017500000001145313570057155014776 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "platform_defs.h" #include "command.h" #include "input.h" #include "init.h" #include "io.h" char *progname; int exitcode; int expert; static int idlethread; size_t pagesize; struct timeval stopwatch; static void usage(void) { fprintf(stderr, _("Usage: %s [-adfinrRstVx] [-m mode] [-p prog] [[-c|-C] cmd]... file\n"), progname); exit(1); } void init_cvtnum( size_t *blocksize, size_t *sectsize) { if (!file || (file->flags & IO_FOREIGN)) { *blocksize = 4096; *sectsize = 512; } else { *blocksize = file->geom.blocksize; *sectsize = file->geom.sectsize; } } static void init_commands(void) { attr_init(); bmap_init(); bulkstat_init(); copy_range_init(); cowextsize_init(); encrypt_init(); fadvise_init(); fiemap_init(); file_init(); flink_init(); freeze_init(); fsmap_init(); fsync_init(); getrusage_init(); help_init(); imap_init(); inject_init(); label_init(); log_writes_init(); madvise_init(); mincore_init(); mmap_init(); open_init(); parent_init(); pread_init(); prealloc_init(); pwrite_init(); quit_init(); readdir_init(); reflink_init(); repair_init(); resblks_init(); scrub_init(); seek_init(); sendfile_init(); shutdown_init(); stat_init(); swapext_init(); sync_init(); sync_range_init(); truncate_init(); utimes_init(); crc32cselftest_init(); } /* * This allows xfs_io commands specified on the command line to be run on every * open file in the file table. Commands that should not be iterated across all * open files need to specify CMD_FLAG_ONESHOT in their command flags. */ static int filetable_iterator( int index) { if (index >= filecount) return 0; file = &filetable[index++]; return index; } static int init_check_command( const cmdinfo_t *ct) { if (!file && !(ct->flags & CMD_NOFILE_OK)) { fprintf(stderr, _("no files are open, try 'help open'\n")); return 0; } if (!mapping && !(ct->flags & CMD_NOMAP_OK)) { fprintf(stderr, _("no mapped regions, try 'help mmap'\n")); return 0; } if (file && !(ct->flags & CMD_FOREIGN_OK) && (file->flags & IO_FOREIGN)) { fprintf(stderr, _("foreign file active, %s command is for XFS filesystems only\n"), ct->name); return 0; } return 1; } static void init( int argc, char **argv) { int c, flags = 0; char *sp; mode_t mode = 0600; struct xfs_fsop_geom geometry = { 0 }; struct fs_path fsp; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); pagesize = getpagesize(); gettimeofday(&stopwatch, NULL); fs_table_initialise(0, NULL, 0, NULL); while ((c = getopt(argc, argv, "ac:C:dFfiLm:p:PnrRstTVx")) != EOF) { switch (c) { case 'a': flags |= IO_APPEND; break; case 'c': add_user_command(optarg); break; case 'C': add_oneshot_user_command(optarg); break; case 'd': flags |= IO_DIRECT; break; case 'F': /* Ignored / deprecated now, handled automatically */ break; case 'f': flags |= IO_CREAT; break; case 'i': idlethread = 1; break; case 'm': mode = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { fprintf(stderr, _("non-numeric mode -- %s\n"), optarg); exit(1); } break; case 'n': flags |= IO_NONBLOCK; break; case 'p': progname = optarg; break; case 'r': flags |= IO_READONLY; break; case 's': flags |= IO_OSYNC; break; case 't': flags |= IO_TRUNC; break; case 'P': flags |= IO_PATH; break; case 'L': flags |= IO_NOFOLLOW; break; case 'R': flags |= IO_REALTIME; break; case 'T': flags |= IO_TMPFILE; break; case 'x': expert = 1; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); default: usage(); } } while (optind < argc) { c = openfile(argv[optind], &geometry, flags, mode, &fsp); if (c < 0) exit(1); if (!platform_test_xfs_fd(c)) flags |= IO_FOREIGN; if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0) exit(1); optind++; } init_commands(); add_command_iterator(filetable_iterator); add_check_command(init_check_command); } /* * The purpose of this idle thread is to test io from a multi threaded process. * With single threaded process, the file table is not shared and file structs * are not reference counted. Spawning an idle thread can help detecting file * struct reference leaks. */ static void * idle_loop(void *arg) { for (;;) pause(); return NULL; } static void start_idle_thread(void) { pthread_t t; if (pthread_create(&t, NULL, idle_loop, NULL)) { fprintf(stderr, "Error creating idle thread\n"); exit(1); } } int main( int argc, char **argv) { init(argc, argv); if (idlethread) start_idle_thread(); command_loop(); return exitcode; } xfsprogs-5.3.0/io/init.h0000644000175000017500000000074513435336036015003 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #define CMD_NOFILE_OK (1<<0) /* command doesn't need an open file */ #define CMD_NOMAP_OK (1<<1) /* command doesn't need a mapped region */ #define CMD_FOREIGN_OK CMD_FLAG_FOREIGN_OK extern char *progname; extern int exitcode; extern int expert; extern size_t pagesize; extern struct timeval stopwatch; extern void init_cvtnum(size_t *blocksize, size_t *sectsize); xfsprogs-5.3.0/io/inject.c0000644000175000017500000000765013570057155015313 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include "xfs_errortag.h" static cmdinfo_t inject_cmd; static int error_tag(char *name) { static struct { int tag; char *name; } *e, eflags[] = { { XFS_ERRTAG_NOERROR, "noerror" }, { XFS_ERRTAG_IFLUSH_1, "iflush1" }, { XFS_ERRTAG_IFLUSH_2, "iflush2" }, { XFS_ERRTAG_IFLUSH_3, "iflush3" }, { XFS_ERRTAG_IFLUSH_4, "iflush4" }, { XFS_ERRTAG_IFLUSH_5, "iflush5" }, { XFS_ERRTAG_IFLUSH_6, "iflush6" }, { XFS_ERRTAG_DA_READ_BUF, "dareadbuf" }, { XFS_ERRTAG_BTREE_CHECK_LBLOCK, "btree_chk_lblk" }, { XFS_ERRTAG_BTREE_CHECK_SBLOCK, "btree_chk_sblk" }, { XFS_ERRTAG_ALLOC_READ_AGF, "readagf" }, { XFS_ERRTAG_IALLOC_READ_AGI, "readagi" }, { XFS_ERRTAG_ITOBP_INOTOBP, "itobp" }, { XFS_ERRTAG_IUNLINK, "iunlink" }, { XFS_ERRTAG_IUNLINK_REMOVE, "iunlinkrm" }, { XFS_ERRTAG_DIR_INO_VALIDATE, "dirinovalid" }, { XFS_ERRTAG_BULKSTAT_READ_CHUNK, "bulkstat" }, { XFS_ERRTAG_IODONE_IOERR, "logiodone" }, { XFS_ERRTAG_STRATREAD_IOERR, "stratread" }, { XFS_ERRTAG_STRATCMPL_IOERR, "stratcmpl" }, { XFS_ERRTAG_DIOWRITE_IOERR, "diowrite" }, { XFS_ERRTAG_BMAPIFORMAT, "bmapifmt" }, { XFS_ERRTAG_FREE_EXTENT, "free_extent" }, { XFS_ERRTAG_RMAP_FINISH_ONE, "rmap_finish_one" }, { XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE, "refcount_continue_update" }, { XFS_ERRTAG_REFCOUNT_FINISH_ONE, "refcount_finish_one" }, { XFS_ERRTAG_BMAP_FINISH_ONE, "bmap_finish_one" }, { XFS_ERRTAG_AG_RESV_CRITICAL, "ag_resv_critical" }, { XFS_ERRTAG_DROP_WRITES, "drop_writes" }, { XFS_ERRTAG_LOG_BAD_CRC, "log_bad_crc" }, { XFS_ERRTAG_LOG_ITEM_PIN, "log_item_pin" }, { XFS_ERRTAG_BUF_LRU_REF, "buf_lru_ref" }, { XFS_ERRTAG_FORCE_SCRUB_REPAIR, "force_repair" }, { XFS_ERRTAG_FORCE_SUMMARY_RECALC, "bad_summary" }, { XFS_ERRTAG_IUNLINK_FALLBACK, "iunlink_fallback" }, { XFS_ERRTAG_MAX, NULL } }; int count; /* * If this fails make sure every tag is defined in the array above, * see xfs_errortag_attrs in kernelspace. */ BUILD_BUG_ON(sizeof(eflags) != (XFS_ERRTAG_MAX + 1) * sizeof(*e)); /* Search for a name */ if (name) { for (e = eflags; e->name; e++) if (strcmp(name, e->name) == 0) return e->tag; return -1; } /* Dump all the names */ fputs("tags: [ ", stdout); for (count = 0, e = eflags; e->name; e++, count++) { if (count) { fputs(", ", stdout); if (!(count % 5)) fputs("\n\t", stdout); } fputs(e->name, stdout); } fputs(" ]\n", stdout); return 0; } static void inject_help(void) { printf(_( "\n" " inject errors into the filesystem of the currently open file\n" "\n" " Example:\n" " 'inject readagf' - cause errors on allocation group freespace reads\n" "\n" " Causes the kernel to generate and react to errors within XFS, provided\n" " the XFS kernel code has been built with debugging features enabled.\n" " With no arguments, displays the list of error injection tags.\n" "\n")); } static int inject_f( int argc, char **argv) { xfs_error_injection_t error; int command = XFS_IOC_ERROR_INJECTION; if (argc == 1) return error_tag(NULL); while (--argc > 0) { error.fd = file->fd; if ((error.errtag = error_tag(argv[argc])) < 0) { fprintf(stderr, _("no such tag -- %s\n"), argv[1]); continue; } if (error.errtag == XFS_ERRTAG_NOERROR) command = XFS_IOC_ERROR_CLEARALL; if ((xfsctl(file->name, file->fd, command, &error)) < 0) { perror("XFS_IOC_ERROR_INJECTION"); continue; } } return 0; } void inject_init(void) { inject_cmd.name = "inject"; inject_cmd.cfunc = inject_f; inject_cmd.argmin = 0; inject_cmd.argmax = -1; inject_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT; inject_cmd.args = _("[tag ...]"); inject_cmd.oneline = _("inject errors into a filesystem"); inject_cmd.help = inject_help; if (expert) add_command(&inject_cmd); } xfsprogs-5.3.0/io/io.h0000644000175000017500000001113313570057155014442 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "xfs.h" #include "libfrog/paths.h" /* * Read/write patterns (default is always "forward") */ #define IO_RANDOM ( 0) #define IO_FORWARD ( 1) #define IO_BACKWARD (-1) #define IO_ONCE ( 2) /* * File descriptor options */ #define IO_READONLY (1<<0) #define IO_DIRECT (1<<1) #define IO_REALTIME (1<<2) #define IO_APPEND (1<<3) #define IO_OSYNC (1<<4) #define IO_CREAT (1<<5) #define IO_TRUNC (1<<6) #define IO_FOREIGN (1<<7) #define IO_NONBLOCK (1<<8) #define IO_TMPFILE (1<<9) #define IO_PATH (1<<10) #define IO_NOFOLLOW (1<<11) /* * Regular file I/O control */ typedef struct fileio { int fd; /* open file descriptor */ int flags; /* flags describing file state */ char *name; /* file name at time of open */ struct xfs_fsop_geom geom; /* XFS filesystem geometry */ struct fs_path fs_path; /* XFS path information */ } fileio_t; extern fileio_t *filetable; /* open file table */ extern int filecount; /* number of open files */ extern fileio_t *file; /* active file in file table */ extern int filelist_f(void); extern int stat_f(int argc, char **argv); /* * Memory mapped file regions */ typedef struct mmap_region { void *addr; /* address of start of mapping */ size_t length; /* length of mapping */ off64_t offset; /* start offset into backing file */ int prot; /* protection mode of the mapping */ bool map_sync; /* is this a MAP_SYNC mapping? */ char *name; /* name of backing file */ } mmap_region_t; extern mmap_region_t *maptable; /* mmap'd region array */ extern int mapcount; /* #entries in the mapping table */ extern mmap_region_t *mapping; /* active mapping table entry */ extern int maplist_f(void); extern void *check_mapping_range(mmap_region_t *, off64_t, size_t, int); /* * Various xfs_io helper routines/globals */ extern off64_t filesize(void); extern int openfile(char *, struct xfs_fsop_geom *, int, mode_t, struct fs_path *); extern int addfile(char *, int , struct xfs_fsop_geom *, int, struct fs_path *); extern void printxattr(uint, int, int, const char *, int, int); extern unsigned int recurse_all; extern unsigned int recurse_dir; extern void *io_buffer; extern size_t io_buffersize; extern int vectors; extern struct iovec *iov; extern int alloc_buffer(size_t, int, unsigned int); extern int read_buffer(int, off64_t, long long, long long *, int, int); extern void dump_buffer(off64_t, ssize_t); extern void attr_init(void); extern void bmap_init(void); extern void encrypt_init(void); extern void file_init(void); extern void flink_init(void); extern void freeze_init(void); extern void fsync_init(void); extern void getrusage_init(void); extern void help_init(void); extern void imap_init(void); extern void inject_init(void); extern void label_init(void); extern void mmap_init(void); extern void open_init(void); extern void parent_init(void); extern void pread_init(void); extern void prealloc_init(void); extern void pwrite_init(void); extern void quit_init(void); extern void resblks_init(void); extern void seek_init(void); extern void shutdown_init(void); extern void stat_init(void); extern void swapext_init(void); extern void sync_init(void); extern void truncate_init(void); extern void utimes_init(void); #ifdef HAVE_FADVISE extern void fadvise_init(void); #else #define fadvise_init() do { } while (0) #endif #ifdef HAVE_SENDFILE extern void sendfile_init(void); #else #define sendfile_init() do { } while (0) #endif #ifdef HAVE_MADVISE extern void madvise_init(void); #else #define madvise_init() do { } while (0) #endif #ifdef HAVE_MINCORE extern void mincore_init(void); #else #define mincore_init() do { } while (0) #endif #ifdef HAVE_FIEMAP extern void fiemap_init(void); #else #define fiemap_init() do { } while (0) #endif #ifdef HAVE_COPY_FILE_RANGE extern void copy_range_init(void); #else #define copy_range_init() do { } while (0) #endif #ifdef HAVE_SYNC_FILE_RANGE extern void sync_range_init(void); #else #define sync_range_init() do { } while (0) #endif #ifdef HAVE_READDIR extern void readdir_init(void); #else #define readdir_init() do { } while (0) #endif extern void reflink_init(void); extern void cowextsize_init(void); #ifdef HAVE_GETFSMAP extern void fsmap_init(void); #else # define fsmap_init() do { } while (0) #endif #ifdef HAVE_DEVMAPPER extern void log_writes_init(void); #else #define log_writes_init() do { } while (0) #endif extern void scrub_init(void); extern void repair_init(void); extern void crc32cselftest_init(void); extern void bulkstat_init(void); xfsprogs-5.3.0/io/label.c0000644000175000017500000000376513570057155015121 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018 Red Hat, Inc. All Rights Reserved. */ #include #include "platform_defs.h" #include "libxfs.h" #include "libfrog/paths.h" #include "command.h" #include "init.h" #include "io.h" #ifndef FS_IOC_GETFSLABEL /* Max chars for the interface; fs limits may differ */ #define FSLABEL_MAX 256 #define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX]) #define FS_IOC_SETFSLABEL _IOW(0x94, 50, char[FSLABEL_MAX]) #endif static cmdinfo_t label_cmd; static void label_help(void) { printf(_( "\n" " Manipulate or query the filesystem label while mounted.\n" "\n" " With no arguments, displays the current filesystem label.\n" " -s newlabel -- set the filesystem label to newlabel\n" " -c -- clear the filesystem label (sets to NULL string)\n" "\n")); } static int label_f( int argc, char **argv) { int c; int error; char label[FSLABEL_MAX + 1]; if (argc == 1) { memset(label, 0, sizeof(label)); error = ioctl(file->fd, FS_IOC_GETFSLABEL, &label); goto out; } while ((c = getopt(argc, argv, "cs:")) != EOF) { switch (c) { case 'c': label[0] = '\0'; break; case 's': if (strlen(optarg) > FSLABEL_MAX) { errno = EINVAL; error = 1; goto out; } strncpy(label, optarg, sizeof(label) - 1); label[sizeof(label) - 1] = 0; break; default: return command_usage(&label_cmd); } } /* Check for trailing arguments */ if (argc != optind) return command_usage(&label_cmd); error = ioctl(file->fd, FS_IOC_SETFSLABEL, label); out: if (error) { perror("label"); exitcode = 1; } else { printf("label = \"%s\"\n", label); } return 0; } void label_init(void) { label_cmd.name = "label"; label_cmd.cfunc = label_f; label_cmd.argmin = 0; label_cmd.argmax = 3; label_cmd.args = _("[-s label|-c]"); label_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; label_cmd.oneline = _("query, set, or clear the filesystem label while mounted"); label_cmd.help = label_help; add_command(&label_cmd); } xfsprogs-5.3.0/io/link.c0000644000175000017500000000172513435336036014767 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Christoph Hellwig. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #ifndef AT_EMPTY_PATH #define AT_EMPTY_PATH 0x1000 #endif static cmdinfo_t flink_cmd; static void flink_help(void) { printf(_( "\n" "link the open file descriptor to the supplied filename\n" "\n" "\n")); } static int flink_f( int argc, char **argv) { if (argc != 2) return command_usage(&flink_cmd); if (linkat(file->fd, "", AT_FDCWD, argv[1], AT_EMPTY_PATH) < 0) { perror("flink"); return 0; } return 0; } void flink_init(void) { flink_cmd.name = "flink"; flink_cmd.cfunc = flink_f; flink_cmd.argmin = 1; flink_cmd.argmax = 1; flink_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; flink_cmd.args = _("filename"); flink_cmd.oneline = _("link the open file descriptor to the supplied filename"); flink_cmd.help = flink_help; add_command(&flink_cmd); } xfsprogs-5.3.0/io/log_writes.c0000644000175000017500000000336713435336036016214 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2017 Intel Corporation. * All Rights Reserved. */ #include "platform_defs.h" #include #include "command.h" #include "init.h" #include "io.h" static cmdinfo_t log_writes_cmd; static int mark_log(const char *device, const char *mark) { struct dm_task *dmt; const int size = 80; char message[size]; int len, ret = 0; len = snprintf(message, size, "mark %s", mark); if (len >= size) { printf("mark '%s' is too long\n", mark); return ret; } if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG))) return ret; if (!dm_task_set_name(dmt, device)) goto out; if (!dm_task_set_sector(dmt, 0)) goto out; if (!dm_task_set_message(dmt, message)) goto out; if (dm_task_run(dmt)) ret = 1; out: dm_task_destroy(dmt); return ret; } static int log_writes_f( int argc, char **argv) { const char *device = NULL; const char *mark = NULL; int c; exitcode = 1; while ((c = getopt(argc, argv, "d:m:")) != EOF) { switch (c) { case 'd': device = optarg; break; case 'm': mark = optarg; break; default: return command_usage(&log_writes_cmd); } } if (device == NULL || mark == NULL) return command_usage(&log_writes_cmd); if (mark_log(device, mark)) exitcode = 0; return 0; } void log_writes_init(void) { log_writes_cmd.name = "log_writes"; log_writes_cmd.altname = "lw"; log_writes_cmd.cfunc = log_writes_f; log_writes_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; log_writes_cmd.argmin = 0; log_writes_cmd.argmax = -1; log_writes_cmd.args = _("-d device -m mark"); log_writes_cmd.oneline = _("create mark in the dm-log-writes log specified by "); add_command(&log_writes_cmd); } xfsprogs-5.3.0/io/madvise.c0000644000175000017500000000567113435336036015466 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include "init.h" #include "io.h" static cmdinfo_t madvise_cmd; static void madvise_help(void) { printf(_( "\n" " advise the page cache about access patterns expected for a mapping\n" "\n" " Modifies page cache behavior when operating on the current mapping.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_MADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_MADV_DONTNEED) [*]\n" " -r -- expect random page references (POSIX_MADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_MADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_MADV_WILLNEED) [*]\n" " Notes:\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED forces the maximum readahead.\n" "\n")); } static int madvise_f( int argc, char **argv) { off64_t offset, llength; size_t length; void *start; int advise = MADV_NORMAL, c; size_t blocksize, sectsize; while ((c = getopt(argc, argv, "drsw")) != EOF) { switch (c) { case 'd': /* Don't need these pages */ advise = MADV_DONTNEED; break; case 'r': /* Expect random page references */ advise = MADV_RANDOM; break; case 's': /* Expect sequential page references */ advise = MADV_SEQUENTIAL; break; case 'w': /* Will need these pages */ advise = MADV_WILLNEED; break; default: return command_usage(&madvise_cmd); } } if (optind == argc) { offset = mapping->offset; length = mapping->length; } else if (optind == argc - 2) { init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; llength = cvtnum(blocksize, sectsize, argv[optind]); if (llength < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } else if (llength > (size_t)llength) { printf(_("length argument too large -- %lld\n"), (long long)llength); return 0; } else length = (size_t)llength; } else { return command_usage(&madvise_cmd); } start = check_mapping_range(mapping, offset, length, 1); if (!start) return 0; if (madvise(start, length, advise) < 0) { perror("madvise"); return 0; } return 0; } void madvise_init(void) { madvise_cmd.name = "madvise"; madvise_cmd.altname = "ma"; madvise_cmd.cfunc = madvise_f; madvise_cmd.argmin = 0; madvise_cmd.argmax = -1; madvise_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; madvise_cmd.args = _("[-drsw] [off len]"); madvise_cmd.oneline = _("give advice about use of memory"); madvise_cmd.help = madvise_help; add_command(&madvise_cmd); } xfsprogs-5.3.0/io/mincore.c0000644000175000017500000000506513435336036015467 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include "init.h" #include "io.h" static cmdinfo_t mincore_cmd; static int mincore_f( int argc, char **argv) { off64_t offset, llength; size_t length; size_t blocksize, sectsize; void *start; void *current, *previous; unsigned char *vec; int i; if (argc == 1) { offset = mapping->offset; length = mapping->length; } else if (argc == 3) { init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[1]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[1]); return 0; } llength = cvtnum(blocksize, sectsize, argv[2]); if (llength < 0) { printf(_("non-numeric length argument -- %s\n"), argv[2]); return 0; } else if (llength > (size_t)llength) { printf(_("length argument too large -- %lld\n"), (long long)llength); return 0; } else length = (size_t)llength; } else { return command_usage(&mincore_cmd); } start = check_mapping_range(mapping, offset, length, 1); if (!start) return 0; vec = calloc(length/pagesize, sizeof(unsigned char)); if (!vec) { perror("calloc"); return 0; } if (mincore(start, length, vec) < 0) { perror("mincore"); free(vec); return 0; } previous = NULL; current = start; for (i = 0; i < length/pagesize; i++, current += pagesize) { if (vec[i]) { if (!previous) { /* print start address */ printf("0x%lx - ", (unsigned long)current); previous = start + (i * pagesize); } } else if (previous) { /* print end and page count */ printf(_("0x%lx %lu pages (%llu : %lu)\n"), (unsigned long)current, (unsigned long)(current - previous) / pagesize, (unsigned long long)offset + (unsigned long long)(previous - start), (unsigned long)(current - previous)); previous = NULL; } } if (previous) printf(_("0x%lx %lu pages (%llu : %lu)\n"), (unsigned long)current, (unsigned long)(current - previous) / pagesize, (unsigned long long)offset + (unsigned long long)(previous - start), (unsigned long)(current - previous)); free(vec); return 0; } void mincore_init(void) { mincore_cmd.name = "mincore"; mincore_cmd.altname = "mi"; mincore_cmd.cfunc = mincore_f; mincore_cmd.argmin = 0; mincore_cmd.argmax = 2; mincore_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; mincore_cmd.args = _("[off len]"); mincore_cmd.oneline = _("find mapping pages that are memory resident"); add_command(&mincore_cmd); } xfsprogs-5.3.0/io/mmap.c0000644000175000017500000004307613435336036014771 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include #include "init.h" #include "io.h" static cmdinfo_t mmap_cmd; static cmdinfo_t mread_cmd; static cmdinfo_t msync_cmd; static cmdinfo_t munmap_cmd; static cmdinfo_t mwrite_cmd; #ifdef HAVE_MREMAP static cmdinfo_t mremap_cmd; #endif /* HAVE_MREMAP */ mmap_region_t *maptable; int mapcount; mmap_region_t *mapping; static void print_mapping( mmap_region_t *map, int index, int braces) { char buffer[8] = { 0 }; int i; static struct { int prot; int mode; } *p, pflags[] = { { PROT_READ, 'r' }, { PROT_WRITE, 'w' }, { PROT_EXEC, 'x' }, { PROT_NONE, 0 } }; for (i = 0, p = pflags; p->prot != PROT_NONE; i++, p++) buffer[i] = (map->prot & p->prot) ? p->mode : '-'; if (map->map_sync) sprintf(&buffer[i], " S"); printf("%c%03d%c 0x%lx - 0x%lx %s %14s (%lld : %ld)\n", braces? '[' : ' ', index, braces? ']' : ' ', (unsigned long)map->addr, (unsigned long)((char *)map->addr + map->length), buffer, map->name ? map->name : "???", (long long)map->offset, (long)map->length); } void * check_mapping_range( mmap_region_t *map, off64_t offset, size_t length, int pagealign) { off64_t relative; if (offset < mapping->offset) { printf(_("offset (%lld) is before start of mapping (%lld)\n"), (long long)offset, (long long)mapping->offset); return NULL; } relative = offset - mapping->offset; if (relative > mapping->length) { printf(_("offset (%lld) is beyond end of mapping (%lld)\n"), (long long)relative, (long long)mapping->offset); return NULL; } if ((relative + length) > (mapping->offset + mapping->length)) { printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"), (long long)offset, (long long)relative, (long long)mapping->offset, (long)mapping->length); return NULL; } if (pagealign && (long)((char *)mapping->addr + relative) % pagesize) { printf(_("offset address (%p) is not page aligned\n"), (char *)mapping->addr + relative); return NULL; } return (char *)mapping->addr + relative; } int maplist_f(void) { int i; for (i = 0; i < mapcount; i++) print_mapping(&maptable[i], i, &maptable[i] == mapping); return 0; } static int mapset_f( int argc, char **argv) { int i; ASSERT(argc == 2); i = atoi(argv[1]); if (i < 0 || i >= mapcount) { printf("value %d is out of range (0-%d)\n", i, mapcount); } else { mapping = &maptable[i]; maplist_f(); } return 0; } static void mmap_help(void) { printf(_( "\n" " maps a range within the current file into memory\n" "\n" " Example:\n" " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n" "\n" " Memory maps a range of a file for subsequent use by other xfs_io commands.\n" " With no arguments, mmap shows the current mappings. The current mapping\n" " can be set by using the single argument form (mapping number or address).\n" " If two arguments are specified (a range), a new mapping is created and the\n" " following options are available:\n" " -r -- map with PROT_READ protection\n" " -w -- map with PROT_WRITE protection\n" " -x -- map with PROT_EXEC protection\n" " -S -- map with MAP_SYNC and MAP_SHARED_VALIDATE flags\n" " -s -- first do mmap(size)/munmap(size), try to reserve some free space\n" " If no protection mode is specified, all are used by default.\n" "\n")); } static int mmap_f( int argc, char **argv) { off64_t offset; ssize_t length = 0, length2 = 0; void *address = NULL; char *filename; size_t blocksize, sectsize; int c, prot = 0, flags = MAP_SHARED; if (argc == 1) { if (mapping) return maplist_f(); fprintf(stderr, file ? _("no mapped regions, try 'help mmap'\n") : _("no files are open, try 'help open'\n")); return 0; } else if (argc == 2) { if (mapping) return mapset_f(argc, argv); fprintf(stderr, file ? _("no mapped regions, try 'help mmap'\n") : _("no files are open, try 'help open'\n")); return 0; } else if (!file) { fprintf(stderr, _("no files are open, try 'help open'\n")); return 0; } init_cvtnum(&blocksize, §size); while ((c = getopt(argc, argv, "rwxSs:")) != EOF) { switch (c) { case 'r': prot |= PROT_READ; break; case 'w': prot |= PROT_WRITE; break; case 'x': prot |= PROT_EXEC; break; case 'S': flags = MAP_SYNC | MAP_SHARED_VALIDATE; /* * If MAP_SYNC and MAP_SHARED_VALIDATE aren't defined * in the system headers we will have defined them * both as 0. */ if (!flags) { printf("MAP_SYNC not supported\n"); return 0; } break; case 's': length2 = cvtnum(blocksize, sectsize, optarg); break; default: return command_usage(&mmap_cmd); } } if (!prot) prot = PROT_READ | PROT_WRITE | PROT_EXEC; if (optind != argc - 2) return command_usage(&mmap_cmd); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; length = cvtnum(blocksize, sectsize, argv[optind]); if (length < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } filename = strdup(file->name); if (!filename) { perror("strdup"); return 0; } /* * mmap and munmap memory area of length2 region is helpful to * make a region of extendible free memory. It's generally used * for later mremap operation(no MREMAP_MAYMOVE flag). But there * isn't guarantee that the memory after length (up to length2) * will stay free. */ if (length2 > length) { address = mmap(NULL, length2, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); munmap(address, length2); } address = mmap(address, length, prot, flags, file->fd, offset); if (address == MAP_FAILED) { perror("mmap"); free(filename); return 0; } /* Extend the control array of mmap'd regions */ maptable = (mmap_region_t *)realloc(maptable, /* growing */ ++mapcount * sizeof(mmap_region_t)); if (!maptable) { perror("realloc"); mapcount = 0; munmap(address, length); free(filename); return 0; } /* Finally, make this the new active mapping */ mapping = &maptable[mapcount - 1]; mapping->addr = address; mapping->length = length; mapping->offset = offset; mapping->name = filename; mapping->prot = prot; mapping->map_sync = (flags == (MAP_SYNC | MAP_SHARED_VALIDATE)); return 0; } static void msync_help(void) { printf(_( "\n" " flushes a range of bytes in the current memory mapping\n" "\n" " Writes all modified copies of pages over the specified range (or entire\n" " mapping if no range specified) to their backing storage locations. Also,\n" " optionally invalidates so that subsequent references to the pages will be\n" " obtained from their backing storage locations (instead of cached copies).\n" " -a -- perform asynchronous writes (MS_ASYNC)\n" " -i -- invalidate mapped pages (MS_INVALIDATE)\n" " -s -- perform synchronous writes (MS_SYNC)\n" "\n")); } static int msync_f( int argc, char **argv) { off64_t offset; ssize_t length; void *start; int c, flags = 0; size_t blocksize, sectsize; while ((c = getopt(argc, argv, "ais")) != EOF) { switch (c) { case 'a': flags |= MS_ASYNC; break; case 'i': flags |= MS_INVALIDATE; break; case 's': flags |= MS_SYNC; break; default: return command_usage(&msync_cmd); } } if (optind == argc) { offset = mapping->offset; length = mapping->length; } else if (optind == argc - 2) { init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; length = cvtnum(blocksize, sectsize, argv[optind]); if (length < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } } else { return command_usage(&msync_cmd); } start = check_mapping_range(mapping, offset, length, 1); if (!start) return 0; if (msync(start, length, flags) < 0) perror("msync"); return 0; } static void mread_help(void) { printf(_( "\n" " reads a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n" "\n" " Accesses a range of the current memory mapping, optionally dumping it to\n" " the standard output stream (with -v option) for subsequent inspection.\n" " -f -- verbose mode, dump bytes with offsets relative to start of file.\n" " -r -- reverse order; start accessing from the end of range, moving backward\n" " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n" " The accesses are performed sequentially from the start offset by default.\n" " Notes:\n" " References to whole pages following the end of the backing file results\n" " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n" " on various filesystem conditions, including quota exceeded errors, and\n" " for physical device errors (such as unreadable disk blocks). No attempt\n" " has been made to catch signals at this stage...\n" "\n")); } static int mread_f( int argc, char **argv) { off64_t offset, tmp, dumpoffset, printoffset; ssize_t length; size_t dumplen, cnt = 0; char *bp; void *start; int dump = 0, rflag = 0, c; size_t blocksize, sectsize; while ((c = getopt(argc, argv, "frv")) != EOF) { switch (c) { case 'f': dump = 2; /* file offset dump */ break; case 'r': rflag = 1; /* read in reverse */ break; case 'v': dump = 1; /* mapping offset dump */ break; default: return command_usage(&mread_cmd); } } if (optind == argc) { offset = mapping->offset; length = mapping->length; } else if (optind == argc - 2) { init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; length = cvtnum(blocksize, sectsize, argv[optind]); if (length < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } } else { return command_usage(&mread_cmd); } start = check_mapping_range(mapping, offset, length, 0); if (!start) return 0; dumpoffset = offset - mapping->offset; if (dump == 2) printoffset = offset; else printoffset = dumpoffset; if (alloc_buffer(pagesize, 0, 0) < 0) return 0; bp = (char *)io_buffer; dumplen = length % pagesize; if (!dumplen) dumplen = pagesize; if (rflag) { for (tmp = length - 1, c = 0; tmp >= 0; tmp--, c = 1) { *bp = *(((char *)mapping->addr) + dumpoffset + tmp); cnt++; if (c && cnt == dumplen) { if (dump) { dump_buffer(printoffset, dumplen); printoffset += dumplen; } bp = (char *)io_buffer; dumplen = pagesize; cnt = 0; } else { bp++; } } } else { for (tmp = 0, c = 0; tmp < length; tmp++, c = 1) { *bp = *(((char *)mapping->addr) + dumpoffset + tmp); cnt++; if (c && cnt == dumplen) { if (dump) dump_buffer(printoffset + tmp - (dumplen - 1), dumplen); bp = (char *)io_buffer; dumplen = pagesize; cnt = 0; } else { bp++; } } } return 0; } static int munmap_f( int argc, char **argv) { ssize_t length; unsigned int offset; if (munmap(mapping->addr, mapping->length) < 0) { perror("munmap"); return 0; } free(mapping->name); /* Shuffle the mapping table entries down over the removed entry */ offset = mapping - &maptable[0]; length = mapcount * sizeof(mmap_region_t); length -= (offset + 1) * sizeof(mmap_region_t); if (length) memmove(mapping, mapping + 1, length); /* Resize the memory allocated for the table, possibly freeing */ if (--mapcount) { maptable = (mmap_region_t *)realloc(maptable, /* shrinking */ mapcount * sizeof(mmap_region_t)); if (offset == mapcount) offset--; mapping = maptable + offset; } else { free(maptable); mapping = maptable = NULL; } maplist_f(); return 0; } static void mwrite_help(void) { printf(_( "\n" " dirties a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n" "\n" " Stores a byte into memory for a range within a mapping.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -S -- use an alternate seed character\n" " -r -- reverse order; start storing from the end of range, moving backward\n" " The stores are performed sequentially from the start offset by default.\n" "\n")); } static int mwrite_f( int argc, char **argv) { off64_t offset, tmp; ssize_t length; void *start; char *sp; int seed = 'X'; int rflag = 0; int c; size_t blocksize, sectsize; while ((c = getopt(argc, argv, "rS:")) != EOF) { switch (c) { case 'r': rflag = 1; break; case 'S': seed = (int)strtol(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric seed -- %s\n"), optarg); return 0; } break; default: return command_usage(&mwrite_cmd); } } if (optind == argc) { offset = mapping->offset; length = mapping->length; } else if (optind == argc - 2) { init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; length = cvtnum(blocksize, sectsize, argv[optind]); if (length < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } } else { return command_usage(&mwrite_cmd); } start = check_mapping_range(mapping, offset, length, 0); if (!start) return 0; offset -= mapping->offset; if (rflag) { for (tmp = offset + length -1; tmp >= offset; tmp--) ((char *)mapping->addr)[tmp] = seed; } else { for (tmp = offset; tmp < offset + length; tmp++) ((char *)mapping->addr)[tmp] = seed; } return 0; } #ifdef HAVE_MREMAP static void mremap_help(void) { printf(_( "\n" " resizes the current memory mapping\n" "\n" " Examples:\n" " 'mremap 8192' - resizes the current mapping to 8192 bytes.\n" "\n" " Resizes the mapping, growing or shrinking from the current size.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -f -- use MREMAP_FIXED flag to mremap on new_address\n" " -m -- use the MREMAP_MAYMOVE flag\n" "\n")); } static int mremap_f( int argc, char **argv) { ssize_t new_length; void *new_addr = NULL; int flags = 0; int c; size_t blocksize, sectsize; init_cvtnum(&blocksize, §size); while ((c = getopt(argc, argv, "f:m")) != EOF) { switch (c) { case 'f': flags = MREMAP_FIXED|MREMAP_MAYMOVE; new_addr = (void *)(unsigned long)cvtnum(blocksize, sectsize, optarg); break; case 'm': flags = MREMAP_MAYMOVE; break; default: return command_usage(&mremap_cmd); } } if (optind != argc - 1) return command_usage(&mremap_cmd); new_length = cvtnum(blocksize, sectsize, argv[optind]); if (new_length < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } if (!new_addr) new_addr = mremap(mapping->addr, mapping->length, new_length, flags); else new_addr = mremap(mapping->addr, mapping->length, new_length, flags, new_addr); if (new_addr == MAP_FAILED) perror("mremap"); else { mapping->addr = new_addr; mapping->length = new_length; } return 0; } #endif /* HAVE_MREMAP */ void mmap_init(void) { mmap_cmd.name = "mmap"; mmap_cmd.altname = "mm"; mmap_cmd.cfunc = mmap_f; mmap_cmd.argmin = 0; mmap_cmd.argmax = -1; mmap_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; mmap_cmd.args = _("[N] | [-rwxS] [-s size] [off len]"); mmap_cmd.oneline = _("mmap a range in the current file, show mappings"); mmap_cmd.help = mmap_help; mread_cmd.name = "mread"; mread_cmd.altname = "mr"; mread_cmd.cfunc = mread_f; mread_cmd.argmin = 0; mread_cmd.argmax = -1; mread_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; mread_cmd.args = _("[-r] [off len]"); mread_cmd.oneline = _("reads data from a region in the current memory mapping"); mread_cmd.help = mread_help; msync_cmd.name = "msync"; msync_cmd.altname = "ms"; msync_cmd.cfunc = msync_f; msync_cmd.argmin = 0; msync_cmd.argmax = -1; msync_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; msync_cmd.args = _("[-ais] [off len]"); msync_cmd.oneline = _("flush a region in the current memory mapping"); msync_cmd.help = msync_help; munmap_cmd.name = "munmap"; munmap_cmd.altname = "mu"; munmap_cmd.cfunc = munmap_f; munmap_cmd.argmin = 0; munmap_cmd.argmax = 0; munmap_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; munmap_cmd.oneline = _("unmaps the current memory mapping"); mwrite_cmd.name = "mwrite"; mwrite_cmd.altname = "mw"; mwrite_cmd.cfunc = mwrite_f; mwrite_cmd.argmin = 0; mwrite_cmd.argmax = -1; mwrite_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; mwrite_cmd.args = _("[-r] [-S seed] [off len]"); mwrite_cmd.oneline = _("writes data into a region in the current memory mapping"); mwrite_cmd.help = mwrite_help; #ifdef HAVE_MREMAP mremap_cmd.name = "mremap"; mremap_cmd.altname = "mrm"; mremap_cmd.cfunc = mremap_f; mremap_cmd.argmin = 1; mremap_cmd.argmax = 3; mremap_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; mremap_cmd.args = _("[-m|-f ] newsize"); mremap_cmd.oneline = _("alters the size of the current memory mapping"); mremap_cmd.help = mremap_help; #endif /* HAVE_MREMAP */ add_command(&mmap_cmd); add_command(&mread_cmd); add_command(&msync_cmd); add_command(&munmap_cmd); add_command(&mwrite_cmd); #ifdef HAVE_MREMAP add_command(&mremap_cmd); #endif /* HAVE_MREMAP */ } xfsprogs-5.3.0/io/open.c0000644000175000017500000005034013570057155014772 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include "libxfs.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" #ifndef __O_TMPFILE #if defined __alpha__ #define __O_TMPFILE 0100000000 #elif defined(__hppa__) #define __O_TMPFILE 040000000 #elif defined(__sparc__) #define __O_TMPFILE 0x2000000 #else #define __O_TMPFILE 020000000 #endif #endif /* __O_TMPFILE */ #ifndef O_TMPFILE #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) #endif #ifndef O_PATH #if defined __alpha__ #define O_PATH 040000000 #elif defined(__hppa__) #define O_PATH 020000000 #elif defined(__sparc__) #define O_PATH 0x1000000 #else #define O_PATH 010000000 #endif #endif /* O_PATH */ static cmdinfo_t open_cmd; static cmdinfo_t close_cmd; static cmdinfo_t chproj_cmd; static cmdinfo_t lsproj_cmd; static cmdinfo_t extsize_cmd; static cmdinfo_t inode_cmd; static cmdinfo_t chmod_cmd; static prid_t prid; static long extsize; int openfile( char *path, struct xfs_fsop_geom *geom, int flags, mode_t mode, struct fs_path *fs_path) { struct fs_path *fsp; struct stat st = { 0 }; int fd; int oflags; oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR; if (flags & IO_APPEND) oflags |= O_APPEND; if (flags & IO_CREAT) oflags |= O_CREAT; if (flags & IO_DIRECT) oflags |= O_DIRECT; if (flags & IO_OSYNC) oflags |= O_SYNC; if (flags & IO_TRUNC) oflags |= O_TRUNC; if (flags & IO_NONBLOCK) oflags |= O_NONBLOCK; if (flags & IO_TMPFILE) oflags |= O_TMPFILE; if (flags & IO_PATH) oflags |= O_PATH; if (flags & IO_NOFOLLOW) oflags |= O_NOFOLLOW; /* * if we've been passed a pipe to open, don't block waiting for a * reader or writer to appear. We want to either succeed or error out * immediately. */ if (stat(path, &st) < 0 && errno != ENOENT) { perror("stat"); return -1; } if (S_ISFIFO(st.st_mode)) oflags |= O_NONBLOCK; fd = open(path, oflags, mode); if (fd < 0) { if (errno == EISDIR && ((oflags & (O_RDWR|O_TMPFILE)) == O_RDWR)) { /* make it as if we asked for O_RDONLY & try again */ oflags &= ~O_RDWR; oflags |= O_RDONLY; flags |= IO_READONLY; fd = open(path, oflags, mode); if (fd < 0) { perror(path); return -1; } } else { perror(path); return -1; } } if (!geom || !platform_test_xfs_fd(fd)) return fd; if (flags & IO_PATH) { /* Can't call ioctl() on O_PATH fds */ memset(geom, 0, sizeof(*geom)); } else { int ret; ret = -xfrog_geometry(fd, geom); if (ret) { xfrog_perror(ret, "XFS_IOC_FSGEOMETRY"); close(fd); return -1; } } if (!(flags & (IO_READONLY | IO_PATH)) && (flags & IO_REALTIME)) { struct fsxattr attr; if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &attr) < 0) { perror("FS_IOC_FSGETXATTR"); close(fd); return -1; } if (!(attr.fsx_xflags & FS_XFLAG_REALTIME)) { attr.fsx_xflags |= FS_XFLAG_REALTIME; if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &attr) < 0) { perror("FS_IOC_FSSETXATTR"); close(fd); return -1; } } } if (fs_path) { fsp = fs_table_lookup(path, FS_MOUNT_POINT); if (!fsp) memset(fs_path, 0, sizeof(*fs_path)); else *fs_path = *fsp; } return fd; } int addfile( char *name, int fd, struct xfs_fsop_geom *geometry, int flags, struct fs_path *fs_path) { char *filename; filename = strdup(name); if (!filename) { perror("strdup"); close(fd); return -1; } /* Extend the table of currently open files */ filetable = (fileio_t *)realloc(filetable, /* growing */ ++filecount * sizeof(fileio_t)); if (!filetable) { perror("realloc"); filecount = 0; free(filename); close(fd); return -1; } /* Finally, make this the new active open file */ file = &filetable[filecount - 1]; file->fd = fd; file->flags = flags; file->name = filename; file->geom = *geometry; file->fs_path = *fs_path; return 0; } static void open_help(void) { printf(_( "\n" " opens a new file in the requested mode\n" "\n" " Example:\n" " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n" "\n" " Opens a file for subsequent use by all of the other xfs_io commands.\n" " With no arguments, open uses the stat command to show the current file.\n" " -a -- open with the O_APPEND flag (append-only mode)\n" " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n" " -f -- open with O_CREAT (create the file if it doesn't exist)\n" " -m -- permissions to use in case a new file is created (default 0600)\n" " -n -- open with O_NONBLOCK\n" " -r -- open with O_RDONLY, the default is O_RDWR\n" " -s -- open with O_SYNC\n" " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n" " -R -- mark the file as a realtime XFS file immediately after opening it\n" " -T -- open with O_TMPFILE (create a file not visible in the namespace)\n" " -P -- open with O_PATH (create an fd that is merely a location reference)\n" " -L -- open with O_NOFOLLOW (don't follow symlink)\n" " Note1: usually read/write direct IO requests must be blocksize aligned;\n" " some kernels, however, allow sectorsize alignment for direct IO.\n" " Note2: the bmap for non-regular files can be obtained provided the file\n" " was opened correctly (in particular, must be opened read-only).\n" "\n")); } static int open_f( int argc, char **argv) { int c, fd, flags = 0; char *sp; mode_t mode = 0600; struct xfs_fsop_geom geometry = { 0 }; struct fs_path fsp; if (argc == 1) { if (file) return stat_f(argc, argv); fprintf(stderr, _("no files are open, try 'help open'\n")); return 0; } while ((c = getopt(argc, argv, "FLPRTacdfm:nrstx")) != EOF) { switch (c) { case 'F': /* Ignored / deprecated now, handled automatically */ break; case 'a': flags |= IO_APPEND; break; case 'c': case 'f': flags |= IO_CREAT; break; case 'd': flags |= IO_DIRECT; break; case 'm': mode = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric mode -- %s\n"), optarg); return 0; } break; case 'n': flags |= IO_NONBLOCK; break; case 'r': flags |= IO_READONLY; break; case 's': flags |= IO_OSYNC; break; case 't': flags |= IO_TRUNC; break; case 'R': case 'x': /* backwards compatibility */ flags |= IO_REALTIME; break; case 'T': flags |= IO_TMPFILE; break; case 'P': flags |= IO_PATH; break; case 'L': flags |= IO_NOFOLLOW; break; default: return command_usage(&open_cmd); } } if (optind != argc - 1) return command_usage(&open_cmd); if ((flags & (IO_READONLY|IO_TMPFILE)) == (IO_READONLY|IO_TMPFILE)) { fprintf(stderr, _("-T and -r options are incompatible\n")); return -1; } if ((flags & (IO_PATH|IO_NOFOLLOW)) && (flags & ~(IO_PATH|IO_NOFOLLOW))) { fprintf(stderr, _("-P and -L are incompatible with the other options\n")); return -1; } fd = openfile(argv[optind], &geometry, flags, mode, &fsp); if (fd < 0) return 0; if (!platform_test_xfs_fd(fd)) flags |= IO_FOREIGN; addfile(argv[optind], fd, &geometry, flags, &fsp); return 0; } static int close_f( int argc, char **argv) { size_t length; unsigned int offset; if (close(file->fd) < 0) { perror("close"); return 0; } free(file->name); /* Shuffle the file table entries down over the removed entry */ offset = file - &filetable[0]; length = filecount * sizeof(fileio_t); length -= (offset + 1) * sizeof(fileio_t); if (length) memmove(file, file + 1, length); /* Resize the memory allocated for the table, possibly freeing */ if (--filecount) { filetable = (fileio_t *)realloc(filetable, /* shrinking */ filecount * sizeof(fileio_t)); if (offset == filecount) offset--; file = filetable + offset; } else { free(filetable); file = filetable = NULL; } filelist_f(); return 0; } static void lsproj_help(void) { printf(_( "\n" " displays the project identifier associated with the current path\n" "\n" " Options:\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, but only list projects on directories\n" "\n")); } static int lsproj_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { prid_t projid; int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; if ((fd = open(path, O_RDONLY)) == -1) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else { if (getprojid(path, fd, &projid) == 0) printf("[%u] %s\n", (unsigned int)projid, path); close(fd); } return 0; } static int lsproj_f( int argc, char **argv) { prid_t projid; int c; recurse_all = recurse_dir = 0; while ((c = getopt(argc, argv, "DR")) != EOF) { switch (c) { case 'D': recurse_all = 0; recurse_dir = 1; break; case 'R': recurse_all = 1; recurse_dir = 0; break; default: return command_usage(&lsproj_cmd); } } if (argc != optind) return command_usage(&lsproj_cmd); if (recurse_all || recurse_dir) nftw(file->name, lsproj_callback, 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); else if (getprojid(file->name, file->fd, &projid) < 0) perror("getprojid"); else printf(_("projid = %u\n"), (unsigned int)projid); return 0; } static void chproj_help(void) { printf(_( "\n" " modifies the project identifier associated with the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying projects on directories\n" "\n")); } static int chproj_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; if ((fd = open(path, O_RDONLY)) == -1) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else { if (setprojid(path, fd, prid) < 0) perror("setprojid"); close(fd); } return 0; } static int chproj_f( int argc, char **argv) { int c; recurse_all = recurse_dir = 0; while ((c = getopt(argc, argv, "DR")) != EOF) { switch (c) { case 'D': recurse_all = 0; recurse_dir = 1; break; case 'R': recurse_all = 1; recurse_dir = 0; break; default: return command_usage(&chproj_cmd); } } if (argc != optind + 1) return command_usage(&chproj_cmd); prid = prid_from_string(argv[optind]); if (prid == -1) { printf(_("invalid project ID -- %s\n"), argv[optind]); return 0; } if (recurse_all || recurse_dir) nftw(file->name, chproj_callback, 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); else if (setprojid(file->name, file->fd, prid) < 0) perror("setprojid"); return 0; } static void extsize_help(void) { printf(_( "\n" " report or modify preferred extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying extsize on directories\n" "\n")); } static int get_extsize(const char *path, int fd) { struct fsxattr fsx; if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { printf("%s: FS_IOC_FSGETXATTR %s: %s\n", progname, path, strerror(errno)); return 0; } printf("[%u] %s\n", fsx.fsx_extsize, path); return 0; } static int set_extsize(const char *path, int fd, long extsz) { struct fsxattr fsx; struct stat stat; if (fstat(fd, &stat) < 0) { perror("fstat"); return 0; } if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { printf("%s: FS_IOC_FSGETXATTR %s: %s\n", progname, path, strerror(errno)); return 0; } if (S_ISREG(stat.st_mode)) { fsx.fsx_xflags |= FS_XFLAG_EXTSIZE; } else if (S_ISDIR(stat.st_mode)) { fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT; } else { printf(_("invalid target file type - file %s\n"), path); return 0; } fsx.fsx_extsize = extsz; if ((xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx)) < 0) { printf("%s: FS_IOC_FSSETXATTR %s: %s\n", progname, path, strerror(errno)); return 0; } return 0; } static int get_extsize_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; if ((fd = open(path, O_RDONLY)) == -1) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else { get_extsize(path, fd); close(fd); } return 0; } static int set_extsize_callback( const char *path, const struct stat *stat, int status, struct FTW *data) { int fd; if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; if ((fd = open(path, O_RDONLY)) == -1) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else { set_extsize(path, fd, extsize); close(fd); } return 0; } static int extsize_f( int argc, char **argv) { size_t blocksize, sectsize; int c; recurse_all = recurse_dir = 0; init_cvtnum(&blocksize, §size); while ((c = getopt(argc, argv, "DR")) != EOF) { switch (c) { case 'D': recurse_all = 0; recurse_dir = 1; break; case 'R': recurse_all = 1; recurse_dir = 0; break; default: return command_usage(&extsize_cmd); } } if (optind < argc) { extsize = (long)cvtnum(blocksize, sectsize, argv[optind]); if (extsize < 0) { printf(_("non-numeric extsize argument -- %s\n"), argv[optind]); return 0; } } else { extsize = -1; } if (recurse_all || recurse_dir) nftw(file->name, (extsize >= 0) ? set_extsize_callback : get_extsize_callback, 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); else if (extsize >= 0) set_extsize(file->name, file->fd, extsize); else get_extsize(file->name, file->fd); return 0; } static void inode_help(void) { printf(_( "\n" "Query physical information about an inode" "\n" " Default: -- Return 1 if any inode number greater than 32 bits exists in\n" " the filesystem, or 0 if none exist\n" " num -- Return inode number [num] if in use, or 0 if not in use\n" " -n num -- Return the next used inode after [num]\n" " -v -- Verbose mode - display returned inode number's size in bits\n" "\n")); } #define IGROUP_NR (1024) static __u64 get_last_inode(void) { struct xfs_fd xfd = XFS_FD_INIT(file->fd); struct xfs_inumbers_req *ireq; uint32_t lastgrp = 0; __u64 last_ino = 0; int ret; ret = -xfrog_inumbers_alloc_req(IGROUP_NR, 0, &ireq); if (ret) { xfrog_perror(ret, "alloc req"); return 0; } for (;;) { ret = -xfrog_inumbers(&xfd, ireq); if (ret) { xfrog_perror(ret, "XFS_IOC_FSINUMBERS"); goto out; } /* Did we reach the last inode? */ if (ireq->hdr.ocount == 0) break; /* last inode in igroup table */ lastgrp = ireq->hdr.ocount; } if (lastgrp == 0) goto out; lastgrp--; /* The last inode number in use */ last_ino = ireq->inumbers[lastgrp].xi_startino + libxfs_highbit64(ireq->inumbers[lastgrp].xi_allocmask); out: free(ireq); return last_ino; } static int inode_f( int argc, char **argv) { struct xfs_bulkstat bulkstat; uint64_t result_ino = 0; uint64_t userino = NULLFSINO; char *p; int c; int verbose = 0; int ret_next = 0; int ret; while ((c = getopt(argc, argv, "nv")) != EOF) { switch (c) { case 'v': verbose = 1; break; case 'n': ret_next = 1; break; default: return command_usage(&inode_cmd); } } /* Last arg (if present) should be an inode number */ if (optind < argc) { userino = strtoull(argv[optind], &p, 10); if ((*p != '\0')) { printf(_("%s is not a numeric inode value\n"), argv[optind]); exitcode = 1; return 0; } optind++; } /* Extra junk? */ if (optind < argc) return command_usage(&inode_cmd); /* -n option requires an inode number */ if (ret_next && userino == NULLFSINO) return command_usage(&inode_cmd); if (userino == NULLFSINO) { /* We are finding last inode in use */ result_ino = get_last_inode(); if (!result_ino) { exitcode = 1; return 0; } } else if (ret_next) { struct xfs_fd xfd = XFS_FD_INIT(file->fd); struct xfs_bulkstat_req *breq; /* * The -n option means that the caller wants to know the number * of the next allocated inode, so we need to increment here. */ ret = -xfrog_bulkstat_alloc_req(1, userino + 1, &breq); if (ret) { xfrog_perror(ret, "alloc bulkstat"); exitcode = 1; return 0; } /* get next inode */ ret = -xfrog_bulkstat(&xfd, breq); if (ret) { xfrog_perror(ret, "bulkstat"); free(breq); exitcode = 1; return 0; } /* The next inode in use, or 0 if none */ if (breq->hdr.ocount) result_ino = breq->bulkstat[0].bs_ino; else result_ino = 0; free(breq); } else { struct xfs_fd xfd = XFS_FD_INIT(file->fd); /* get this inode */ ret = -xfrog_bulkstat_single(&xfd, userino, 0, &bulkstat); if (ret == EINVAL) { /* Not in use */ result_ino = 0; } else if (ret) { xfrog_perror(ret, "bulkstat_single"); exitcode = 1; return 0; } else { result_ino = bulkstat.bs_ino; } } if (verbose && result_ino) { /* Requested verbose and we have an answer */ printf("%llu:%d\n", (unsigned long long)result_ino, result_ino > XFS_MAXINUMBER_32 ? 64 : 32); } else if (userino == NULLFSINO) { /* Just checking 32 or 64 bit presence, non-verbose */ printf("%d\n", result_ino > XFS_MAXINUMBER_32 ? 1 : 0); } else { /* We asked about a specific inode, non-verbose */ printf("%llu\n", (unsigned long long)result_ino); } return 0; } static void chmod_help(void) { printf(_( "\n" " Change the read/write permissions on the current file\n" "\n" " Options:\n" " -r -- make the file read only (0444 permissions)\n" " -w -- make the file read/write (0664 permissions)\n" "\n")); } static int chmod_f( int argc, char **argv) { mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; int c; while ((c = getopt(argc, argv, "rw")) != EOF) { switch (c) { case 'r': break; case 'w': mode |= S_IWUSR | S_IWGRP; break; default: return command_usage(&chmod_cmd); } } if (argc != optind) return command_usage(&chmod_cmd); if (fchmod(file->fd, mode) < 0) { exitcode = 1; perror("fchmod"); } return 0; } void open_init(void) { open_cmd.name = "open"; open_cmd.altname = "o"; open_cmd.cfunc = open_f; open_cmd.argmin = 0; open_cmd.argmax = -1; open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; open_cmd.args = _("[-acdrstxRTPL] [-m mode] [path]"); open_cmd.oneline = _("open the file specified by path"); open_cmd.help = open_help; close_cmd.name = "close"; close_cmd.altname = "c"; close_cmd.cfunc = close_f; close_cmd.argmin = 0; close_cmd.argmax = 0; close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; close_cmd.oneline = _("close the current open file"); chproj_cmd.name = "chproj"; chproj_cmd.cfunc = chproj_f; chproj_cmd.args = _("[-D | -R] projid"); chproj_cmd.argmin = 1; chproj_cmd.argmax = -1; chproj_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; chproj_cmd.oneline = _("change project identifier on the currently open file"); chproj_cmd.help = chproj_help; lsproj_cmd.name = "lsproj"; lsproj_cmd.cfunc = lsproj_f; lsproj_cmd.args = _("[-D | -R]"); lsproj_cmd.argmin = 0; lsproj_cmd.argmax = -1; lsproj_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; lsproj_cmd.oneline = _("list project identifier set on the currently open file"); lsproj_cmd.help = lsproj_help; extsize_cmd.name = "extsize"; extsize_cmd.cfunc = extsize_f; extsize_cmd.args = _("[-D | -R] [extsize]"); extsize_cmd.argmin = 0; extsize_cmd.argmax = -1; extsize_cmd.flags = CMD_NOMAP_OK; extsize_cmd.oneline = _("get/set preferred extent size (in bytes) for the open file"); extsize_cmd.help = extsize_help; inode_cmd.name = "inode"; inode_cmd.cfunc = inode_f; inode_cmd.args = _("[-nv] [num]"); inode_cmd.argmin = 0; inode_cmd.argmax = 3; inode_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT; inode_cmd.oneline = _("Query inode number usage in the filesystem"); inode_cmd.help = inode_help; chmod_cmd.name = "chmod"; chmod_cmd.cfunc = chmod_f; chmod_cmd.args = _("-r | -w"); chmod_cmd.argmin = 1; chmod_cmd.argmax = 1; chmod_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; chmod_cmd.oneline = _("change the read/write permissions on the currently open file"); chmod_cmd.help = chmod_help; add_command(&open_cmd); add_command(&close_cmd); add_command(&chproj_cmd); add_command(&lsproj_cmd); add_command(&extsize_cmd); add_command(&inode_cmd); add_command(&chmod_cmd); } xfsprogs-5.3.0/io/parent.c0000644000175000017500000002360013570057155015321 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "libfrog/paths.h" #include "parent.h" #include "handle.h" #include "jdm.h" #include "init.h" #include "io.h" #define PARENTBUF_SZ 16384 #define BSTATBUF_SZ 16384 static cmdinfo_t parent_cmd; static int verbose_flag; static int err_status; static __u64 inodes_checked; static char *mntpt; /* * check out a parent entry to see if the values seem valid */ static void check_parent_entry(struct xfs_bstat *bstatp, parent_t *parent) { int sts; char fullpath[PATH_MAX]; struct stat statbuf; char *str; sprintf(fullpath, _("%s%s"), mntpt, parent->p_name); sts = lstat(fullpath, &statbuf); if (sts != 0) { fprintf(stderr, _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), (unsigned long long) bstatp->bs_ino, fullpath); if (verbose_flag) { fprintf(stderr, _("path \"%s\" does not stat for inode: %llu; err = %s\n"), fullpath, (unsigned long long) bstatp->bs_ino, strerror(errno)); } err_status++; return; } else { if (verbose_flag > 1) { printf(_("path \"%s\" found\n"), fullpath); } } if (statbuf.st_ino != bstatp->bs_ino) { fprintf(stderr, _("inode-path for inode: %llu is incorrect - wrong inode#\n"), (unsigned long long) bstatp->bs_ino); if (verbose_flag) { fprintf(stderr, _("ino mismatch for path \"%s\" %llu vs %llu\n"), fullpath, (unsigned long long)statbuf.st_ino, (unsigned long long)bstatp->bs_ino); } err_status++; return; } else if (verbose_flag > 1) { printf(_("inode number match: %llu\n"), (unsigned long long)statbuf.st_ino); } /* get parent path */ str = strrchr(fullpath, '/'); *str = '\0'; sts = stat(fullpath, &statbuf); if (sts != 0) { fprintf(stderr, _("parent path \"%s\" does not stat: %s\n"), fullpath, strerror(errno)); err_status++; return; } else { if (parent->p_ino != statbuf.st_ino) { fprintf(stderr, _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), (unsigned long long) bstatp->bs_ino); if (verbose_flag) { fprintf(stderr, _("ino mismatch for path \"%s\" %llu vs %llu\n"), fullpath, (unsigned long long)parent->p_ino, (unsigned long long)statbuf.st_ino); } err_status++; return; } else { if (verbose_flag > 1) { printf(_("parent ino match for %llu\n"), (unsigned long long) parent->p_ino); } } } } static void check_parents(parent_t *parentbuf, size_t *parentbuf_size, jdm_fshandle_t *fshandlep, struct xfs_bstat *statp) { int error, i; __u32 count; parent_t *entryp; do { error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); if (error == ERANGE) { *parentbuf_size *= 2; parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); } else if (error) { fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), (unsigned long long) statp->bs_ino, strerror(errno)); err_status++; break; } } while (error == ERANGE); if (count == 0) { /* no links for inode - something wrong here */ fprintf(stderr, _("inode-path for inode: %llu is missing\n"), (unsigned long long) statp->bs_ino); err_status++; } entryp = parentbuf; for (i = 0; i < count; i++) { check_parent_entry(statp, entryp); entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); } } static int do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, struct xfs_bstat *bstatbuf, int fsfd, jdm_fshandle_t *fshandlep) { __s32 buflenout; __u64 lastino = 0; struct xfs_bstat *p; struct xfs_bstat *endp; struct xfs_fsop_bulkreq bulkreq; struct stat mntstat; if (stat(mntpt, &mntstat)) { fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), mntpt, strerror(errno)); return 1; } bulkreq.lastip = &lastino; bulkreq.icount = BSTATBUF_SZ; bulkreq.ubuffer = (void *)bstatbuf; bulkreq.ocount = &buflenout; while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { if (*(bulkreq.ocount) == 0) { return 0; } for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { /* inode being modified, get synced data with iget */ if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { fprintf(stderr, _("failed to get bulkstat information for inode %llu\n"), (unsigned long long) p->bs_ino); continue; } if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { fprintf(stderr, _("failed to get valid bulkstat information for inode %llu\n"), (unsigned long long) p->bs_ino); continue; } } /* skip root */ if (p->bs_ino == mntstat.st_ino) { continue; } if (verbose_flag > 1) { printf(_("checking inode %llu\n"), (unsigned long long) p->bs_ino); } /* print dotted progress */ if ((inodes_checked % 100) == 0 && verbose_flag == 1) { printf("."); fflush(stdout); } inodes_checked++; check_parents(parentbuf, parentbuf_size, fshandlep, p); } }/*while*/ fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); return 1; } static int parent_check(void) { int fsfd; jdm_fshandle_t *fshandlep; parent_t *parentbuf; size_t parentbuf_size = PARENTBUF_SZ; struct xfs_bstat *bstatbuf; err_status = 0; inodes_checked = 0; sync(); fsfd = file->fd; fshandlep = jdm_getfshandle(mntpt); if (fshandlep == NULL) { fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), mntpt, strerror(errno)); return 1; } /* allocate buffers */ bstatbuf = (struct xfs_bstat *)calloc(BSTATBUF_SZ, sizeof(struct xfs_bstat)); parentbuf = (parent_t *)malloc(parentbuf_size); if (!bstatbuf || !parentbuf) { fprintf(stderr, _("unable to allocate buffers: %s\n"), strerror(errno)); err_status = 1; goto out; } if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) err_status++; if (err_status > 0) fprintf(stderr, _("num errors: %d\n"), err_status); else printf(_("succeeded checking %llu inodes\n"), (unsigned long long) inodes_checked); out: free(bstatbuf); free(parentbuf); free(fshandlep); return err_status; } static void print_parent_entry(parent_t *parent, int fullpath) { printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); printf(_("p_gen = %u\n"), parent->p_gen); printf(_("p_reclen = %u\n"), parent->p_reclen); if (fullpath) printf(_("p_name = \"%s%s\"\n"), mntpt, parent->p_name); else printf(_("p_name = \"%s\"\n"), parent->p_name); } static int parent_list(int fullpath) { void *handlep = NULL; size_t handlen; int error, i; int retval = 1; __u32 count; parent_t *entryp; parent_t *parentbuf = NULL; char *path = file->name; int pb_size = PARENTBUF_SZ; /* XXXX for linux libhandle version - to set libhandle fsfd cache */ { void *fshandle; size_t fshlen; if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), progname, path, strerror(errno)); goto error; } free_handle(fshandle, fshlen); } if (path_to_handle(path, &handlep, &handlen) != 0) { fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); goto error; } do { parentbuf = (parent_t *)realloc(parentbuf, pb_size); if (!parentbuf) { fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), progname, strerror(errno)); goto error; } if (fullpath) { error = parentpaths_by_handle(handlep, handlen, parentbuf, pb_size, &count); } else { error = parents_by_handle(handlep, handlen, parentbuf, pb_size, &count); } if (error == ERANGE) { pb_size *= 2; } else if (error) { fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), progname, fullpath ? "parentpaths" : "parents", path, strerror(errno)); goto error; } } while (error == ERANGE); if (count == 0) { /* no links for inode - something wrong here */ fprintf(stderr, _("%s: inode-path is missing\n"), progname); goto error; } entryp = parentbuf; for (i = 0; i < count; i++) { print_parent_entry(entryp, fullpath); entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); } retval = 0; error: free(handlep); free(parentbuf); return retval; } static int parent_f(int argc, char **argv) { int c; int listpath_flag = 0; int check_flag = 0; fs_path_t *fs; static int tab_init; if (!tab_init) { tab_init = 1; fs_table_initialise(0, NULL, 0, NULL); } fs = fs_table_lookup(file->name, FS_MOUNT_POINT); if (!fs) { fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"), file->name); return 1; } mntpt = fs->fs_dir; verbose_flag = 0; while ((c = getopt(argc, argv, "cpv")) != EOF) { switch (c) { case 'c': check_flag = 1; break; case 'p': listpath_flag = 1; break; case 'v': verbose_flag++; break; default: return command_usage(&parent_cmd); } } if (!check_flag && !listpath_flag) /* default case */ exitcode = parent_list(listpath_flag); else { if (listpath_flag) exitcode = parent_list(listpath_flag); if (check_flag) exitcode = parent_check(); } return 0; } static void parent_help(void) { printf(_( "\n" " list the current file's parents and their filenames\n" "\n" " -c -- check the current file's file system for parent consistency\n" " -p -- list the current file's parents and their full paths\n" " -v -- verbose mode\n" "\n")); } void parent_init(void) { parent_cmd.name = "parent"; parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; parent_cmd.args = _("[-cpv]"); parent_cmd.flags = CMD_NOMAP_OK; parent_cmd.oneline = _("print or check parent inodes"); parent_cmd.help = parent_help; if (expert) add_command(&parent_cmd); } xfsprogs-5.3.0/io/pread.c0000644000175000017500000002367313435336036015133 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #define _BSD_SOURCE #define _DEFAULT_SOURCE #include #include "command.h" #include "input.h" #include #include "init.h" #include "io.h" static cmdinfo_t pread_cmd; static void pread_help(void) { printf(_( "\n" " reads a range of bytes in a specified block size from the given offset\n" "\n" " Example:\n" " 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n" "\n" " Reads a segment of the currently open file, optionally dumping it to the\n" " standard output stream (with -v option) for subsequent inspection.\n" " The reads are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different pattern is requested.\n" " -B -- read backwards through the range from offset (backwards N bytes)\n" " -F -- read forwards through the range of bytes from offset (default)\n" " -v -- be verbose, dump out buffers (used when reading forwards)\n" " -R -- read at random offsets in the range of bytes\n" " -Z N -- zeed the random number generator (used when reading randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" #ifdef HAVE_PREADV " -V N -- use vectored IO with N iovecs of blocksize each (preadv)\n" #endif "\n" " When in \"random\" mode, the number of read operations will equal the\n" " number required to do a complete forward/backward scan of the range.\n" " Note that the offset within the range is chosen at random each time\n" " (an offset may be read more than once when operating in this mode).\n" "\n")); } void *io_buffer; size_t highwater; size_t io_buffersize; int vectors; struct iovec *iov; static int alloc_iovec( size_t bsize, int uflag, unsigned int seed) { int i; iov = calloc(vectors, sizeof(struct iovec)); if (!iov) return -1; io_buffersize = 0; for (i = 0; i < vectors; i++) { iov[i].iov_base = memalign(pagesize, bsize); if (!iov[i].iov_base) { perror("memalign"); goto unwind; } iov[i].iov_len = bsize; if (!uflag) memset(iov[i].iov_base, seed, bsize); } io_buffersize = bsize * vectors; return 0; unwind: for( ; i >= 0; i--) free(iov[i].iov_base); free(iov); iov = NULL; return -1; } int alloc_buffer( size_t bsize, int uflag, unsigned int seed) { if (vectors) return alloc_iovec(bsize, uflag, seed); if (bsize > highwater) { if (io_buffer) free(io_buffer); io_buffer = memalign(pagesize, bsize); if (!io_buffer) { perror("memalign"); highwater = io_buffersize = 0; return -1; } highwater = bsize; } io_buffersize = bsize; if (!uflag) memset(io_buffer, seed, io_buffersize); return 0; } void __dump_buffer( void *buf, off64_t offset, ssize_t len) { int i, j; char *p; for (i = 0, p = (char *)buf; i < len; i += 16) { char *s = p; printf("%08llx: ", (unsigned long long)offset + i); for (j = 0; j < 16 && i + j < len; j++, p++) printf("%02x ", *p); printf(" "); for (j = 0; j < 16 && i + j < len; j++, s++) { if (isalnum((int)*s)) printf("%c", *s); else printf("."); } printf("\n"); } } void dump_buffer( off64_t offset, ssize_t len) { int i, l; if (!vectors) { __dump_buffer(io_buffer, offset, len); return; } for (i = 0; len > 0 && i < vectors; i++) { l = min(len, iov[i].iov_len); __dump_buffer(iov[i].iov_base, offset, l); len -= l; offset += l; } } #ifdef HAVE_PREADV static ssize_t do_preadv( int fd, off64_t offset, size_t count) { int vecs = 0; ssize_t oldlen = 0; ssize_t bytes = 0; /* trim the iovec if necessary */ if (count < io_buffersize) { size_t len = 0; while (len + iov[vecs].iov_len < count) { len += iov[vecs].iov_len; vecs++; } oldlen = iov[vecs].iov_len; iov[vecs].iov_len = count - len; vecs++; } else { vecs = vectors; } bytes = preadv(fd, iov, vectors, offset); /* restore trimmed iov */ if (oldlen) iov[vecs - 1].iov_len = oldlen; return bytes; } #else #define do_preadv(fd, offset, count) (0) #endif static ssize_t do_pread( int fd, off64_t offset, size_t count, size_t buffer_size) { if (!vectors) return pread(fd, io_buffer, min(count, buffer_size), offset); return do_preadv(fd, offset, count); } static int read_random( int fd, off64_t offset, long long count, long long *total, unsigned int seed, int eof) { off64_t end, off, range; ssize_t bytes; int ops = 0; srandom(seed); end = lseek(fd, 0, SEEK_END); offset = (eof || offset > end) ? end : offset; if ((bytes = (offset % io_buffersize))) offset -= bytes; offset = max(0, offset); if ((bytes = (count % io_buffersize))) count += bytes; count = max(io_buffersize, count); range = count - io_buffersize; *total = 0; while (count > 0) { if (range) off = ((offset + (random() % range)) / io_buffersize) * io_buffersize; else off = offset; bytes = do_pread(fd, off, io_buffersize, io_buffersize); if (bytes == 0) break; if (bytes < 0) { perror("pread"); return -1; } ops++; *total += bytes; if (bytes < io_buffersize) break; count -= bytes; } return ops; } static int read_backward( int fd, off64_t *offset, long long *count, long long *total, int eof) { off64_t end, off = *offset; ssize_t bytes = 0, bytes_requested; long long cnt = *count; int ops = 0; end = lseek(fd, 0, SEEK_END); off = eof ? end : min(end, lseek(fd, off, SEEK_SET)); if ((end = off - cnt) < 0) { cnt += end; /* subtraction, end is negative */ end = 0; } *total = 0; *count = cnt; *offset = off; /* Do initial unaligned read if needed */ if ((bytes_requested = (off % io_buffersize))) { off -= bytes_requested; bytes = do_pread(fd, off, bytes_requested, io_buffersize); if (bytes == 0) return ops; if (bytes < 0) { perror("pread"); return -1; } ops++; *total += bytes; if (bytes < bytes_requested) return ops; cnt -= bytes; } /* Iterate backward through the rest of the range */ while (cnt > end) { bytes_requested = min(cnt, io_buffersize); off -= bytes_requested; bytes = do_pread(fd, off, cnt, io_buffersize); if (bytes == 0) break; if (bytes < 0) { perror("pread"); return -1; } ops++; *total += bytes; if (bytes < bytes_requested) break; cnt -= bytes; } return ops; } static int read_forward( int fd, off64_t offset, long long count, long long *total, int verbose, int onlyone, int eof) { ssize_t bytes; int ops = 0; *total = 0; while (count > 0 || eof) { bytes = do_pread(fd, offset, count, io_buffersize); if (bytes == 0) break; if (bytes < 0) { perror("pread"); return -1; } ops++; if (verbose) dump_buffer(offset, bytes); *total += bytes; if (onlyone || bytes < min(count, io_buffersize)) break; offset += bytes; count -= bytes; } return ops; } int read_buffer( int fd, off64_t offset, long long count, long long *total, int verbose, int onlyone) { return read_forward(fd, offset, count, total, verbose, onlyone, 0); } static int pread_f( int argc, char **argv) { size_t bsize; off64_t offset; unsigned int zeed = 0; long long count, total, tmp; size_t fsblocksize, fssectsize; struct timeval t1, t2; char *sp; int Cflag, qflag, uflag, vflag; int eof = 0, direction = IO_FORWARD; int c; Cflag = qflag = uflag = vflag = 0; init_cvtnum(&fsblocksize, &fssectsize); bsize = fsblocksize; while ((c = getopt(argc, argv, "b:BCFRquvV:Z:")) != EOF) { switch (c) { case 'b': tmp = cvtnum(fsblocksize, fssectsize, optarg); if (tmp < 0) { printf(_("non-numeric bsize -- %s\n"), optarg); return 0; } bsize = tmp; break; case 'C': Cflag = 1; break; case 'F': direction = IO_FORWARD; break; case 'B': direction = IO_BACKWARD; break; case 'R': direction = IO_RANDOM; break; case 'q': qflag = 1; break; case 'u': uflag = 1; break; case 'v': vflag = 1; break; #ifdef HAVE_PREADV case 'V': vectors = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric vector count == %s\n"), optarg); return 0; } break; #endif case 'Z': zeed = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric seed -- %s\n"), optarg); return 0; } break; default: return command_usage(&pread_cmd); } } if (optind != argc - 2) return command_usage(&pread_cmd); offset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (offset < 0 && (direction & (IO_RANDOM|IO_BACKWARD))) { eof = -1; /* read from EOF */ } else if (offset < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } optind++; count = cvtnum(fsblocksize, fssectsize, argv[optind]); if (count < 0 && (direction & (IO_RANDOM|IO_FORWARD))) { eof = -1; /* read to EOF */ } else if (count < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } if (alloc_buffer(bsize, uflag, 0xabababab) < 0) return 0; gettimeofday(&t1, NULL); switch (direction) { case IO_RANDOM: if (!zeed) /* srandom seed */ zeed = time(NULL); c = read_random(file->fd, offset, count, &total, zeed, eof); break; case IO_FORWARD: c = read_forward(file->fd, offset, count, &total, vflag, 0, eof); if (eof) count = total; break; case IO_BACKWARD: c = read_backward(file->fd, &offset, &count, &total, eof); break; default: ASSERT(0); } if (c < 0) return 0; if (qflag) return 0; gettimeofday(&t2, NULL); t2 = tsub(t2, t1); report_io_times("read", &t2, (long long)offset, count, total, c, Cflag); return 0; } void pread_init(void) { pread_cmd.name = "pread"; pread_cmd.altname = "r"; pread_cmd.cfunc = pread_f; pread_cmd.argmin = 2; pread_cmd.argmax = -1; pread_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; pread_cmd.args = _("[-b bs] [-v] [-i N] [-FBR [-Z N]] off len"); pread_cmd.oneline = _("reads a number of bytes at a specified offset"); pread_cmd.help = pread_help; add_command(&pread_cmd); } xfsprogs-5.3.0/io/prealloc.c0000644000175000017500000002252013466663244015637 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #if defined(HAVE_FALLOCATE) #include #endif #include "command.h" #include "input.h" #include "init.h" #include "io.h" #ifndef FALLOC_FL_PUNCH_HOLE #define FALLOC_FL_PUNCH_HOLE 0x02 #endif #ifndef FALLOC_FL_COLLAPSE_RANGE #define FALLOC_FL_COLLAPSE_RANGE 0x08 #endif #ifndef FALLOC_FL_ZERO_RANGE #define FALLOC_FL_ZERO_RANGE 0x10 #endif #ifndef FALLOC_FL_INSERT_RANGE #define FALLOC_FL_INSERT_RANGE 0x20 #endif #ifndef FALLOC_FL_UNSHARE_RANGE #define FALLOC_FL_UNSHARE_RANGE 0x40 #endif static cmdinfo_t allocsp_cmd; static cmdinfo_t freesp_cmd; static cmdinfo_t resvsp_cmd; static cmdinfo_t unresvsp_cmd; static cmdinfo_t zero_cmd; #if defined(HAVE_FALLOCATE) static cmdinfo_t falloc_cmd; static cmdinfo_t fpunch_cmd; static cmdinfo_t fcollapse_cmd; static cmdinfo_t finsert_cmd; static cmdinfo_t fzero_cmd; #endif static int offset_length( char *offset, char *length, xfs_flock64_t *segment) { size_t blocksize, sectsize; init_cvtnum(&blocksize, §size); memset(segment, 0, sizeof(*segment)); segment->l_whence = SEEK_SET; segment->l_start = cvtnum(blocksize, sectsize, offset); if (segment->l_start < 0) { printf(_("non-numeric offset argument -- %s\n"), offset); return 0; } segment->l_len = cvtnum(blocksize, sectsize, length); if (segment->l_len < 0) { printf(_("non-numeric length argument -- %s\n"), length); return 0; } return 1; } static int allocsp_f( int argc, char **argv) { xfs_flock64_t segment; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (xfsctl(file->name, file->fd, XFS_IOC_ALLOCSP64, &segment) < 0) { perror("XFS_IOC_ALLOCSP64"); return 0; } return 0; } static int freesp_f( int argc, char **argv) { xfs_flock64_t segment; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (xfsctl(file->name, file->fd, XFS_IOC_FREESP64, &segment) < 0) { perror("XFS_IOC_FREESP64"); return 0; } return 0; } static int resvsp_f( int argc, char **argv) { xfs_flock64_t segment; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (xfsctl(file->name, file->fd, XFS_IOC_RESVSP64, &segment) < 0) { perror("XFS_IOC_RESVSP64"); return 0; } return 0; } static int unresvsp_f( int argc, char **argv) { xfs_flock64_t segment; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (xfsctl(file->name, file->fd, XFS_IOC_UNRESVSP64, &segment) < 0) { perror("XFS_IOC_UNRESVSP64"); return 0; } return 0; } static int zero_f( int argc, char **argv) { xfs_flock64_t segment; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (xfsctl(file->name, file->fd, XFS_IOC_ZERO_RANGE, &segment) < 0) { perror("XFS_IOC_ZERO_RANGE"); return 0; } return 0; } #if defined (HAVE_FALLOCATE) static void falloc_help(void) { printf(_( "\n" " modifies space associated with part of a file via fallocate" "\n" " Example:\n" " 'falloc 0 1m' - fills all holes within the first megabyte\n" "\n" " falloc uses the fallocate system call to alter space allocations in the\n" " open file. The following operations are supported:\n" " All the file offsets are in units of bytes.\n" " -c -- collapses the given range.\n" " -i -- inserts a hole into the given range of the file.\n" " -k -- do not change file size.\n" " -p -- unmap the given range from the file.\n" " -u -- unshare shared extents in the given range.\n" "\n")); } static int fallocate_f( int argc, char **argv) { xfs_flock64_t segment; int mode = 0; int c; while ((c = getopt(argc, argv, "cikpu")) != EOF) { switch (c) { case 'c': mode = FALLOC_FL_COLLAPSE_RANGE; break; case 'i': mode = FALLOC_FL_INSERT_RANGE; break; case 'k': mode = FALLOC_FL_KEEP_SIZE; break; case 'p': mode = FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE; break; case 'u': mode = FALLOC_FL_UNSHARE_RANGE; break; default: command_usage(&falloc_cmd); } } if (optind != argc - 2) return command_usage(&falloc_cmd); if (!offset_length(argv[optind], argv[optind+1], &segment)) return 0; if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) { perror("fallocate"); return 0; } return 0; } static int fpunch_f( int argc, char **argv) { xfs_flock64_t segment; int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) { perror("fallocate"); return 0; } return 0; } static int fcollapse_f( int argc, char **argv) { xfs_flock64_t segment; int mode = FALLOC_FL_COLLAPSE_RANGE; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) { perror("fallocate"); return 0; } return 0; } static int finsert_f( int argc, char **argv) { xfs_flock64_t segment; int mode = FALLOC_FL_INSERT_RANGE; if (!offset_length(argv[1], argv[2], &segment)) return 0; if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) { perror("fallocate"); return 0; } return 0; } static int fzero_f( int argc, char **argv) { xfs_flock64_t segment; int mode = FALLOC_FL_ZERO_RANGE; int c; while ((c = getopt(argc, argv, "k")) != EOF) { switch (c) { case 'k': mode |= FALLOC_FL_KEEP_SIZE; break; default: command_usage(&fzero_cmd); } } if (optind != argc - 2) return command_usage(&fzero_cmd); if (!offset_length(argv[optind], argv[optind + 1], &segment)) return 0; if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) { perror("fallocate"); return 0; } return 0; } static int funshare_f( int argc, char **argv) { xfs_flock64_t segment; int mode = FALLOC_FL_UNSHARE_RANGE; int index = 1; if (!offset_length(argv[index], argv[index + 1], &segment)) return 0; if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) { perror("fallocate"); return 0; } return 0; } #endif /* HAVE_FALLOCATE */ void prealloc_init(void) { allocsp_cmd.name = "allocsp"; allocsp_cmd.cfunc = allocsp_f; allocsp_cmd.argmin = 2; allocsp_cmd.argmax = 2; allocsp_cmd.flags = CMD_NOMAP_OK; allocsp_cmd.args = _("off len"); allocsp_cmd.oneline = _("allocates zeroed space for part of a file"); freesp_cmd.name = "freesp"; freesp_cmd.cfunc = freesp_f; freesp_cmd.argmin = 2; freesp_cmd.argmax = 2; freesp_cmd.flags = CMD_NOMAP_OK; freesp_cmd.args = _("off len"); freesp_cmd.oneline = _("frees space associated with part of a file"); resvsp_cmd.name = "resvsp"; resvsp_cmd.cfunc = resvsp_f; resvsp_cmd.argmin = 2; resvsp_cmd.argmax = 2; resvsp_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; resvsp_cmd.args = _("off len"); resvsp_cmd.oneline = _("reserves space associated with part of a file"); unresvsp_cmd.name = "unresvsp"; unresvsp_cmd.cfunc = unresvsp_f; unresvsp_cmd.argmin = 2; unresvsp_cmd.argmax = 2; unresvsp_cmd.args = _("off len"); unresvsp_cmd.flags = CMD_NOMAP_OK; unresvsp_cmd.oneline = _("frees reserved space associated with part of a file"); zero_cmd.name = "zero"; zero_cmd.cfunc = zero_f; zero_cmd.argmin = 2; zero_cmd.argmax = 2; zero_cmd.flags = CMD_NOMAP_OK; zero_cmd.args = _("off len"); zero_cmd.oneline = _("Converts the given range of a file to allocated zeros"); add_command(&allocsp_cmd); add_command(&freesp_cmd); add_command(&resvsp_cmd); add_command(&unresvsp_cmd); add_command(&zero_cmd); #if defined (HAVE_FALLOCATE) falloc_cmd.name = "falloc"; falloc_cmd.cfunc = fallocate_f; falloc_cmd.argmin = 2; falloc_cmd.argmax = -1; falloc_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; falloc_cmd.args = _("[-c] [-k] [-p] [-u] off len"); falloc_cmd.oneline = _("allocates space associated with part of a file via fallocate"); falloc_cmd.help = falloc_help; add_command(&falloc_cmd); fpunch_cmd.name = "fpunch"; fpunch_cmd.cfunc = fpunch_f; fpunch_cmd.argmin = 2; fpunch_cmd.argmax = 2; fpunch_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fpunch_cmd.args = _("off len"); fpunch_cmd.oneline = _("de-allocates space associated with part of a file via fallocate"); add_command(&fpunch_cmd); fcollapse_cmd.name = "fcollapse"; fcollapse_cmd.cfunc = fcollapse_f; fcollapse_cmd.argmin = 2; fcollapse_cmd.argmax = 2; fcollapse_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fcollapse_cmd.args = _("off len"); fcollapse_cmd.oneline = _("de-allocates space and eliminates the hole by shifting extents"); add_command(&fcollapse_cmd); finsert_cmd.name = "finsert"; finsert_cmd.cfunc = finsert_f; finsert_cmd.argmin = 2; finsert_cmd.argmax = 2; finsert_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; finsert_cmd.args = _("off len"); finsert_cmd.oneline = _("creates new space for writing within file by shifting extents"); add_command(&finsert_cmd); fzero_cmd.name = "fzero"; fzero_cmd.cfunc = fzero_f; fzero_cmd.argmin = 2; fzero_cmd.argmax = 3; fzero_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fzero_cmd.args = _("[-k] off len"); fzero_cmd.oneline = _("zeroes space and eliminates holes by preallocating"); add_command(&fzero_cmd); fzero_cmd.name = "funshare"; fzero_cmd.cfunc = funshare_f; fzero_cmd.argmin = 2; fzero_cmd.argmax = 2; fzero_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; fzero_cmd.args = _("off len"); fzero_cmd.oneline = _("unshares shared blocks within the range"); add_command(&fzero_cmd); #endif /* HAVE_FALLOCATE */ } xfsprogs-5.3.0/io/pwrite.c0000644000175000017500000002400513435336036015340 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t pwrite_cmd; static void pwrite_help(void) { printf(_( "\n" " writes a range of bytes (in block size increments) from the given offset\n" "\n" " Example:\n" " 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Writes into a segment of the currently open file, using either a buffer\n" " filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n" " The writes are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different write pattern is requested.\n" " -S -- use an alternate seed number for filling the write buffer\n" " -i -- input file, source of data to write (used when writing forward)\n" " -d -- open the input file for direct IO\n" " -s -- skip a number of bytes at the start of the input file\n" " -w -- call fdatasync(2) at the end (included in timing results)\n" " -W -- call fsync(2) at the end (included in timing results)\n" " -B -- write backwards through the range from offset (backwards N bytes)\n" " -F -- write forwards through the range of bytes from offset (default)\n" " -O -- perform pwrite call once and return (maybe partial) bytes written\n" " -R -- write at random offsets in the specified range of bytes\n" " -Z N -- zeed the random number generator (used when writing randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" #ifdef HAVE_PWRITEV " -V N -- use vectored IO with N iovecs of blocksize each (pwritev)\n" #endif #ifdef HAVE_PWRITEV2 " -N -- Perform the pwritev2() with RWF_NOWAIT\n" " -D -- Perform the pwritev2() with RWF_DSYNC\n" #endif "\n")); } #ifdef HAVE_PWRITEV static ssize_t do_pwritev( int fd, off64_t offset, size_t count, int pwritev2_flags) { int vecs = 0; ssize_t oldlen = 0; ssize_t bytes = 0; /* trim the iovec if necessary */ if (count < io_buffersize) { size_t len = 0; while (len + iov[vecs].iov_len < count) { len += iov[vecs].iov_len; vecs++; } oldlen = iov[vecs].iov_len; iov[vecs].iov_len = count - len; vecs++; } else { vecs = vectors; } #ifdef HAVE_PWRITEV2 if (pwritev2_flags) bytes = pwritev2(fd, iov, vectors, offset, pwritev2_flags); else bytes = pwritev(fd, iov, vectors, offset); #else bytes = pwritev(fd, iov, vectors, offset); #endif /* restore trimmed iov */ if (oldlen) iov[vecs - 1].iov_len = oldlen; return bytes; } #else #define do_pwritev(fd, offset, count, pwritev2_flags) (0) #endif static ssize_t do_pwrite( int fd, off64_t offset, size_t count, size_t buffer_size, int pwritev2_flags) { if (!vectors) return pwrite(fd, io_buffer, min(count, buffer_size), offset); return do_pwritev(fd, offset, count, pwritev2_flags); } static int write_random( off64_t offset, long long count, unsigned int seed, long long *total, int pwritev2_flags) { off64_t off, range; ssize_t bytes; int ops = 0; srandom(seed); if ((bytes = (offset % io_buffersize))) offset -= bytes; offset = max(0, offset); if ((bytes = (count % io_buffersize))) count += bytes; count = max(io_buffersize, count); range = count - io_buffersize; *total = 0; while (count > 0) { if (range) off = ((offset + (random() % range)) / io_buffersize) * io_buffersize; else off = offset; bytes = do_pwrite(file->fd, off, io_buffersize, io_buffersize, pwritev2_flags); if (bytes == 0) break; if (bytes < 0) { perror("pwrite"); return -1; } ops++; *total += bytes; if (bytes < io_buffersize) break; count -= bytes; } return ops; } static int write_backward( off64_t offset, long long *count, long long *total, int pwritev2_flags) { off64_t end, off = offset; ssize_t bytes = 0, bytes_requested; long long cnt = *count; int ops = 0; if ((end = off - cnt) < 0) { cnt += end; /* subtraction, end is negative */ end = 0; } *total = 0; *count = cnt; /* Do initial unaligned write if needed */ if ((bytes_requested = (off % io_buffersize))) { bytes_requested = min(cnt, bytes_requested); off -= bytes_requested; bytes = do_pwrite(file->fd, off, bytes_requested, io_buffersize, pwritev2_flags); if (bytes == 0) return ops; if (bytes < 0) { perror("pwrite"); return -1; } ops++; *total += bytes; if (bytes < bytes_requested) return ops; cnt -= bytes; } /* Iterate backward through the rest of the range */ while (cnt > end) { bytes_requested = min(cnt, io_buffersize); off -= bytes_requested; bytes = do_pwrite(file->fd, off, cnt, io_buffersize, pwritev2_flags); if (bytes == 0) break; if (bytes < 0) { perror("pwrite"); return -1; } ops++; *total += bytes; if (bytes < bytes_requested) break; cnt -= bytes; } return ops; } static int write_buffer( off64_t offset, long long count, size_t bs, int fd, off64_t skip, long long *total, int pwritev2_flags) { ssize_t bytes; long long bar = min(bs, count); int ops = 0; *total = 0; while (count >= 0) { if (fd > 0) { /* input file given, read buffer first */ if (read_buffer(fd, skip + *total, bs, &bar, 0, 1) < 0) break; } bytes = do_pwrite(file->fd, offset, count, bar, pwritev2_flags); if (bytes == 0) break; if (bytes < 0) { perror("pwrite"); return -1; } ops++; *total += bytes; if (bytes < min(count, bar)) break; offset += bytes; count -= bytes; if (count == 0) break; } return ops; } static int write_once( off64_t offset, long long count, long long *total, int pwritev2_flags) { ssize_t bytes; bytes = do_pwrite(file->fd, offset, count, count, pwritev2_flags); if (bytes < 0) { perror("pwrite"); return -1; } *total = bytes; return 1; } static int pwrite_f( int argc, char **argv) { size_t bsize; off64_t offset, skip = 0; long long count, total, tmp; unsigned int zeed = 0, seed = 0xcdcdcdcd; size_t fsblocksize, fssectsize; struct timeval t1, t2; char *sp, *infile = NULL; int Cflag, qflag, uflag, dflag, wflag, Wflag; int direction = IO_FORWARD; int c, fd = -1; int pwritev2_flags = 0; Cflag = qflag = uflag = dflag = wflag = Wflag = 0; init_cvtnum(&fsblocksize, &fssectsize); bsize = fsblocksize; while ((c = getopt(argc, argv, "b:BCdDf:Fi:NqRs:OS:uV:wWZ:")) != EOF) { switch (c) { case 'b': tmp = cvtnum(fsblocksize, fssectsize, optarg); if (tmp < 0) { printf(_("non-numeric bsize -- %s\n"), optarg); return 0; } bsize = tmp; break; case 'C': Cflag = 1; break; case 'F': direction = IO_FORWARD; break; case 'B': direction = IO_BACKWARD; break; case 'R': direction = IO_RANDOM; break; case 'O': direction = IO_ONCE; break; case 'd': dflag = 1; break; case 'f': case 'i': infile = optarg; break; #ifdef HAVE_PWRITEV2 case 'N': pwritev2_flags |= RWF_NOWAIT; break; case 'D': pwritev2_flags |= RWF_DSYNC; break; #endif case 's': skip = cvtnum(fsblocksize, fssectsize, optarg); if (skip < 0) { printf(_("non-numeric skip -- %s\n"), optarg); return 0; } break; case 'S': seed = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric seed -- %s\n"), optarg); return 0; } break; case 'q': qflag = 1; break; case 'u': uflag = 1; break; #ifdef HAVE_PWRITEV case 'V': vectors = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric vector count == %s\n"), optarg); return 0; } break; #endif case 'w': wflag = 1; break; case 'W': Wflag = 1; break; case 'Z': zeed = strtoul(optarg, &sp, 0); if (!sp || sp == optarg) { printf(_("non-numeric seed -- %s\n"), optarg); return 0; } break; default: /* Handle ifdef'd-out options above */ if (c != '?') printf(_("%s: command -%c not supported\n"), argv[0], c); else command_usage(&pwrite_cmd); return 0; } } if (((skip || dflag) && !infile) || (optind != argc - 2)) return command_usage(&pwrite_cmd); if (infile && direction != IO_FORWARD) return command_usage(&pwrite_cmd); offset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; count = cvtnum(fsblocksize, fssectsize, argv[optind]); if (count < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } if (alloc_buffer(bsize, uflag, seed) < 0) return 0; c = IO_READONLY | (dflag ? IO_DIRECT : 0); if (infile && ((fd = openfile(infile, NULL, c, 0, NULL)) < 0)) return 0; gettimeofday(&t1, NULL); switch (direction) { case IO_RANDOM: if (!zeed) /* srandom seed */ zeed = time(NULL); c = write_random(offset, count, zeed, &total, pwritev2_flags); break; case IO_FORWARD: c = write_buffer(offset, count, bsize, fd, skip, &total, pwritev2_flags); break; case IO_BACKWARD: c = write_backward(offset, &count, &total, pwritev2_flags); break; case IO_ONCE: c = write_once(offset, count, &total, pwritev2_flags); break; default: total = 0; ASSERT(0); } if (c < 0) goto done; if (Wflag) { if (fsync(file->fd) < 0) { perror("fsync"); goto done; } } if (wflag) { if (fdatasync(file->fd) < 0) { perror("fdatasync"); goto done; } } if (qflag) goto done; gettimeofday(&t2, NULL); t2 = tsub(t2, t1); report_io_times("wrote", &t2, (long long)offset, count, total, c, Cflag); done: if (infile) close(fd); return 0; } void pwrite_init(void) { pwrite_cmd.name = "pwrite"; pwrite_cmd.altname = "w"; pwrite_cmd.cfunc = pwrite_f; pwrite_cmd.argmin = 2; pwrite_cmd.argmax = -1; pwrite_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; pwrite_cmd.args = _("[-i infile [-dDwNOW] [-s skip]] [-b bs] [-S seed] [-FBR [-Z N]] [-V N] off len"); pwrite_cmd.oneline = _("writes a number of bytes at a specified offset"); pwrite_cmd.help = pwrite_help; add_command(&pwrite_cmd); } xfsprogs-5.3.0/io/readdir.c0000644000175000017500000000706713435336036015451 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include #include #ifndef _DIRENT_HAVE_D_RECLEN #include #endif static struct cmdinfo readdir_cmd; static const char *d_type_str(unsigned int type) { const char *str; switch (type) { case DT_UNKNOWN: str = "DT_UNKNOWN"; break; case DT_FIFO: str = "DT_FIFO"; break; case DT_CHR: str = "DT_CHR"; break; case DT_DIR: str = "DT_DIR"; break; case DT_BLK: str = "DT_BLK"; break; case DT_REG: str = "DT_REG"; break; case DT_LNK: str = "DT_LNK"; break; case DT_SOCK: str = "DT_SOCK"; break; case DT_WHT: str = "DT_WHT"; break; default: str = "ERROR!"; break; } return str; } static void dump_dirent( long long offset, struct dirent *dirent) { printf("%08llx: d_ino: 0x%08llx", offset, (unsigned long long)dirent->d_ino); #ifdef _DIRENT_HAVE_D_OFF printf(" d_off: 0x%08llx", (unsigned long long)dirent->d_off); #endif #ifdef _DIRENT_HAVE_D_RECLEN printf(" d_reclen: 0x%x", dirent->d_reclen); #endif #ifdef _DIRENT_HAVE_D_TYPE printf(" d_type: %s", d_type_str(dirent->d_type)); #endif printf(" d_name: %s\n", dirent->d_name); } static int read_directory( DIR *dir, long long offset, unsigned long long length, int dump, unsigned long long *total) { struct dirent *dirent; int count = 0; seekdir(dir, offset); *total = 0; while (*total < length) { dirent = readdir(dir); if (!dirent) break; #ifdef _DIRENT_HAVE_D_RECLEN *total += dirent->d_reclen; #else *total += strlen(dirent->d_name) + sizeof(*dirent); #endif count++; if (dump) { dump_dirent(offset, dirent); #ifdef _DIRENT_HAVE_D_OFF offset = dirent->d_off; #else /* Some platforms don't have dirent->d_off, but because * it is used only for dumping the value, it should be * safe to only set it to zero in such case. */ offset = 0; #endif } } return count; } static int readdir_f( int argc, char **argv) { int cnt; unsigned long long total; int c; size_t fsblocksize, fssectsize; struct timeval t1, t2; char s1[64], s2[64], ts[64]; long long offset = -1; unsigned long long length = -1; /* max length limit */ int verbose = 0; DIR *dir; int dfd; init_cvtnum(&fsblocksize, &fssectsize); while ((c = getopt(argc, argv, "l:o:v")) != EOF) { switch (c) { case 'l': length = cvtnum(fsblocksize, fssectsize, optarg); break; case 'o': offset = cvtnum(fsblocksize, fssectsize, optarg); break; case 'v': verbose = 1; break; default: return command_usage(&readdir_cmd); } } dfd = dup(file->fd); if (dfd < 0) return -1; dir = fdopendir(dfd); if (!dir) { close(dfd); return -1; } if (offset == -1) { rewinddir(dir); offset = telldir(dir); } gettimeofday(&t1, NULL); cnt = read_directory(dir, offset, length, verbose, &total); gettimeofday(&t2, NULL); closedir(dir); close(dfd); t2 = tsub(t2, t1); timestr(&t2, ts, sizeof(ts), 0); cvtstr(total, s1, sizeof(s1)); cvtstr(tdiv(total, t2), s2, sizeof(s2)); printf(_("read %llu bytes from offset %lld\n"), total, offset); printf(_("%s, %d ops, %s (%s/sec and %.4f ops/sec)\n"), s1, cnt, ts, s2, tdiv(cnt, t2)); return 0; } void readdir_init(void) { readdir_cmd.name = "readdir"; readdir_cmd.cfunc = readdir_f; readdir_cmd.argmax = 5; readdir_cmd.flags = CMD_NOMAP_OK|CMD_FOREIGN_OK; readdir_cmd.args = _("[-v][-o offset][-l length]"); readdir_cmd.oneline = _("read directory entries"); add_command(&readdir_cmd); } xfsprogs-5.3.0/io/reflink.c0000644000175000017500000001726713435336036015474 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 Oracle, Inc. * All Rights Reserved. */ #include #include #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t dedupe_cmd; static cmdinfo_t reflink_cmd; static void dedupe_help(void) { printf(_("\n\ Links a range of bytes (in block size increments) from a file into a range\n\ of bytes in the open file. The contents of both file ranges must match.\n\ \n\ Example:\n\ 'dedupe some_file 0 4096 32768' - links 32768 bytes from some_file at\n\ offset 0 to into the open file at\n\ position 4096\n\ \n\ Reflink a range of blocks from a given input file to the open file. Both\n\ files share the same range of physical disk blocks; a write to the shared\n\ range of either file should result in the write landing in a new block and\n\ that range of the file being remapped (i.e. copy-on-write). Both files\n\ must reside on the same filesystem, and the contents of both ranges must\n\ match.\n\ ")); } static uint64_t dedupe_ioctl( int fd, uint64_t soffset, uint64_t doffset, uint64_t len, int *ops) { struct xfs_extent_data *args; struct xfs_extent_data_info *info; int error; uint64_t deduped = 0; args = calloc(1, sizeof(struct xfs_extent_data) + sizeof(struct xfs_extent_data_info)); if (!args) goto done; info = (struct xfs_extent_data_info *)(args + 1); args->logical_offset = soffset; args->length = len; args->dest_count = 1; info->fd = file->fd; info->logical_offset = doffset; while (args->length > 0 || !*ops) { error = ioctl(fd, XFS_IOC_FILE_EXTENT_SAME, args); if (error) { perror("XFS_IOC_FILE_EXTENT_SAME"); goto done; } if (info->status < 0) { fprintf(stderr, "XFS_IOC_FILE_EXTENT_SAME: %s\n", _(strerror(-info->status))); goto done; } if (info->status == XFS_EXTENT_DATA_DIFFERS) { fprintf(stderr, "XFS_IOC_FILE_EXTENT_SAME: %s\n", _("Extents did not match.")); goto done; } if (args->length != 0 && (info->bytes_deduped == 0 || info->bytes_deduped > args->length)) break; (*ops)++; args->logical_offset += info->bytes_deduped; info->logical_offset += info->bytes_deduped; if (args->length >= info->bytes_deduped) args->length -= info->bytes_deduped; deduped += info->bytes_deduped; } done: free(args); return deduped; } static int dedupe_f( int argc, char **argv) { off64_t soffset, doffset; long long count, total; char *infile; int condensed, quiet_flag; size_t fsblocksize, fssectsize; struct timeval t1, t2; int c, ops = 0, fd = -1; condensed = quiet_flag = 0; init_cvtnum(&fsblocksize, &fssectsize); while ((c = getopt(argc, argv, "Cq")) != EOF) { switch (c) { case 'C': condensed = 1; break; case 'q': quiet_flag = 1; break; default: return command_usage(&dedupe_cmd); } } if (optind != argc - 4) return command_usage(&dedupe_cmd); infile = argv[optind]; optind++; soffset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (soffset < 0) { printf(_("non-numeric src offset argument -- %s\n"), argv[optind]); return 0; } optind++; doffset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (doffset < 0) { printf(_("non-numeric dest offset argument -- %s\n"), argv[optind]); return 0; } optind++; count = cvtnum(fsblocksize, fssectsize, argv[optind]); if (count < 0) { printf(_("non-positive length argument -- %s\n"), argv[optind]); return 0; } fd = openfile(infile, NULL, IO_READONLY, 0, NULL); if (fd < 0) return 0; gettimeofday(&t1, NULL); total = dedupe_ioctl(fd, soffset, doffset, count, &ops); if (ops == 0 || quiet_flag) goto done; gettimeofday(&t2, NULL); t2 = tsub(t2, t1); report_io_times("deduped", &t2, (long long)doffset, count, total, ops, condensed); done: close(fd); return 0; } static void reflink_help(void) { printf(_("\n\ Links a range of bytes (in block size increments) from a file into a range\n\ of bytes in the open file. The two extent ranges need not contain identical\n\ data.\n\ \n\ Example:\n\ 'reflink some_file 0 4096 32768' - links 32768 bytes from some_file at\n\ offset 0 to into the open file at\n\ position 4096\n\ 'reflink some_file' - links all bytes from some_file into the open file\n\ at position 0\n\ \n\ Reflink a range of blocks from a given input file to the open file. Both\n\ files share the same range of physical disk blocks; a write to the shared\n\ range of either file should result in the write landing in a new block and\n\ that range of the file being remapped (i.e. copy-on-write). Both files\n\ must reside on the same filesystem.\n\ ")); } static uint64_t reflink_ioctl( int fd, uint64_t soffset, uint64_t doffset, uint64_t len, int *ops) { struct xfs_clone_args args; int error; if (soffset == 0 && doffset == 0 && len == 0) { error = ioctl(file->fd, XFS_IOC_CLONE, fd); if (error) perror("XFS_IOC_CLONE"); } else { args.src_fd = fd; args.src_offset = soffset; args.src_length = len; args.dest_offset = doffset; error = ioctl(file->fd, XFS_IOC_CLONE_RANGE, &args); if (error) perror("XFS_IOC_CLONE_RANGE"); } if (!error) (*ops)++; return error ? 0 : len; } static int reflink_f( int argc, char **argv) { off64_t soffset, doffset; long long count = 0, total; char *infile = NULL; int condensed, quiet_flag; size_t fsblocksize, fssectsize; struct timeval t1, t2; int c, ops = 0, fd = -1; condensed = quiet_flag = 0; doffset = soffset = 0; init_cvtnum(&fsblocksize, &fssectsize); while ((c = getopt(argc, argv, "Cq")) != EOF) { switch (c) { case 'C': condensed = 1; break; case 'q': quiet_flag = 1; break; default: return command_usage(&reflink_cmd); } } if (optind != argc - 4 && optind != argc - 1) return command_usage(&reflink_cmd); infile = argv[optind]; optind++; if (optind == argc) goto clone_all; soffset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (soffset < 0) { printf(_("non-numeric src offset argument -- %s\n"), argv[optind]); return 0; } optind++; doffset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (doffset < 0) { printf(_("non-numeric dest offset argument -- %s\n"), argv[optind]); return 0; } optind++; count = cvtnum(fsblocksize, fssectsize, argv[optind]); if (count < 0) { printf(_("non-positive length argument -- %s\n"), argv[optind]); return 0; } clone_all: fd = openfile(infile, NULL, IO_READONLY, 0, NULL); if (fd < 0) return 0; gettimeofday(&t1, NULL); total = reflink_ioctl(fd, soffset, doffset, count, &ops); if (ops == 0 || quiet_flag) goto done; gettimeofday(&t2, NULL); t2 = tsub(t2, t1); report_io_times("linked", &t2, (long long)doffset, count, total, ops, condensed); done: close(fd); return 0; } void reflink_init(void) { reflink_cmd.name = "reflink"; reflink_cmd.altname = "rl"; reflink_cmd.cfunc = reflink_f; reflink_cmd.argmin = 1; reflink_cmd.argmax = -1; reflink_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; reflink_cmd.args = _("infile [src_off dst_off len]"); reflink_cmd.oneline = _("reflinks an entire file, or a number of bytes at a specified offset"); reflink_cmd.help = reflink_help; add_command(&reflink_cmd); dedupe_cmd.name = "dedupe"; dedupe_cmd.altname = "dd"; dedupe_cmd.cfunc = dedupe_f; dedupe_cmd.argmin = 4; dedupe_cmd.argmax = -1; dedupe_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; dedupe_cmd.args = _("infile src_off dst_off len"); dedupe_cmd.oneline = _("dedupes a number of bytes at a specified offset"); dedupe_cmd.help = dedupe_help; add_command(&dedupe_cmd); } xfsprogs-5.3.0/io/resblks.c0000644000175000017500000000250313435336036015472 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t resblks_cmd; static int resblks_f(int argc, char **argv); static int resblks_f( int argc, char **argv) { xfs_fsop_resblks_t res; long long blks; if (argc == 2) { blks = cvtnum(file->geom.blocksize, file->geom.sectsize, argv[1]); if (blks < 0) { printf(_("non-numeric argument -- %s\n"), argv[1]); return 0; } res.resblks = blks; if (xfsctl(file->name, file->fd, XFS_IOC_SET_RESBLKS, &res) < 0) { perror("XFS_IOC_SET_RESBLKS"); return 0; } } else if (xfsctl(file->name, file->fd, XFS_IOC_GET_RESBLKS, &res) < 0) { perror("XFS_IOC_GET_RESBLKS"); return 0; } printf(_("reserved blocks = %llu\n"), (unsigned long long) res.resblks); printf(_("available reserved blocks = %llu\n"), (unsigned long long) res.resblks_avail); return 0; } void resblks_init(void) { resblks_cmd.name = "resblks"; resblks_cmd.cfunc = resblks_f; resblks_cmd.argmin = 0; resblks_cmd.argmax = 1; resblks_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT; resblks_cmd.args = _("[blocks]"); resblks_cmd.oneline = _("get and/or set count of reserved filesystem blocks"); if (expert) add_command(&resblks_cmd); } xfsprogs-5.3.0/io/scrub.c0000644000175000017500000001603113570057155015146 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include #include "command.h" #include "input.h" #include "init.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "libfrog/scrub.h" #include "io.h" static struct cmdinfo scrub_cmd; static struct cmdinfo repair_cmd; static void scrub_help(void) { const struct xfrog_scrub_descr *d; int i; printf(_( "\n" " Scrubs a piece of XFS filesystem metadata. The first argument is the type\n" " of metadata to examine. Allocation group metadata types take one AG number\n" " as the second parameter. Inode metadata types act on the currently open file\n" " or (optionally) take an inode number and generation number to act upon as\n" " the second and third parameters.\n" "\n" " Example:\n" " 'scrub inobt 3' - scrub the inode btree in AG 3.\n" " 'scrub bmapbtd 128 13525' - scrubs the extent map of inode 128 gen 13525.\n" "\n" " Known metadata scrub types are:")); for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) printf(" %s", d->name); printf("\n"); } static void scrub_ioctl( int fd, int type, uint64_t control, uint32_t control2) { struct xfs_scrub_metadata meta; const struct xfrog_scrub_descr *sc; int error; sc = &xfrog_scrubbers[type]; memset(&meta, 0, sizeof(meta)); meta.sm_type = type; switch (sc->type) { case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: meta.sm_agno = control; break; case XFROG_SCRUB_TYPE_INODE: meta.sm_ino = control; meta.sm_gen = control2; break; case XFROG_SCRUB_TYPE_NONE: case XFROG_SCRUB_TYPE_FS: /* no control parameters */ break; } meta.sm_flags = 0; error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); if (error) perror("scrub"); if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) printf(_("Corruption detected.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) printf(_("Optimization possible.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) printf(_("Cross-referencing failed.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) printf(_("Corruption detected during cross-referencing.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) printf(_("Scan was not complete.\n")); } static int parse_args( int argc, char **argv, struct cmdinfo *cmdinfo, void (*fn)(int, int, uint64_t, uint32_t)) { char *p; int type = -1; int i, c; uint64_t control = 0; uint32_t control2 = 0; const struct xfrog_scrub_descr *d = NULL; while ((c = getopt(argc, argv, "")) != EOF) { switch (c) { default: return command_usage(cmdinfo); } } if (optind > argc - 1) return command_usage(cmdinfo); for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) { if (strcmp(d->name, argv[optind]) == 0) { type = i; break; } } if (type < 0) { printf(_("Unknown type '%s'.\n"), argv[optind]); return command_usage(cmdinfo); } optind++; switch (d->type) { case XFROG_SCRUB_TYPE_INODE: if (optind == argc) { control = 0; control2 = 0; } else if (optind == argc - 2) { control = strtoull(argv[optind], &p, 0); if (*p != '\0') { fprintf(stderr, _("Bad inode number '%s'.\n"), argv[optind]); return 0; } control2 = strtoul(argv[optind + 1], &p, 0); if (*p != '\0') { fprintf(stderr, _("Bad generation number '%s'.\n"), argv[optind + 1]); return 0; } } else { fprintf(stderr, _("Must specify inode number and generation.\n")); return 0; } break; case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: if (optind != argc - 1) { fprintf(stderr, _("Must specify one AG number.\n")); return 0; } control = strtoul(argv[optind], &p, 0); if (*p != '\0') { fprintf(stderr, _("Bad AG number '%s'.\n"), argv[optind]); return 0; } break; case XFROG_SCRUB_TYPE_FS: case XFROG_SCRUB_TYPE_NONE: if (optind != argc) { fprintf(stderr, _("No parameters allowed.\n")); return 0; } break; default: ASSERT(0); break; } fn(file->fd, type, control, control2); return 0; } static int scrub_f( int argc, char **argv) { return parse_args(argc, argv, &scrub_cmd, scrub_ioctl); } void scrub_init(void) { scrub_cmd.name = "scrub"; scrub_cmd.altname = "sc"; scrub_cmd.cfunc = scrub_f; scrub_cmd.argmin = 1; scrub_cmd.argmax = -1; scrub_cmd.flags = CMD_NOMAP_OK; scrub_cmd.args = _("type [agno|ino gen]"); scrub_cmd.oneline = _("scrubs filesystem metadata"); scrub_cmd.help = scrub_help; add_command(&scrub_cmd); } static void repair_help(void) { const struct xfrog_scrub_descr *d; int i; printf(_( "\n" " Repairs a piece of XFS filesystem metadata. The first argument is the type\n" " of metadata to examine. Allocation group metadata types take one AG number\n" " as the second parameter. Inode metadata types act on the currently open file\n" " or (optionally) take an inode number and generation number to act upon as\n" " the second and third parameters.\n" "\n" " Example:\n" " 'repair inobt 3' - repairs the inode btree in AG 3.\n" " 'repair bmapbtd 128 13525' - repairs the extent map of inode 128 gen 13525.\n" "\n" " Known metadata repairs types are:")); for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) printf(" %s", d->name); printf("\n"); } static void repair_ioctl( int fd, int type, uint64_t control, uint32_t control2) { struct xfs_scrub_metadata meta; const struct xfrog_scrub_descr *sc; int error; sc = &xfrog_scrubbers[type]; memset(&meta, 0, sizeof(meta)); meta.sm_type = type; switch (sc->type) { case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: meta.sm_agno = control; break; case XFROG_SCRUB_TYPE_INODE: meta.sm_ino = control; meta.sm_gen = control2; break; case XFROG_SCRUB_TYPE_NONE: case XFROG_SCRUB_TYPE_FS: /* no control parameters */ break; } meta.sm_flags = XFS_SCRUB_IFLAG_REPAIR; error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); if (error) perror("repair"); if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) printf(_("Corruption remains.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) printf(_("Optimization possible.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) printf(_("Cross-referencing failed.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) printf(_("Corruption still detected during cross-referencing.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) printf(_("Repair was not complete.\n")); if (meta.sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) printf(_("Metadata did not need repair or optimization.\n")); } static int repair_f( int argc, char **argv) { return parse_args(argc, argv, &repair_cmd, repair_ioctl); } void repair_init(void) { if (!expert) return; repair_cmd.name = "repair"; repair_cmd.altname = "fix"; repair_cmd.cfunc = repair_f; repair_cmd.argmin = 1; repair_cmd.argmax = -1; repair_cmd.flags = CMD_NOMAP_OK; repair_cmd.args = _("type [agno|ino gen]"); repair_cmd.oneline = _("repairs filesystem metadata"); repair_cmd.help = repair_help; add_command(&repair_cmd); } xfsprogs-5.3.0/io/seek.c0000644000175000017500000001270613435336036014762 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013 SGI * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include #include "init.h" #include "io.h" static cmdinfo_t seek_cmd; static void seek_help(void) { printf(_( "\n" " returns the next hole and/or data offset at or after the requested offset\n" "\n" " Example:\n" " 'seek -d 512' - offset of data at or following offset 512\n" " 'seek -a -r 0' - offsets of all data and hole in entire file\n" "\n" " Returns the offset of the next data and/or hole. There is an implied hole\n" " at the end of file. If the specified offset is past end of file, or there\n" " is no data past the specified offset, EOF is returned.\n" " -a -- return the next data and hole starting at the specified offset.\n" " -d -- return the next data starting at the specified offset.\n" " -h -- return the next hole starting at the specified offset.\n" " -r -- return all remaining type(s) starting at the specified offset.\n" " -s -- also print the starting offset.\n" "\n")); } #ifndef HAVE_SEEK_DATA #define SEEK_DATA 3 /* seek to the next data */ #define SEEK_HOLE 4 /* seek to the next hole */ #endif /* values for flag variable */ #define SEEK_DFLAG (1 << 0) #define SEEK_HFLAG (1 << 1) #define SEEK_RFLAG (1 << 2) /* indexes into the seekinfo array */ #define DATA 0 #define HOLE 1 static struct seekinfo { char *name; /* display item name */ int seektype; /* data or hole */ int mask; /* compared for print and looping */ } seekinfo[] = { {"DATA", SEEK_DATA, SEEK_DFLAG}, {"HOLE", SEEK_HOLE, SEEK_HFLAG} }; /* print item type and offset. catch special cases of eof and error */ static void seek_output( int startflag, char *type, off64_t start, off64_t offset) { if (offset == -1) { if (errno == ENXIO) { if (startflag) printf("%s %lld EOF\n", type, (long long)start); else printf("%s EOF\n", type); } else { printf("ERR %lld ", (long long)start); fflush(stdout); /* so the printf preceded the perror */ perror(""); } } else { if (startflag) printf("%s %lld %lld\n", type, (long long)start, (long long)offset); else printf("%s %lld\n", type, (long long)offset); } } static int seek_f( int argc, char **argv) { off64_t offset, start; size_t fsblocksize, fssectsize; int c; int current; /* specify data or hole */ int flag; int startflag; flag = startflag = 0; init_cvtnum(&fsblocksize, &fssectsize); while ((c = getopt(argc, argv, "adhrs")) != EOF) { switch (c) { case 'a': flag |= (SEEK_HFLAG | SEEK_DFLAG); break; case 'd': flag |= SEEK_DFLAG; break; case 'h': flag |= SEEK_HFLAG; break; case 'r': flag |= SEEK_RFLAG; break; case 's': startflag = 1; break; default: return command_usage(&seek_cmd); } } if (!(flag & (SEEK_DFLAG | SEEK_HFLAG)) || optind != argc - 1) return command_usage(&seek_cmd); start = offset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (offset < 0) return command_usage(&seek_cmd); /* * check to see if the offset is a data or hole entry and * decide if we want to display that type of entry. */ if (flag & SEEK_HFLAG) { current = HOLE; offset = lseek(file->fd, start, SEEK_HOLE); if (offset != -1 && offset < start) goto bad_result; if ((start == offset) || !(flag & SEEK_DFLAG)) { /* * this offset is a hole or are only displaying holes. * if this offset is for data and we are displaying * data, then we will fall through below to * initialize the data search. */ goto found_hole; } } /* The offset is not a hole, or we are looking just for data */ current = DATA; offset = lseek(file->fd, start, SEEK_DATA); if (offset != -1 && offset < start) goto bad_result; found_hole: /* * At this point we know which type and the offset of the starting * item. "current" alternates between data / hole entries in * assending order - this alternation is needed even if only one * type is to be displayed. * * An error or EOF will terminate the display, otherwise "flag" * determines if there are more items to be displayed. */ if (startflag) printf("Whence Start Result\n"); else printf("Whence Result\n"); for (c = 0; flag; c++) { if (offset == -1) { /* print error or eof if the only entry */ if (errno != ENXIO || c == 0 ) seek_output(startflag, seekinfo[current].name, start, offset); return 0; /* stop on error or EOF */ } if (flag & seekinfo[current].mask) seek_output(startflag, seekinfo[current].name, start, offset); /* * When displaying only a single data and/or hole item, mask * off the item as it is displayed. The loop will end when all * requested items have been displayed. */ if (!(flag & SEEK_RFLAG)) flag &= ~seekinfo[current].mask; current ^= 1; /* alternate between data and hole */ start = offset; offset = lseek(file->fd, start, seekinfo[current].seektype); if (offset != -1 && offset <= start) goto bad_result; } return 0; bad_result: fprintf(stderr, "Invalid seek result: lseek(, %lld, SEEK_%s) = %lld\n", (long long)start, seekinfo[current].name, (long long)offset); return 0; } void seek_init(void) { seek_cmd.name = "seek"; seek_cmd.cfunc = seek_f; seek_cmd.argmin = 2; seek_cmd.argmax = 5; seek_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; seek_cmd.args = _("-a | -d | -h [-r] off"); seek_cmd.oneline = _("locate the next data and/or hole"); seek_cmd.help = seek_help; add_command(&seek_cmd); } xfsprogs-5.3.0/io/sendfile.c0000644000175000017500000000654513435336036015630 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include #include "init.h" #include "io.h" static cmdinfo_t sendfile_cmd; static void sendfile_help(void) { printf(_( "\n" " transfer a range of bytes from the given offset between files\n" "\n" " Example:\n" " 'send -f 2 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Copies data between one file descriptor and another. Because this copying\n" " is done within the kernel, sendfile does not need to transfer data to and\n" " from user space.\n" " -f -- specifies an input file from which to source data to write\n" " -i -- specifies an input file name from which to source data to write.\n" " An offset and length in the source file can be optionally specified.\n" "\n")); } static int send_buffer( off64_t offset, size_t count, int fd, long long *total) { off64_t off = offset; ssize_t bytes, bytes_remaining = count; int ops = 0; *total = 0; while (count > 0) { bytes = sendfile(file->fd, fd, &off, bytes_remaining); if (bytes == 0) break; if (bytes < 0) { perror("sendfile"); return -1; } ops++; *total += bytes; if (bytes >= bytes_remaining) break; bytes_remaining -= bytes; } return ops; } static int sendfile_f( int argc, char **argv) { off64_t offset = 0; long long count, total; size_t blocksize, sectsize; struct timeval t1, t2; char *infile = NULL; int Cflag, qflag; int c, fd = -1; Cflag = qflag = 0; init_cvtnum(&blocksize, §size); while ((c = getopt(argc, argv, "Cf:i:q")) != EOF) { switch (c) { case 'C': Cflag = 1; break; case 'q': qflag = 1; break; case 'f': fd = atoi(argv[1]); if (fd < 0 || fd >= filecount) { printf(_("value %d is out of range (0-%d)\n"), fd, filecount-1); return 0; } break; case 'i': infile = optarg; break; default: return command_usage(&sendfile_cmd); } } if (infile && fd != -1) return command_usage(&sendfile_cmd); if (!infile) fd = filetable[fd].fd; else if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0) return 0; if (optind == argc - 2) { offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); goto done; } optind++; count = cvtnum(blocksize, sectsize, argv[optind]); if (count < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); goto done; } } else { struct stat stat; if (fstat(fd, &stat) < 0) { perror("fstat"); goto done; } count = stat.st_size; } gettimeofday(&t1, NULL); c = send_buffer(offset, count, fd, &total); if (c < 0) goto done; if (qflag) goto done; gettimeofday(&t2, NULL); t2 = tsub(t2, t1); report_io_times("sent", &t2, (long long)offset, count, total, c, Cflag); done: if (infile) close(fd); return 0; } void sendfile_init(void) { sendfile_cmd.name = "sendfile"; sendfile_cmd.altname = "send"; sendfile_cmd.cfunc = sendfile_f; sendfile_cmd.argmin = 2; sendfile_cmd.argmax = -1; sendfile_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; sendfile_cmd.args = _("-i infile | -f N [off len]"); sendfile_cmd.oneline = _("Transfer data directly between file descriptors"); sendfile_cmd.help = sendfile_help; add_command(&sendfile_cmd); } xfsprogs-5.3.0/io/shutdown.c0000644000175000017500000000301013435336036015672 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t shutdown_cmd; static int shutdown_f( int argc, char **argv) { int c, flag = XFS_FSOP_GOING_FLAGS_NOLOGFLUSH; while ((c = getopt(argc, argv, "fv")) != -1) { switch (c) { case 'f': flag = XFS_FSOP_GOING_FLAGS_LOGFLUSH; break; default: return command_usage(&shutdown_cmd); } } if ((xfsctl(file->name, file->fd, XFS_IOC_GOINGDOWN, &flag)) < 0) { perror("XFS_IOC_GOINGDOWN"); return 0; } return 0; } static void shutdown_help(void) { printf(_( "\n" " Shuts down the filesystem and prevents any further IO from occurring.\n" "\n" " By default, shutdown will not flush completed transactions to disk\n" " before shutting the filesystem down, simulating a disk failure or crash.\n" " With -f, the log will be flushed to disk, matching XFS behavior when\n" " metadata corruption is encountered.\n" "\n" " -f -- Flush completed transactions to disk before shut down.\n" "\n")); } void shutdown_init(void) { shutdown_cmd.name = "shutdown"; shutdown_cmd.cfunc = shutdown_f; shutdown_cmd.argmin = 0; shutdown_cmd.argmax = 1; shutdown_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK; shutdown_cmd.args = _("[-f]"); shutdown_cmd.help = shutdown_help; shutdown_cmd.oneline = _("shuts down the filesystem where the current file resides"); if (expert) add_command(&shutdown_cmd); } xfsprogs-5.3.0/io/stat.c0000644000175000017500000002603413570057155015007 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. * Copyright (C) 2015, 2017 Red Hat, Inc. * Portions of statx support written by David Howells (dhowells@redhat.com) */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include "statx.h" #include "libxfs.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" #include static cmdinfo_t stat_cmd; static cmdinfo_t statfs_cmd; static cmdinfo_t statx_cmd; off64_t filesize(void) { struct stat st; if (fstat(file->fd, &st) < 0) { perror("fstat"); return -1; } return st.st_size; } static char * filetype(mode_t mode) { switch (mode & S_IFMT) { case S_IFSOCK: return _("socket"); case S_IFDIR: return _("directory"); case S_IFCHR: return _("char device"); case S_IFBLK: return _("block device"); case S_IFREG: return _("regular file"); case S_IFLNK: return _("symbolic link"); case S_IFIFO: return _("fifo"); } return NULL; } static int dump_raw_stat(struct stat *st) { printf("stat.blksize = %lu\n", (unsigned long)st->st_blksize); printf("stat.nlink = %lu\n", (unsigned long)st->st_nlink); printf("stat.uid = %u\n", st->st_uid); printf("stat.gid = %u\n", st->st_gid); printf("stat.mode: 0%o\n", st->st_mode); printf("stat.ino = %llu\n", (unsigned long long)st->st_ino); printf("stat.size = %lld\n", (long long)st->st_size); printf("stat.blocks = %lld\n", (long long)st->st_blocks); printf("stat.atime.tv_sec = %ld\n", st->st_atim.tv_sec); printf("stat.atime.tv_nsec = %ld\n", st->st_atim.tv_nsec); printf("stat.ctime.tv_sec = %ld\n", st->st_ctim.tv_sec); printf("stat.ctime.tv_nsec = %ld\n", st->st_ctim.tv_nsec); printf("stat.mtime.tv_sec = %ld\n", st->st_mtim.tv_sec); printf("stat.mtime.tv_nsec = %ld\n", st->st_mtim.tv_nsec); printf("stat.rdev_major = %u\n", major(st->st_rdev)); printf("stat.rdev_minor = %u\n", minor(st->st_rdev)); printf("stat.dev_major = %u\n", major(st->st_dev)); printf("stat.dev_minor = %u\n", minor(st->st_dev)); return 0; } static void print_file_info(void) { printf(_("fd.path = \"%s\"\n"), file->name); printf(_("fd.flags = %s,%s,%s%s%s%s%s\n"), file->flags & IO_OSYNC ? _("sync") : _("non-sync"), file->flags & IO_DIRECT ? _("direct") : _("non-direct"), file->flags & IO_READONLY ? _("read-only") : _("read-write"), file->flags & IO_REALTIME ? _(",real-time") : "", file->flags & IO_APPEND ? _(",append-only") : "", file->flags & IO_NONBLOCK ? _(",non-block") : "", file->flags & IO_TMPFILE ? _(",tmpfile") : ""); } static void print_xfs_info(int verbose) { struct dioattr dio; struct fsxattr fsx, fsxa; if ((xfsctl(file->name, file->fd, FS_IOC_FSGETXATTR, &fsx)) < 0 || (xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTRA, &fsxa)) < 0) { perror("FS_IOC_FSGETXATTR"); } else { printf(_("fsxattr.xflags = 0x%x "), fsx.fsx_xflags); printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1); printf(_("fsxattr.projid = %u\n"), fsx.fsx_projid); printf(_("fsxattr.extsize = %u\n"), fsx.fsx_extsize); printf(_("fsxattr.cowextsize = %u\n"), fsx.fsx_cowextsize); printf(_("fsxattr.nextents = %u\n"), fsx.fsx_nextents); printf(_("fsxattr.naextents = %u\n"), fsxa.fsx_nextents); } if ((xfsctl(file->name, file->fd, XFS_IOC_DIOINFO, &dio)) < 0) { perror("XFS_IOC_DIOINFO"); } else { printf(_("dioattr.mem = 0x%x\n"), dio.d_mem); printf(_("dioattr.miniosz = %u\n"), dio.d_miniosz); printf(_("dioattr.maxiosz = %u\n"), dio.d_maxiosz); } } int stat_f( int argc, char **argv) { struct stat st; int c, verbose = 0, raw = 0; while ((c = getopt(argc, argv, "rv")) != EOF) { switch (c) { case 'r': raw = 1; break; case 'v': verbose = 1; break; default: return command_usage(&stat_cmd); } } if (raw && verbose) return command_usage(&stat_cmd); if (fstat(file->fd, &st) < 0) { perror("fstat"); return 0; } if (raw) return dump_raw_stat(&st); print_file_info(); printf(_("stat.ino = %lld\n"), (long long)st.st_ino); printf(_("stat.type = %s\n"), filetype(st.st_mode)); printf(_("stat.size = %lld\n"), (long long)st.st_size); printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks); if (verbose) { printf(_("stat.atime = %s"), ctime(&st.st_atime)); printf(_("stat.mtime = %s"), ctime(&st.st_mtime)); printf(_("stat.ctime = %s"), ctime(&st.st_ctime)); } if (file->flags & IO_FOREIGN) return 0; print_xfs_info(verbose); return 0; } static int statfs_f( int argc, char **argv) { struct xfs_fsop_counts fscounts; struct xfs_fsop_geom fsgeo; struct statfs st; int ret; printf(_("fd.path = \"%s\"\n"), file->name); if (platform_fstatfs(file->fd, &st) < 0) { perror("fstatfs"); } else { printf(_("statfs.f_bsize = %lld\n"), (long long) st.f_bsize); printf(_("statfs.f_blocks = %lld\n"), (long long) st.f_blocks); printf(_("statfs.f_bavail = %lld\n"), (long long) st.f_bavail); printf(_("statfs.f_files = %lld\n"), (long long) st.f_files); printf(_("statfs.f_ffree = %lld\n"), (long long) st.f_ffree); #ifdef HAVE_STATFS_FLAGS printf(_("statfs.f_flags = 0x%llx\n"), (long long) st.f_flags); #endif } if (file->flags & IO_FOREIGN) return 0; ret = -xfrog_geometry(file->fd, &fsgeo); if (ret) { xfrog_perror(ret, "XFS_IOC_FSGEOMETRY"); } else { printf(_("geom.bsize = %u\n"), fsgeo.blocksize); printf(_("geom.agcount = %u\n"), fsgeo.agcount); printf(_("geom.agblocks = %u\n"), fsgeo.agblocks); printf(_("geom.datablocks = %llu\n"), (unsigned long long) fsgeo.datablocks); printf(_("geom.rtblocks = %llu\n"), (unsigned long long) fsgeo.rtblocks); printf(_("geom.rtextents = %llu\n"), (unsigned long long) fsgeo.rtextents); printf(_("geom.rtextsize = %u\n"), fsgeo.rtextsize); printf(_("geom.sunit = %u\n"), fsgeo.sunit); printf(_("geom.swidth = %u\n"), fsgeo.swidth); } if ((xfsctl(file->name, file->fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) { perror("XFS_IOC_FSCOUNTS"); } else { printf(_("counts.freedata = %llu\n"), (unsigned long long) fscounts.freedata); printf(_("counts.freertx = %llu\n"), (unsigned long long) fscounts.freertx); printf(_("counts.freeino = %llu\n"), (unsigned long long) fscounts.freeino); printf(_("counts.allocino = %llu\n"), (unsigned long long) fscounts.allocino); } return 0; } static ssize_t _statx( int dfd, const char *filename, unsigned int flags, unsigned int mask, struct statx *buffer) { #ifdef __NR_statx return syscall(__NR_statx, dfd, filename, flags, mask, buffer); #else errno = ENOSYS; return -1; #endif } static void statx_help(void) { printf(_( "\n" " Display extended file status.\n" "\n" " Options:\n" " -v -- More verbose output\n" " -r -- Print raw statx structure fields\n" " -m mask -- Specify the field mask for the statx call\n" " (can also be 'basic' or 'all'; default STATX_ALL)\n" " -D -- Don't sync attributes with the server\n" " -F -- Force the attributes to be sync'd with the server\n" "\n")); } /* statx helper */ static int dump_raw_statx(struct statx *stx) { printf("stat.mask = 0x%x\n", stx->stx_mask); printf("stat.blksize = %u\n", stx->stx_blksize); printf("stat.attributes = 0x%llx\n", (unsigned long long)stx->stx_attributes); printf("stat.nlink = %u\n", stx->stx_nlink); printf("stat.uid = %u\n", stx->stx_uid); printf("stat.gid = %u\n", stx->stx_gid); printf("stat.mode: 0%o\n", stx->stx_mode); printf("stat.ino = %llu\n", (unsigned long long)stx->stx_ino); printf("stat.size = %llu\n", (unsigned long long)stx->stx_size); printf("stat.blocks = %llu\n", (unsigned long long)stx->stx_blocks); printf("stat.attributes_mask = 0x%llx\n", (unsigned long long)stx->stx_attributes_mask); printf("stat.atime.tv_sec = %lld\n", (long long)stx->stx_atime.tv_sec); printf("stat.atime.tv_nsec = %d\n", stx->stx_atime.tv_nsec); printf("stat.btime.tv_sec = %lld\n", (long long)stx->stx_btime.tv_sec); printf("stat.btime.tv_nsec = %d\n", stx->stx_btime.tv_nsec); printf("stat.ctime.tv_sec = %lld\n", (long long)stx->stx_ctime.tv_sec); printf("stat.ctime.tv_nsec = %d\n", stx->stx_ctime.tv_nsec); printf("stat.mtime.tv_sec = %lld\n", (long long)stx->stx_mtime.tv_sec); printf("stat.mtime.tv_nsec = %d\n", stx->stx_mtime.tv_nsec); printf("stat.rdev_major = %u\n", stx->stx_rdev_major); printf("stat.rdev_minor = %u\n", stx->stx_rdev_minor); printf("stat.dev_major = %u\n", stx->stx_dev_major); printf("stat.dev_minor = %u\n", stx->stx_dev_minor); return 0; } /* * options: * - input flags - query type * - output style for flags (and all else?) (chars vs. hex?) * - output - mask out incidental flag or not? */ static int statx_f( int argc, char **argv) { int c, verbose = 0, raw = 0; char *p; struct statx stx; int atflag = 0; unsigned int mask = STATX_ALL; while ((c = getopt(argc, argv, "m:rvFD")) != EOF) { switch (c) { case 'm': if (strcmp(optarg, "basic") == 0) mask = STATX_BASIC_STATS; else if (strcmp(optarg, "all") == 0) mask = STATX_ALL; else { mask = strtoul(optarg, &p, 0); if (!p || p == optarg) { printf( _("non-numeric mask -- %s\n"), optarg); return 0; } } break; case 'r': raw = 1; break; case 'v': verbose = 1; break; case 'F': atflag &= ~AT_STATX_SYNC_TYPE; atflag |= AT_STATX_FORCE_SYNC; break; case 'D': atflag &= ~AT_STATX_SYNC_TYPE; atflag |= AT_STATX_DONT_SYNC; break; default: return command_usage(&statx_cmd); } } if (raw && verbose) return command_usage(&statx_cmd); memset(&stx, 0xbf, sizeof(stx)); if (_statx(file->fd, "", atflag | AT_EMPTY_PATH, mask, &stx) < 0) { perror("statx"); return 0; } if (raw) return dump_raw_statx(&stx); print_file_info(); printf(_("stat.ino = %lld\n"), (long long)stx.stx_ino); printf(_("stat.type = %s\n"), filetype(stx.stx_mode)); printf(_("stat.size = %lld\n"), (long long)stx.stx_size); printf(_("stat.blocks = %lld\n"), (long long)stx.stx_blocks); if (verbose) { printf(_("stat.atime = %s"), ctime((time_t *)&stx.stx_atime.tv_sec)); printf(_("stat.mtime = %s"), ctime((time_t *)&stx.stx_mtime.tv_sec)); printf(_("stat.ctime = %s"), ctime((time_t *)&stx.stx_ctime.tv_sec)); if (stx.stx_mask & STATX_BTIME) printf(_("stat.btime = %s"), ctime((time_t *)&stx.stx_btime.tv_sec)); } if (file->flags & IO_FOREIGN) return 0; print_xfs_info(verbose); return 0; } void stat_init(void) { stat_cmd.name = "stat"; stat_cmd.cfunc = stat_f; stat_cmd.argmin = 0; stat_cmd.argmax = 1; stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; stat_cmd.args = _("[-v|-r]"); stat_cmd.oneline = _("statistics on the currently open file"); statx_cmd.name = "statx"; statx_cmd.cfunc = statx_f; statx_cmd.argmin = 0; statx_cmd.argmax = -1; statx_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; statx_cmd.args = _("[-v|-r][-m basic | -m all | -m ][-FD]"); statx_cmd.oneline = _("extended statistics on the currently open file"); statx_cmd.help = statx_help; statfs_cmd.name = "statfs"; statfs_cmd.cfunc = statfs_f; statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; statfs_cmd.oneline = _("statistics on the filesystem of the currently open file"); add_command(&stat_cmd); add_command(&statx_cmd); add_command(&statfs_cmd); } xfsprogs-5.3.0/io/statx.h0000644000175000017500000001432513466663244015212 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #ifndef XFS_IO_STATX_H #define XFS_IO_STATX_H #include #include #ifndef AT_EMPTY_PATH #define AT_EMPTY_PATH 0x1000 #endif #ifndef AT_STATX_SYNC_TYPE #define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */ #define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ #define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */ #define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */ #endif #ifndef AT_NO_AUTOMOUNT #define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ #endif #ifndef __NR_statx # if defined(__i386__) || defined(__powerpc__) # define __NR_statx 383 # elif defined (__x86_64__) # if defined (__ILP32__) # define __NR_statx (__X32_SYSCALL_BIT + 332) # else # define __NR_statx 332 # endif # endif #endif #ifndef STATX_TYPE /* Pick up kernel definitions if glibc didn't already provide them */ #include #endif #ifndef STATX_TYPE /* Local definitions if glibc & kernel headers didn't already provide them */ /* * Timestamp structure for the timestamps in struct statx. * * tv_sec holds the number of seconds before (negative) or after (positive) * 00:00:00 1st January 1970 UTC. * * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time. * * Note that if both tv_sec and tv_nsec are non-zero, then the two values must * either be both positive or both negative. * * __reserved is held in case we need a yet finer resolution. */ struct statx_timestamp { __s64 tv_sec; __s32 tv_nsec; __s32 __reserved; }; /* * Structures for the extended file attribute retrieval system call * (statx()). * * The caller passes a mask of what they're specifically interested in as a * parameter to statx(). What statx() actually got will be indicated in * st_mask upon return. * * For each bit in the mask argument: * * - if the datum is not supported: * * - the bit will be cleared, and * * - the datum will be set to an appropriate fabricated value if one is * available (eg. CIFS can take a default uid and gid), otherwise * * - the field will be cleared; * * - otherwise, if explicitly requested: * * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is * set or if the datum is considered out of date, and * * - the field will be filled in and the bit will be set; * * - otherwise, if not requested, but available in approximate form without any * effort, it will be filled in anyway, and the bit will be set upon return * (it might not be up to date, however, and no attempt will be made to * synchronise the internal state first); * * - otherwise the field and the bit will be cleared before returning. * * Items in STATX_BASIC_STATS may be marked unavailable on return, but they * will have values installed for compatibility purposes so that stat() and * co. can be emulated in userspace. */ struct statx { /* 0x00 */ __u32 stx_mask; /* What results were written [uncond] */ __u32 stx_blksize; /* Preferred general I/O size [uncond] */ __u64 stx_attributes; /* Flags conveying information about the file [uncond] */ /* 0x10 */ __u32 stx_nlink; /* Number of hard links */ __u32 stx_uid; /* User ID of owner */ __u32 stx_gid; /* Group ID of owner */ __u16 stx_mode; /* File mode */ __u16 __spare0[1]; /* 0x20 */ __u64 stx_ino; /* Inode number */ __u64 stx_size; /* File size */ __u64 stx_blocks; /* Number of 512-byte blocks allocated */ __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ /* 0x40 */ struct statx_timestamp stx_atime; /* Last access time */ struct statx_timestamp stx_btime; /* File creation time */ struct statx_timestamp stx_ctime; /* Last attribute change time */ struct statx_timestamp stx_mtime; /* Last data modification time */ /* 0x80 */ __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */ __u32 stx_rdev_minor; __u32 stx_dev_major; /* ID of device containing file [uncond] */ __u32 stx_dev_minor; /* 0x90 */ __u64 __spare2[14]; /* Spare space for future expansion */ /* 0x100 */ }; /* * Flags to be stx_mask * * Query request/result mask for statx() and struct statx::stx_mask. * * These bits should be set in the mask argument of statx() to request * particular items when calling statx(). */ #define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ #define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ #define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ #define STATX_UID 0x00000008U /* Want/got stx_uid */ #define STATX_GID 0x00000010U /* Want/got stx_gid */ #define STATX_ATIME 0x00000020U /* Want/got stx_atime */ #define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ #define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ #define STATX_INO 0x00000100U /* Want/got stx_ino */ #define STATX_SIZE 0x00000200U /* Want/got stx_size */ #define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ #define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ #define STATX_BTIME 0x00000800U /* Want/got stx_btime */ #define STATX_ALL 0x00000fffU /* All currently supported flags */ #define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ /* * Attributes to be found in stx_attributes * * These give information about the features or the state of a file that might * be of use to ordinary userspace programs such as GUIs or ls rather than * specialised tools. * * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS * semantically. Where possible, the numerical value is picked to correspond * also. */ #define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */ #define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */ #define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ #define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ #define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ #define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ #endif /* STATX_TYPE */ #endif /* XFS_IO_STATX_H */ xfsprogs-5.3.0/io/swapext.c0000644000175000017500000000337513570057155015532 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018 Red Hat, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" static cmdinfo_t swapext_cmd; static void swapext_help(void) { printf(_( "\n" " Swaps extents between the open file descriptor and the supplied filename.\n" "\n")); } static int swapext_f( int argc, char **argv) { struct xfs_fd fxfd = XFS_FD_INIT(file->fd); struct xfs_bulkstat bulkstat; int fd; int error; struct xfs_swapext sx; struct stat stat; /* open the donor file */ fd = openfile(argv[1], NULL, 0, 0, NULL); if (fd < 0) return 0; /* * stat the target file to get the inode number and use the latter to * get the bulkstat info for the swapext cmd. */ error = fstat(file->fd, &stat); if (error) { perror("fstat"); goto out; } error = -xfrog_bulkstat_single(&fxfd, stat.st_ino, 0, &bulkstat); if (error) { xfrog_perror(error, "bulkstat"); goto out; } error = -xfrog_bulkstat_v5_to_v1(&fxfd, &sx.sx_stat, &bulkstat); if (error) { xfrog_perror(error, "bulkstat conversion"); goto out; } sx.sx_version = XFS_SX_VERSION; sx.sx_fdtarget = file->fd; sx.sx_fdtmp = fd; sx.sx_offset = 0; sx.sx_length = stat.st_size; error = ioctl(file->fd, XFS_IOC_SWAPEXT, &sx); if (error) perror("swapext"); out: close(fd); return 0; } void swapext_init(void) { swapext_cmd.name = "swapext"; swapext_cmd.cfunc = swapext_f; swapext_cmd.argmin = 1; swapext_cmd.argmax = 1; swapext_cmd.flags = CMD_NOMAP_OK; swapext_cmd.args = _(""); swapext_cmd.oneline = _("Swap extents between files."); swapext_cmd.help = swapext_help; add_command(&swapext_cmd); } xfsprogs-5.3.0/io/sync.c0000644000175000017500000000201413435336036014776 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Red Hat, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "init.h" #include "io.h" static cmdinfo_t sync_cmd; static int sync_f( int argc, char **argv) { /* sync can't fail */ sync(); return 0; } #ifdef HAVE_SYNCFS static cmdinfo_t syncfs_cmd; static int syncfs_f( int argc, char **argv) { if (syncfs(file->fd) < 0) { perror("syncfs"); exitcode = 1; } return 0; } #endif void sync_init(void) { sync_cmd.name = "sync"; sync_cmd.cfunc = sync_f; sync_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; sync_cmd.oneline = _("calls sync(2) to flush all in-core filesystem state to disk"); add_command(&sync_cmd); #ifdef HAVE_SYNCFS syncfs_cmd.name = "syncfs"; syncfs_cmd.cfunc = syncfs_f; syncfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; syncfs_cmd.oneline = _("calls syncfs(2) to flush all in-core filesystem state to disk"); add_command(&syncfs_cmd); #endif } xfsprogs-5.3.0/io/sync_file_range.c0000644000175000017500000000415413435336036017160 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2012 Red Hat, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t sync_range_cmd; static void sync_range_help(void) { printf(_( "\n" " Trigger specific writeback commands on a range of the current file\n" "\n" " With no options, the SYNC_FILE_RANGE_WRITE is implied.\n" " -a -- wait for IO to finish after writing (SYNC_FILE_RANGE_WAIT_AFTER).\n" " -b -- wait for IO to finish before writing (SYNC_FILE_RANGE_WAIT_BEFORE).\n" " -w -- write dirty data in range (SYNC_FILE_RANGE_WRITE).\n" "\n")); } static int sync_range_f( int argc, char **argv) { off64_t offset = 0, length = 0; int c, sync_mode = 0; size_t blocksize, sectsize; while ((c = getopt(argc, argv, "abw")) != EOF) { switch (c) { case 'a': sync_mode = SYNC_FILE_RANGE_WAIT_AFTER; break; case 'b': sync_mode = SYNC_FILE_RANGE_WAIT_BEFORE; break; case 'w': sync_mode = SYNC_FILE_RANGE_WRITE; break; default: return command_usage(&sync_range_cmd); } } /* default to just starting writeback on the range */ if (!sync_mode) sync_mode = SYNC_FILE_RANGE_WRITE; if (optind != argc - 2) return command_usage(&sync_range_cmd); init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; length = cvtnum(blocksize, sectsize, argv[optind]); if (length < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } if (sync_file_range(file->fd, offset, length, sync_mode) < 0) { perror("sync_file_range"); return 0; } return 0; } void sync_range_init(void) { sync_range_cmd.name = "sync_range"; sync_range_cmd.cfunc = sync_range_f; sync_range_cmd.argmin = 2; sync_range_cmd.argmax = -1; sync_range_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; sync_range_cmd.args = _("[-abw] off len"); sync_range_cmd.oneline = _("Control writeback on a range of a file"); sync_range_cmd.help = sync_range_help; add_command(&sync_range_cmd); } xfsprogs-5.3.0/io/truncate.c0000644000175000017500000000171313435336036015654 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t truncate_cmd; static int truncate_f( int argc, char **argv) { off64_t offset; size_t blocksize, sectsize; init_cvtnum(&blocksize, §size); offset = cvtnum(blocksize, sectsize, argv[1]); if (offset < 0) { printf(_("non-numeric truncate argument -- %s\n"), argv[1]); return 0; } if (ftruncate(file->fd, offset) < 0) { perror("ftruncate"); return 0; } return 0; } void truncate_init(void) { truncate_cmd.name = "truncate"; truncate_cmd.altname = "t"; truncate_cmd.cfunc = truncate_f; truncate_cmd.argmin = 1; truncate_cmd.argmax = 1; truncate_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; truncate_cmd.args = _("off"); truncate_cmd.oneline = _("truncates the current file at the given offset"); add_command(&truncate_cmd); } xfsprogs-5.3.0/io/utimes.c0000644000175000017500000000257313435336036015342 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 Deepa Dinamani * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "io.h" static cmdinfo_t utimes_cmd; static void utimes_help(void) { printf(_( "\n" " Update file atime and mtime of the current file with nansecond precision.\n" "\n" " Usage: utimes atime_sec atime_nsec mtime_sec mtime_nsec.\n" " *_sec: Seconds elapsed since 1970-01-01 00:00:00 UTC.\n" " *_nsec: Nanoseconds since the corresponding *_sec.\n" "\n")); } static int utimes_f( int argc, char **argv) { struct timespec t[2]; int result; /* Get the timestamps */ result = timespec_from_string(argv[1], argv[2], &t[0]); if (result) { fprintf(stderr, "Bad value for atime\n"); return 0; } result = timespec_from_string(argv[3], argv[4], &t[1]); if (result) { fprintf(stderr, "Bad value for mtime\n"); return 0; } /* Call futimens to update time. */ if (futimens(file->fd, t)) { perror("futimens"); return 0; } return 0; } void utimes_init(void) { utimes_cmd.name = "utimes"; utimes_cmd.cfunc = utimes_f; utimes_cmd.argmin = 4; utimes_cmd.argmax = 4; utimes_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; utimes_cmd.args = _("atime_sec atime_nsec mtime_sec mtime_nsec"); utimes_cmd.oneline = _("Update file times of the current file"); utimes_cmd.help = utimes_help; add_command(&utimes_cmd); } xfsprogs-5.3.0/io/xfs_bmap.sh0000755000175000017500000000126713435336036016025 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. # OPTS="" VERSION=false USAGE="Usage: xfs_bmap [-adelpvV] [-n nx] file..." DIRNAME=`dirname $0` while getopts "adeln:pvV" c do case $c in a) OPTS=$OPTS" -a";; d) OPTS=$OPTS" -d";; e) OPTS=$OPTS" -e";; l) OPTS=$OPTS" -l";; n) OPTS=$OPTS" -n "$OPTARG;; p) OPTS=$OPTS" -p";; v) OPTS=$OPTS" -v";; V) VERSION=true;; \?) echo $USAGE 1>&2 exit 2 ;; esac done $VERSION && $DIRNAME/xfs_io -p xfs_bmap -V shift `expr $OPTIND - 1` while [ "$1" != "" ] do $DIRNAME/xfs_io -r -p xfs_bmap -c "bmap $OPTS" "$1" status=$? [ $status -ne 0 ] && exit $status shift done exit 0 xfsprogs-5.3.0/io/xfs_freeze.sh0000644000175000017500000000144013435336036016354 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # OPTS="" USAGE="Usage: xfs_freeze [-V] [-f | -u] " DIRNAME=`dirname $0` VERSION=false FREEZE=false THAW=false while getopts "fuV" c do case $c in f) FREEZE=true;; u) THAW=true;; V) VERSION=true;; \?) echo $USAGE 1>&2 exit 2 ;; esac done if $VERSION ; then $DIRNAME/xfs_io -p xfs_freeze -V exit 0 fi shift `expr $OPTIND - 1` if [ "$1" = "" ]; then echo $USAGE 1>&2 exit 2 fi if $FREEZE ; then $DIRNAME/xfs_io -F -r -p xfs_freeze -x -c "freeze" "$1" status=$? [ $status -ne 0 ] && exit $status elif $THAW ; then $DIRNAME/xfs_io -F -r -p xfs_freeze -x -c "thaw" "$1" status=$? [ $status -ne 0 ] && exit $status else echo $USAGE 1>&2 exit 2 fi exit 0 xfsprogs-5.3.0/io/xfs_mkfile.sh0000755000175000017500000000202013435336036016341 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # OPTS="" NOBYTES=false PREALLOC=false VERBOSE=false VERSION=false XFS_IO=`dirname $0`"/xfs_io -p xfs_mkfile" USAGE="Usage: xfs_mkfile [-npvV] size file..." while getopts "npvV" c do case $c in n) NOBYTES=true;; p) PREALLOC=true;; v) VERBOSE=true;; V) VERSION=true;; \?) echo $USAGE 1>&2 exit 2 ;; esac done $VERSION && $XFS_IO -V shift `expr $OPTIND - 1` [ "$1" != "" ] || exit 0 SIZE="$1" ERRORS=0 shift while [ "$1" != "" ] do if $VERBOSE ; then $PREALLOC && echo "$1 $SIZE bytes pre-allocated" $PREALLOC || echo "$1 $SIZE bytes" fi if $NOBYTES ; then $XFS_IO -ft -c "truncate $SIZE" -- "$1" elif $PREALLOC ; then $XFS_IO -ftd -c "resvsp 0 $SIZE" \ -c "pwrite -q -S0 -b256k 0 $SIZE" \ -c "truncate $SIZE" -- "$1" else $XFS_IO -ftd -c "pwrite -q -S0 -b256k 0 $SIZE" \ -c "truncate $SIZE" -- "$1" fi [ $? -eq 0 ] || ERRORS=`expr $ERRORS + 1` shift done exit $ERRORS xfsprogs-5.3.0/libfrog/Makefile0000644000175000017500000000306113570057155016340 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2017 Oracle. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTLIBRARY = libfrog.la LT_CURRENT = 0 LT_REVISION = 0 LT_AGE = 0 CFILES = \ avl64.c \ bitmap.c \ bulkstat.c \ convert.c \ crc32.c \ fsgeom.c \ list_sort.c \ linux.c \ logging.c \ paths.c \ projects.c \ ptvar.c \ radix-tree.c \ scrub.c \ topology.c \ util.c \ workqueue.c HFILES = \ avl64.h \ bulkstat.h \ bitmap.h \ convert.h \ crc32c.h \ crc32cselftest.h \ crc32defs.h \ crc32table.h \ fsgeom.h \ logging.h \ paths.h \ projects.h \ ptvar.h \ radix-tree.h \ scrub.h \ topology.h \ workqueue.h LSRCFILES += gen_crc32table.c ifeq ($(HAVE_GETMNTENT),yes) LCFLAGS += -DHAVE_GETMNTENT endif LDIRT = gen_crc32table crc32table.h crc32selftest default: crc32selftest ltdepend $(LTLIBRARY) crc32table.h: gen_crc32table.c crc32defs.h @echo " [CC] gen_crc32table" $(Q) $(BUILD_CC) $(BUILD_CFLAGS) -o gen_crc32table $< @echo " [GENERATE] $@" $(Q) ./gen_crc32table > crc32table.h # The selftest binary will return an error if it fails. This is made a # dependency of the build process so that we refuse to build the tools on broken # systems/architectures. Hence we make sure that xfsprogs will never use a # busted CRC calculation at build time and hence avoid putting bad CRCs down on # disk. crc32selftest: gen_crc32table.c crc32table.h crc32.c crc32defs.h @echo " [TEST] CRC32" $(Q) $(BUILD_CC) $(BUILD_CFLAGS) -D CRC32_SELFTEST=1 crc32.c -o $@ $(Q) ./$@ include $(BUILDRULES) install install-dev: default -include .ltdep xfsprogs-5.3.0/libfrog/avl64.c0000644000175000017500000007233613435336036016011 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include "platform_defs.h" #include "avl64.h" #define CERT ASSERT #ifdef AVL_DEBUG static void avl64_checknode( avl64tree_desc_t *tree, avl64node_t *np) { avl64node_t *back = np->avl_back; avl64node_t *forw = np->avl_forw; avl64node_t *nextino = np->avl_nextino; int bal = np->avl_balance; ASSERT(bal != AVL_BALANCE || (!back && !forw) || (back && forw)); ASSERT(bal != AVL_FORW || forw); ASSERT(bal != AVL_BACK || back); if (forw) { ASSERT(AVL_START(tree, np) < AVL_START(tree, forw)); ASSERT(np->avl_forw->avl_parent == np); ASSERT(back || bal == AVL_FORW); } else { ASSERT(bal != AVL_FORW); ASSERT(bal == AVL_BALANCE || back); ASSERT(bal == AVL_BACK || !back); } if (back) { ASSERT(AVL_START(tree, np) > AVL_START(tree, back)); ASSERT(np->avl_back->avl_parent == np); ASSERT(forw || bal == AVL_BACK); } else { ASSERT(bal != AVL_BACK); ASSERT(bal == AVL_BALANCE || forw); ASSERT(bal == AVL_FORW || !forw); } if (nextino == NULL) ASSERT(forw == NULL); else ASSERT(AVL_END(tree, np) <= AVL_START(tree, nextino)); } static void avl64_checktree( avl64tree_desc_t *tree, avl64node_t *root) { avl64node_t *nlast, *nnext, *np; uint64_t offset = 0; uint64_t end; nlast = nnext = root; ASSERT(!nnext || nnext->avl_parent == NULL); while (nnext) { avl64_checknode(tree, nnext); end = AVL_END(tree, nnext); if (end <= offset) { if ((np = nnext->avl_forw) && np != nlast) { nlast = nnext; nnext = np; } else { nlast = nnext; nnext = nnext->avl_parent; } continue; } nlast = nnext; if (np = nnext->avl_back) { if (AVL_END(tree, np) > offset) { nnext = np; continue; } } np = nnext; nnext = nnext->avl_forw; if (!nnext) nnext = np->avl_parent; offset = end; } } #else /* ! AVL_DEBUG */ #define avl64_checktree(t,x) #endif /* AVL_DEBUG */ /* * Reset balance for np up through tree. * ``direction'' is the way that np's balance * is headed after the deletion of one of its children -- * e.g., deleting a avl_forw child sends avl_balance toward AVL_BACK. * Called only when deleting a node from the tree. */ static void retreat( avl64tree_desc_t *tree, avl64node_t *np, int direction) { avl64node_t **rootp = &tree->avl_root; avl64node_t *parent; avl64node_t *child; avl64node_t *tmp; int bal; do { ASSERT(direction == AVL_BACK || direction == AVL_FORW); if (np->avl_balance == AVL_BALANCE) { np->avl_balance = direction; return; } parent = np->avl_parent; /* * If balance is being restored, no local node * reorganization is necessary, but may be at * a higher node. Reset direction and continue. */ if (direction != np->avl_balance) { np->avl_balance = AVL_BALANCE; if (parent) { if (parent->avl_forw == np) direction = AVL_BACK; else direction = AVL_FORW; np = parent; continue; } return; } /* * Imbalance. If a avl_forw node was removed, direction * (and, by reduction, np->avl_balance) is/was AVL_BACK. */ if (np->avl_balance == AVL_BACK) { ASSERT(direction == AVL_BACK); child = np->avl_back; bal = child->avl_balance; if (bal != AVL_FORW) /* single LL */ { /* * np gets pushed down to lesser child's * avl_forw branch. * * np-> -D +B * / \ / \ * child-> B deleted A -D * / \ / * A C C cmn_err(CE_CONT, "!LL delete b 0x%x c 0x%x\n", np, child); */ np->avl_back = child->avl_forw; if (child->avl_forw) child->avl_forw->avl_parent = np; child->avl_forw = np; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = child; direction = AVL_BACK; } else { ASSERT(parent->avl_back == np); parent->avl_back = child; direction = AVL_FORW; } } else { ASSERT(*rootp == np); *rootp = child; } np->avl_parent = child; child->avl_parent = parent; if (bal == AVL_BALANCE) { np->avl_balance = AVL_BACK; child->avl_balance = AVL_FORW; return; } else { np->avl_balance = AVL_BALANCE; child->avl_balance = AVL_BALANCE; np = parent; avl64_checktree(tree, *rootp); continue; } } /* child->avl_balance == AVL_FORW double LR rotation * * child's avl_forw node gets promoted up, along with * its avl_forw subtree * * np-> -G C * / \ / \ * child-> +B H -B G * / \ \ / / \ * A +C deleted A D H * \ * D cmn_err(CE_CONT, "!LR delete b 0x%x c 0x%x t 0x%x\n", np, child, child->avl_forw); */ tmp = child->avl_forw; bal = tmp->avl_balance; child->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = child; tmp->avl_back = child; child->avl_parent = tmp; np->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = np; tmp->avl_forw = np; if (bal == AVL_FORW) child->avl_balance = AVL_BACK; else child->avl_balance = AVL_BALANCE; if (bal == AVL_BACK) np->avl_balance = AVL_FORW; else np->avl_balance = AVL_BALANCE; goto next; } ASSERT(np->avl_balance == AVL_FORW && direction == AVL_FORW); child = np->avl_forw; bal = child->avl_balance; if (bal != AVL_BACK) /* single RR */ { /* * np gets pushed down to greater child's * avl_back branch. * * np-> +B -D * / \ / \ * deleted D <-child +B E * / \ \ * C E C cmn_err(CE_CONT, "!RR delete b 0x%x c 0x%x\n", np, child); */ np->avl_forw = child->avl_back; if (child->avl_back) child->avl_back->avl_parent = np; child->avl_back = np; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = child; direction = AVL_BACK; } else { ASSERT(parent->avl_back == np); parent->avl_back = child; direction = AVL_FORW; } } else { ASSERT(*rootp == np); *rootp = child; } np->avl_parent = child; child->avl_parent = parent; if (bal == AVL_BALANCE) { np->avl_balance = AVL_FORW; child->avl_balance = AVL_BACK; return; } else { np->avl_balance = AVL_BALANCE; child->avl_balance = AVL_BALANCE; np = parent; avl64_checktree(tree, *rootp); continue; } } /* child->avl_balance == AVL_BACK double RL rotation cmn_err(CE_CONT, "!RL delete b 0x%x c 0x%x t 0x%x\n", np, child, child->avl_back); */ tmp = child->avl_back; bal = tmp->avl_balance; child->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = child; tmp->avl_forw = child; child->avl_parent = tmp; np->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = np; tmp->avl_back = np; if (bal == AVL_BACK) child->avl_balance = AVL_FORW; else child->avl_balance = AVL_BALANCE; if (bal == AVL_FORW) np->avl_balance = AVL_BACK; else np->avl_balance = AVL_BALANCE; next: np->avl_parent = tmp; tmp->avl_balance = AVL_BALANCE; tmp->avl_parent = parent; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = tmp; direction = AVL_BACK; } else { ASSERT(parent->avl_back == np); parent->avl_back = tmp; direction = AVL_FORW; } } else { ASSERT(*rootp == np); *rootp = tmp; return; } np = parent; avl64_checktree(tree, *rootp); } while (np); } /* * Remove node from tree. * avl_delete does the local tree manipulations, * calls retreat() to rebalance tree up to its root. */ void avl64_delete( avl64tree_desc_t *tree, avl64node_t *np) { avl64node_t *forw = np->avl_forw; avl64node_t *back = np->avl_back; avl64node_t *parent = np->avl_parent; avl64node_t *nnext; if (np->avl_back) { /* * a left child exits, then greatest left descendent's nextino * is pointing to np; make it point to np->nextino. */ nnext = np->avl_back; while (nnext) { if (!nnext->avl_forw) break; /* can't find anything bigger */ nnext = nnext->avl_forw; } } else if (np->avl_parent) { /* * find nearest ancestor with lesser value. That ancestor's * nextino is pointing to np; make it point to np->nextino */ nnext = np->avl_parent; while (nnext) { if (AVL_END(tree, nnext) <= AVL_END(tree, np)) break; nnext = nnext->avl_parent; } } else nnext = NULL; if (nnext) { ASSERT(nnext->avl_nextino == np); nnext->avl_nextino = np->avl_nextino; /* * Something preceeds np; np cannot be firstino. */ ASSERT(tree->avl_firstino != np); } else { /* * Nothing preceeding np; after deletion, np's nextino * is firstino of tree. */ ASSERT(tree->avl_firstino == np); tree->avl_firstino = np->avl_nextino; } /* * Degenerate cases... */ if (forw == NULL) { forw = back; goto attach; } if (back == NULL) { attach: if (forw) forw->avl_parent = parent; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = forw; retreat(tree, parent, AVL_BACK); } else { ASSERT(parent->avl_back == np); parent->avl_back = forw; retreat(tree, parent, AVL_FORW); } } else { ASSERT(tree->avl_root == np); tree->avl_root = forw; } avl64_checktree(tree, tree->avl_root); return; } /* * Harder case: children on both sides. * If back's avl_forw pointer is null, just have back * inherit np's avl_forw tree, remove np from the tree * and adjust balance counters starting at back. * * np-> xI xH (befor retreat()) * / \ / \ * back-> H J G J * / / \ / \ * G ? ? ? ? * / \ * ? ? */ if ((forw = back->avl_forw) == NULL) { /* * AVL_FORW retreat below will set back's * balance to AVL_BACK. */ back->avl_balance = np->avl_balance; back->avl_forw = forw = np->avl_forw; forw->avl_parent = back; back->avl_parent = parent; if (parent) { if (parent->avl_forw == np) parent->avl_forw = back; else { ASSERT(parent->avl_back == np); parent->avl_back = back; } } else { ASSERT(tree->avl_root == np); tree->avl_root = back; } /* * back is taking np's place in the tree, and * has therefore lost a avl_back node (itself). */ retreat(tree, back, AVL_FORW); avl64_checktree(tree, tree->avl_root); return; } /* * Hardest case: children on both sides, and back's * avl_forw pointer isn't null. Find the immediately * inferior buffer by following back's avl_forw line * to the end, then have it inherit np's avl_forw tree. * * np-> xI xH * / \ / \ * G J back-> G J (before retreat()) * / \ / \ * F ?... F ?1 * / \ * ? H <-forw * / * ?1 */ while ((back = forw->avl_forw)) forw = back; /* * Will be adjusted by retreat() below. */ forw->avl_balance = np->avl_balance; /* * forw inherits np's avl_forw... */ forw->avl_forw = np->avl_forw; np->avl_forw->avl_parent = forw; /* * ... forw's parent gets forw's avl_back... */ back = forw->avl_parent; back->avl_forw = forw->avl_back; if (forw->avl_back) forw->avl_back->avl_parent = back; /* * ... forw gets np's avl_back... */ forw->avl_back = np->avl_back; np->avl_back->avl_parent = forw; /* * ... and forw gets np's parent. */ forw->avl_parent = parent; if (parent) { if (parent->avl_forw == np) parent->avl_forw = forw; else parent->avl_back = forw; } else { ASSERT(tree->avl_root == np); tree->avl_root = forw; } /* * What used to be forw's parent is the starting * point for rebalancing. It has lost a avl_forw node. */ retreat(tree, back, AVL_BACK); avl64_checktree(tree, tree->avl_root); } /* * avl_findanyrange: * * Given range r [start, end), find any range which is contained in r. * if checklen is non-zero, then only ranges of non-zero length are * considered in finding a match. */ avl64node_t * avl64_findanyrange( avl64tree_desc_t *tree, uint64_t start, uint64_t end, int checklen) { avl64node_t *np = tree->avl_root; /* np = avl64_findadjacent(tree, start, AVL_SUCCEED); */ while (np) { if (start < AVL_START(tree, np)) { if (np->avl_back) { np = np->avl_back; continue; } /* if we were to add node with start, would * have a growth of AVL_BACK */ /* if succeeding node is needed, this is it. */ break; } if (start >= AVL_END(tree, np)) { if (np->avl_forw) { np = np->avl_forw; continue; } /* if we were to add node with start, would * have a growth of AVL_FORW; */ /* we are looking for a succeeding node; * this is nextino. */ np = np->avl_nextino; break; } /* AVL_START(tree, np) <= start < AVL_END(tree, np) */ break; } if (np) { if (checklen == AVL_INCLUDE_ZEROLEN) { if (end <= AVL_START(tree, np)) { /* something follows start, but is * is entierly after the range (end) */ return(NULL); } /* np may stradle [start, end) */ return(np); } /* * find non-zero length region */ while (np && (AVL_END(tree, np) - AVL_START(tree, np) == 0) && (AVL_START(tree, np) < end)) np = np->avl_nextino; if ((np == NULL) || (AVL_START(tree, np) >= end)) return NULL; return(np); } /* * nothing succeeds start, all existing ranges are before start. */ return NULL; } /* * Returns a pointer to range which contains value. */ avl64node_t * avl64_findrange( avl64tree_desc_t *tree, uint64_t value) { avl64node_t *np = tree->avl_root; while (np) { if (value < AVL_START(tree, np)) { np = np->avl_back; continue; } if (value >= AVL_END(tree, np)) { np = np->avl_forw; continue; } ASSERT(AVL_START(tree, np) <= value && value < AVL_END(tree, np)); return np; } return NULL; } /* * Returns a pointer to node which contains exact value. */ avl64node_t * avl64_find( avl64tree_desc_t *tree, uint64_t value) { avl64node_t *np = tree->avl_root; uint64_t nvalue; while (np) { nvalue = AVL_START(tree, np); if (value < nvalue) { np = np->avl_back; continue; } if (value == nvalue) { return np; } np = np->avl_forw; } return NULL; } /* * Balance buffer AVL tree after attaching a new node to root. * Called only by avl_insert. */ static void avl64_balance( avl64node_t **rootp, avl64node_t *np, int growth) { /* * At this point, np points to the node to which * a new node has been attached. All that remains is to * propagate avl_balance up the tree. */ for ( ; ; ) { avl64node_t *parent = np->avl_parent; avl64node_t *child; CERT(growth == AVL_BACK || growth == AVL_FORW); /* * If the buffer was already balanced, set avl_balance * to the new direction. Continue if there is a * parent after setting growth to reflect np's * relation to its parent. */ if (np->avl_balance == AVL_BALANCE) { np->avl_balance = growth; if (parent) { if (parent->avl_forw == np) growth = AVL_FORW; else { ASSERT(parent->avl_back == np); growth = AVL_BACK; } np = parent; continue; } break; } if (growth != np->avl_balance) { /* * Subtree is now balanced -- no net effect * in the size of the subtree, so leave. */ np->avl_balance = AVL_BALANCE; break; } if (growth == AVL_BACK) { child = np->avl_back; CERT(np->avl_balance == AVL_BACK && child); if (child->avl_balance == AVL_BACK) { /* single LL */ /* * ``A'' just got inserted; * np points to ``E'', child to ``C'', * and it is already AVL_BACK -- * child will get promoted to top of subtree. np-> -E C / \ / \ child-> -C F -B E / \ / / \ -B D A D F / A Note that child->avl_parent and avl_balance get set in common code. */ np->avl_parent = child; np->avl_balance = AVL_BALANCE; np->avl_back = child->avl_forw; if (child->avl_forw) child->avl_forw->avl_parent = np; child->avl_forw = np; } else { /* * double LR * * child's avl_forw node gets promoted to * the top of the subtree. np-> -E C / \ / \ child-> +B F -B E / \ / / \ A +C A D F \ D */ avl64node_t *tmp = child->avl_forw; CERT(child->avl_balance == AVL_FORW && tmp); child->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = child; tmp->avl_back = child; child->avl_parent = tmp; np->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = np; tmp->avl_forw = np; np->avl_parent = tmp; if (tmp->avl_balance == AVL_BACK) np->avl_balance = AVL_FORW; else np->avl_balance = AVL_BALANCE; if (tmp->avl_balance == AVL_FORW) child->avl_balance = AVL_BACK; else child->avl_balance = AVL_BALANCE; /* * Set child to point to tmp since it is * now the top of the subtree, and will * get attached to the subtree parent in * the common code below. */ child = tmp; } } else /* growth == AVL_BACK */ { /* * This code is the mirror image of AVL_FORW above. */ child = np->avl_forw; CERT(np->avl_balance == AVL_FORW && child); if (child->avl_balance == AVL_FORW) { /* single RR */ np->avl_parent = child; np->avl_balance = AVL_BALANCE; np->avl_forw = child->avl_back; if (child->avl_back) child->avl_back->avl_parent = np; child->avl_back = np; } else { /* * double RL */ avl64node_t *tmp = child->avl_back; ASSERT(child->avl_balance == AVL_BACK && tmp); child->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = child; tmp->avl_forw = child; child->avl_parent = tmp; np->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = np; tmp->avl_back = np; np->avl_parent = tmp; if (tmp->avl_balance == AVL_FORW) np->avl_balance = AVL_BACK; else np->avl_balance = AVL_BALANCE; if (tmp->avl_balance == AVL_BACK) child->avl_balance = AVL_FORW; else child->avl_balance = AVL_BALANCE; child = tmp; } } child->avl_parent = parent; child->avl_balance = AVL_BALANCE; if (parent) { if (parent->avl_back == np) parent->avl_back = child; else parent->avl_forw = child; } else { ASSERT(*rootp == np); *rootp = child; } break; } } static avl64node_t * avl64_insert_find_growth( avl64tree_desc_t *tree, uint64_t start, /* range start at start, */ uint64_t end, /* exclusive */ int *growthp) /* OUT */ { avl64node_t *root = tree->avl_root; avl64node_t *np; np = root; ASSERT(np); /* caller ensures that there is atleast one node in tree */ for ( ; ; ) { CERT(np->avl_parent || root == np); CERT(!np->avl_parent || root != np); CERT(!(np->avl_back) || np->avl_back->avl_parent == np); CERT(!(np->avl_forw) || np->avl_forw->avl_parent == np); CERT(np->avl_balance != AVL_FORW || np->avl_forw); CERT(np->avl_balance != AVL_BACK || np->avl_back); CERT(np->avl_balance != AVL_BALANCE || np->avl_back == NULL || np->avl_forw); CERT(np->avl_balance != AVL_BALANCE || np->avl_forw == NULL || np->avl_back); if (AVL_START(tree, np) >= end) { if (np->avl_back) { np = np->avl_back; continue; } *growthp = AVL_BACK; break; } if (AVL_END(tree, np) <= start) { if (np->avl_forw) { np = np->avl_forw; continue; } *growthp = AVL_FORW; break; } /* found exact match -- let caller decide if it is an error */ return(NULL); } return(np); } static void avl64_insert_grow( avl64tree_desc_t *tree, avl64node_t *parent, avl64node_t *newnode, int growth) { avl64node_t *nnext; uint64_t start = AVL_START(tree, newnode); if (growth == AVL_BACK) { parent->avl_back = newnode; /* * we are growing to the left; previous in-order to newnode is * closest ancestor with lesser value. Before this * insertion, this ancestor will be pointing to * newnode's parent. After insertion, next in-order to newnode * is the parent. */ newnode->avl_nextino = parent; nnext = parent; while (nnext) { if (AVL_END(tree, nnext) <= start) break; nnext = nnext->avl_parent; } if (nnext) { /* * nnext will be null if newnode is * the least element, and hence very first in the list. */ ASSERT(nnext->avl_nextino == parent); nnext->avl_nextino = newnode; } } else { parent->avl_forw = newnode; newnode->avl_nextino = parent->avl_nextino; parent->avl_nextino = newnode; } } avl64node_t * avl64_insert( avl64tree_desc_t *tree, avl64node_t *newnode) { avl64node_t *np; uint64_t start = AVL_START(tree, newnode); uint64_t end = AVL_END(tree, newnode); int growth; ASSERT(newnode); /* * Clean all pointers for sanity; some will be reset as necessary. */ newnode->avl_nextino = NULL; newnode->avl_parent = NULL; newnode->avl_forw = NULL; newnode->avl_back = NULL; newnode->avl_balance = AVL_BALANCE; if ((np = tree->avl_root) == NULL) { /* degenerate case... */ tree->avl_root = newnode; tree->avl_firstino = newnode; return newnode; } if ((np = avl64_insert_find_growth(tree, start, end, &growth)) == NULL) { if (start != end) { /* non-zero length range */ fprintf(stderr, _("avl_insert: Warning! duplicate range [%llu,%llu]\n"), (unsigned long long)start, (unsigned long long)end); } return(NULL); } avl64_insert_grow(tree, np, newnode, growth); if (growth == AVL_BACK) { /* * Growing to left. if np was firstino, newnode will be firstino */ if (tree->avl_firstino == np) tree->avl_firstino = newnode; } #ifdef notneeded else if (growth == AVL_FORW) /* * Cannot possibly be firstino; there is somebody to our left. */ ; #endif newnode->avl_parent = np; CERT(np->avl_forw == newnode || np->avl_back == newnode); avl64_balance(&tree->avl_root, np, growth); avl64_checktree(tree, tree->avl_root); return newnode; } /* * * avl64_insert_immediate(tree, afterp, newnode): * insert newnode immediately into tree immediately after afterp. * after insertion, newnode is right child of afterp. */ void avl64_insert_immediate( avl64tree_desc_t *tree, avl64node_t *afterp, avl64node_t *newnode) { /* * Clean all pointers for sanity; some will be reset as necessary. */ newnode->avl_nextino = NULL; newnode->avl_parent = NULL; newnode->avl_forw = NULL; newnode->avl_back = NULL; newnode->avl_balance = AVL_BALANCE; if (afterp == NULL) { tree->avl_root = newnode; tree->avl_firstino = newnode; return; } ASSERT(afterp->avl_forw == NULL); avl64_insert_grow(tree, afterp, newnode, AVL_FORW); /* grow to right */ CERT(afterp->avl_forw == newnode); avl64_balance(&tree->avl_root, afterp, AVL_FORW); avl64_checktree(tree, tree->avl_root); } /* * Returns first in order node */ avl64node_t * avl64_firstino(avl64node_t *root) { avl64node_t *np; if ((np = root) == NULL) return NULL; while (np->avl_back) np = np->avl_back; return np; } /* * Returns last in order node */ avl64node_t * avl64_lastino(avl64node_t *root) { avl64node_t *np; if ((np = root) == NULL) return NULL; while (np->avl_forw) np = np->avl_forw; return np; } void avl64_init_tree(avl64tree_desc_t *tree, avl64ops_t *ops) { tree->avl_root = NULL; tree->avl_firstino = NULL; tree->avl_ops = ops; } #ifdef AVL_DEBUG static void avl64_printnode(avl64tree_desc_t *tree, avl64node_t *np, int nl) { printf("[%d-%d]%c", AVL_START(tree, np), (AVL_END(tree, np) - 1), nl ? '\n' : ' '); } #endif #ifdef STAND_ALONE_DEBUG struct avl_debug_node { avl64node_t avl_node; xfs_off_t avl_start; unsigned int avl_size; } avl64ops_t avl_debug_ops = { avl_debug_start, avl_debug_end, } static uint64_t avl64_debug_start(avl64node_t *node) { return (uint64_t)(struct avl_debug_node *)node->avl_start; } static uint64_t avl64_debug_end(avl64node_t *node) { return (uint64_t) ((struct avl_debug_node *)node->avl_start + (struct avl_debug_node *)node->avl_size); } avl_debug_node freenodes[100]; avl_debug_node *freehead = &freenodes[0]; static avl64node_t * alloc_avl64_debug_node() { freehead->avl_balance = AVL_BALANCE; freehead->avl_parent = freehead->avl_forw = freehead->avl_back = NULL; return(freehead++); } static void avl64_print(avl64tree_desc_t *tree, avl64node_t *root, int depth) { int i; if (!root) return; if (root->avl_forw) avl64_print(tree, root->avl_forw, depth+5); for (i = 0; i < depth; i++) putchar((int) ' '); avl64_printnode(tree, root,1); if (root->avl_back) avl64_print(tree, root->avl_back, depth+5); } main() { int i, j; avl64node_t *np; avl64tree_desc_t tree; char linebuf[256], cmd[256]; avl64_init_tree(&tree, &avl_debug_ops); for (i = 100; i > 0; i = i - 10) { np = alloc__debug_avlnode(); ASSERT(np); np->avl_start = i; np->avl_size = 10; avl64_insert(&tree, np); } avl64_print(&tree, tree.avl_root, 0); for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino) avl64_printnode(&tree, np, 0); printf("\n"); while (1) { printf(_("Command [fpdir] : ")); fgets(linebuf, 256, stdin); if (feof(stdin)) break; cmd[0] = NULL; if (sscanf(linebuf, "%[fpdir]%d", cmd, &i) != 2) continue; switch (cmd[0]) { case 'd': case 'f': printf(_("end of range ? ")); fgets(linebuf, 256, stdin); j = atoi(linebuf); if (i == j) j = i+1; np = avl64_findinrange(&tree,i,j); if (np) { avl64_printnode(&tree, np, 1); if (cmd[0] == 'd') avl64_delete(&tree, np); } else printf(_("Cannot find %d\n"), i); break; case 'p': avl64_print(&tree, tree.avl_root, 0); for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino) avl64_printnode(&tree, np, 0); printf("\n"); break; case 'i': np = alloc_avlnode(); ASSERT(np); np->avl_start = i; printf(_("size of range ? ")); fgets(linebuf, 256, stdin); j = atoi(linebuf); np->avl_size = j; avl64_insert(&tree, np); break; case 'r': { avl64node_t *b, *e, *t; int checklen; printf(_("End of range ? ")); fgets(linebuf, 256, stdin); j = atoi(linebuf); printf(_("checklen 0/1 ? ")); fgets(linebuf, 256, stdin); checklen = atoi(linebuf); b = avl64_findanyrange(&tree, i, j, checklen); if (b) { printf(_("Found something\n")); t = b; while (t) { if (t != b && AVL_START(&tree, t) >= j) break; avl64_printnode(&tree, t, 0); t = t->avl_nextino; } printf("\n"); } } } } } #endif /* * Given a tree, find value; will find return range enclosing value, * or range immediately succeeding value, * or range immediately preceeding value. */ avl64node_t * avl64_findadjacent( avl64tree_desc_t *tree, uint64_t value, int dir) { avl64node_t *np = tree->avl_root; while (np) { if (value < AVL_START(tree, np)) { if (np->avl_back) { np = np->avl_back; continue; } /* if we were to add node with value, would * have a growth of AVL_BACK */ if (dir == AVL_SUCCEED) { /* if succeeding node is needed, this is it. */ return(np); } if (dir == AVL_PRECEED) { /* * find nearest ancestor with lesser value. */ np = np->avl_parent; while (np) { if (AVL_END(tree, np) <= value) break; np = np->avl_parent; } return(np); } ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); break; } if (value >= AVL_END(tree, np)) { if (np->avl_forw) { np = np->avl_forw; continue; } /* if we were to add node with value, would * have a growth of AVL_FORW; */ if (dir == AVL_SUCCEED) { /* we are looking for a succeeding node; * this is nextino. */ return(np->avl_nextino); } if (dir == AVL_PRECEED) { /* looking for a preceeding node; this is it. */ return(np); } ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); } /* AVL_START(tree, np) <= value < AVL_END(tree, np) */ return(np); } return NULL; } /* * avl_findranges: * * Given range r [start, end), find all ranges in tree which are contained * in r. At return, startp and endp point to first and last of * a chain of elements which describe the contained ranges. Elements * in startp ... endp are in sort order, and can be accessed by * using avl_nextino. */ void avl64_findranges( avl64tree_desc_t *tree, uint64_t start, uint64_t end, avl64node_t **startp, avl64node_t **endp) { avl64node_t *np; np = avl64_findadjacent(tree, start, AVL_SUCCEED); if (np == NULL /* nothing succeding start */ || (np && (end <= AVL_START(tree, np)))) /* something follows start, but... is entirely after end */ { *startp = NULL; *endp = NULL; return; } *startp = np; /* see if end is in this region itself */ if (end <= AVL_END(tree, np) || np->avl_nextino == NULL || (np->avl_nextino && (end <= AVL_START(tree, np->avl_nextino)))) { *endp = np; return; } /* have to munge for end */ /* * note: have to look for (end - 1), since * findadjacent will look for exact value, and does not * care about the fact that end is actually one more * than the value actually being looked for; thus feed it one less. */ *endp = avl64_findadjacent(tree, (end-1), AVL_PRECEED); ASSERT(*endp); } xfsprogs-5.3.0/libfrog/avl64.h0000644000175000017500000000471013570057155016007 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_AVL64_H__ #define __LIBFROG_AVL64_H__ #include typedef struct avl64node { struct avl64node *avl_forw; /* pointer to right child (> parent) */ struct avl64node *avl_back; /* pointer to left child (< parent) */ struct avl64node *avl_parent; /* parent pointer */ struct avl64node *avl_nextino; /* next in-order; NULL terminated list*/ char avl_balance; /* tree balance */ } avl64node_t; /* * avl-tree operations */ typedef struct avl64ops { uint64_t (*avl_start)(avl64node_t *); uint64_t (*avl_end)(avl64node_t *); } avl64ops_t; /* * avoid complaints about multiple def's since these are only used by * the avl code internally */ #ifndef AVL_START #define AVL_START(tree, n) (*(tree)->avl_ops->avl_start)(n) #define AVL_END(tree, n) (*(tree)->avl_ops->avl_end)(n) #endif /* * tree descriptor: * root points to the root of the tree. * firstino points to the first in the ordered list. */ typedef struct avl64tree_desc { avl64node_t *avl_root; avl64node_t *avl_firstino; avl64ops_t *avl_ops; } avl64tree_desc_t; /* possible values for avl_balance */ #define AVL_BACK 1 #define AVL_BALANCE 0 #define AVL_FORW 2 /* * 'Exported' avl tree routines */ avl64node_t *avl64_insert( avl64tree_desc_t *tree, avl64node_t *newnode); void avl64_delete( avl64tree_desc_t *tree, avl64node_t *np); void avl64_insert_immediate( avl64tree_desc_t *tree, avl64node_t *afterp, avl64node_t *newnode); avl64node_t * avl64_firstino(avl64node_t *root); avl64node_t * avl64_lastino(avl64node_t *root); void avl64_init_tree( avl64tree_desc_t *tree, avl64ops_t *ops); avl64node_t * avl64_findrange( avl64tree_desc_t *tree, uint64_t value); avl64node_t * avl64_find( avl64tree_desc_t *tree, uint64_t value); avl64node_t * avl64_findanyrange( avl64tree_desc_t *tree, uint64_t start, uint64_t end, int checklen); avl64node_t * avl64_findadjacent( avl64tree_desc_t *tree, uint64_t value, int dir); void avl64_findranges( avl64tree_desc_t *tree, uint64_t start, uint64_t end, avl64node_t **startp, avl64node_t **endp); /* * avoid complaints about multiple def's since these are only used by * the avl code internally */ #ifndef AVL_PRECEED #define AVL_PRECEED 0x1 #define AVL_SUCCEED 0x2 #define AVL_INCLUDE_ZEROLEN 0x0000 #define AVL_EXCLUDE_ZEROLEN 0x0001 #endif #endif /* __LIBFROG_AVL64_H__ */ xfsprogs-5.3.0/libfrog/bitmap.c0000644000175000017500000002175513570057155016332 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "platform_defs.h" #include "avl64.h" #include "list.h" #include "bitmap.h" /* * Space Efficient Bitmap * * Implements a space-efficient bitmap. We use an AVL tree to manage * extent records that tell us which ranges are set; the bitmap key is * an arbitrary uint64_t. The usual bitmap operations (set, clear, * test, test and set) are supported, plus we can iterate set ranges. */ #define avl_for_each_range_safe(pos, n, l, first, last) \ for (pos = (first), n = pos->avl_nextino, l = (last)->avl_nextino; \ pos != (l); \ pos = n, n = pos ? pos->avl_nextino : NULL) #define avl_for_each_safe(tree, pos, n) \ for (pos = (tree)->avl_firstino, n = pos ? pos->avl_nextino : NULL; \ pos != NULL; \ pos = n, n = pos ? pos->avl_nextino : NULL) #define avl_for_each(tree, pos) \ for (pos = (tree)->avl_firstino; pos != NULL; pos = pos->avl_nextino) struct bitmap_node { struct avl64node btn_node; uint64_t btn_start; uint64_t btn_length; }; static uint64_t extent_start( struct avl64node *node) { struct bitmap_node *btn; btn = container_of(node, struct bitmap_node, btn_node); return btn->btn_start; } static uint64_t extent_end( struct avl64node *node) { struct bitmap_node *btn; btn = container_of(node, struct bitmap_node, btn_node); return btn->btn_start + btn->btn_length; } static struct avl64ops bitmap_ops = { extent_start, extent_end, }; /* Initialize a bitmap. */ int bitmap_alloc( struct bitmap **bmapp) { struct bitmap *bmap; int ret; bmap = calloc(1, sizeof(struct bitmap)); if (!bmap) return -errno; bmap->bt_tree = malloc(sizeof(struct avl64tree_desc)); if (!bmap->bt_tree) { ret = -errno; goto out; } ret = -pthread_mutex_init(&bmap->bt_lock, NULL); if (ret) goto out_tree; avl64_init_tree(bmap->bt_tree, &bitmap_ops); *bmapp = bmap; return 0; out_tree: free(bmap->bt_tree); out: free(bmap); return ret; } /* Free a bitmap. */ void bitmap_free( struct bitmap **bmapp) { struct bitmap *bmap; struct avl64node *node; struct avl64node *n; struct bitmap_node *ext; bmap = *bmapp; avl_for_each_safe(bmap->bt_tree, node, n) { ext = container_of(node, struct bitmap_node, btn_node); free(ext); } free(bmap->bt_tree); free(bmap); *bmapp = NULL; } /* Create a new bitmap extent node. */ static struct bitmap_node * bitmap_node_init( uint64_t start, uint64_t len) { struct bitmap_node *ext; ext = malloc(sizeof(struct bitmap_node)); if (!ext) return NULL; ext->btn_node.avl_nextino = NULL; ext->btn_start = start; ext->btn_length = len; return ext; } /* Create a new bitmap node and insert it. */ static inline int __bitmap_insert( struct bitmap *bmap, uint64_t start, uint64_t length) { struct bitmap_node *ext; struct avl64node *node; ext = bitmap_node_init(start, length); if (!ext) return -errno; node = avl64_insert(bmap->bt_tree, &ext->btn_node); if (node == NULL) { free(ext); return -EEXIST; } return 0; } /* Set a region of bits (locked). */ static int __bitmap_set( struct bitmap *bmap, uint64_t start, uint64_t length) { struct avl64node *firstn; struct avl64node *lastn; struct avl64node *pos; struct avl64node *n; struct avl64node *l; struct bitmap_node *ext; uint64_t new_start; uint64_t new_length; /* Find any existing nodes adjacent or within that range. */ avl64_findranges(bmap->bt_tree, start - 1, start + length + 1, &firstn, &lastn); /* Nothing, just insert a new extent. */ if (firstn == NULL && lastn == NULL) return __bitmap_insert(bmap, start, length); assert(firstn != NULL && lastn != NULL); new_start = start; new_length = length; avl_for_each_range_safe(pos, n, l, firstn, lastn) { ext = container_of(pos, struct bitmap_node, btn_node); /* Bail if the new extent is contained within an old one. */ if (ext->btn_start <= start && ext->btn_start + ext->btn_length >= start + length) return 0; /* Check for overlapping and adjacent extents. */ if (ext->btn_start + ext->btn_length >= start || ext->btn_start <= start + length) { if (ext->btn_start < start) { new_start = ext->btn_start; new_length += ext->btn_length; } if (ext->btn_start + ext->btn_length > new_start + new_length) new_length = ext->btn_start + ext->btn_length - new_start; avl64_delete(bmap->bt_tree, pos); free(ext); } } return __bitmap_insert(bmap, new_start, new_length); } /* Set a region of bits. */ int bitmap_set( struct bitmap *bmap, uint64_t start, uint64_t length) { int res; pthread_mutex_lock(&bmap->bt_lock); res = __bitmap_set(bmap, start, length); pthread_mutex_unlock(&bmap->bt_lock); return res; } #if 0 /* Unused, provided for completeness. */ /* Clear a region of bits. */ int bitmap_clear( struct bitmap *bmap, uint64_t start, uint64_t len) { struct avl64node *firstn; struct avl64node *lastn; struct avl64node *pos; struct avl64node *n; struct avl64node *l; struct bitmap_node *ext; uint64_t new_start; uint64_t new_length; struct avl64node *node; int stat; pthread_mutex_lock(&bmap->bt_lock); /* Find any existing nodes over that range. */ avl64_findranges(bmap->bt_tree, start, start + len, &firstn, &lastn); /* Nothing, we're done. */ if (firstn == NULL && lastn == NULL) { pthread_mutex_unlock(&bmap->bt_lock); return 0; } assert(firstn != NULL && lastn != NULL); /* Delete or truncate everything in sight. */ avl_for_each_range_safe(pos, n, l, firstn, lastn) { ext = container_of(pos, struct bitmap_node, btn_node); stat = 0; if (ext->btn_start < start) stat |= 1; if (ext->btn_start + ext->btn_length > start + len) stat |= 2; switch (stat) { case 0: /* Extent totally within range; delete. */ avl64_delete(bmap->bt_tree, pos); free(ext); break; case 1: /* Extent is left-adjacent; truncate. */ ext->btn_length = start - ext->btn_start; break; case 2: /* Extent is right-adjacent; move it. */ ext->btn_length = ext->btn_start + ext->btn_length - (start + len); ext->btn_start = start + len; break; case 3: /* Extent overlaps both ends. */ ext->btn_length = start - ext->btn_start; new_start = start + len; new_length = ext->btn_start + ext->btn_length - new_start; ext = bitmap_node_init(new_start, new_length); if (!ext) { ret = -errno; goto out; } node = avl64_insert(bmap->bt_tree, &ext->btn_node); if (node == NULL) { ret = -EEXIST; goto out; } break; } } out: pthread_mutex_unlock(&bmap->bt_lock); return ret; } #endif /* Iterate the set regions of this bitmap. */ int bitmap_iterate( struct bitmap *bmap, int (*fn)(uint64_t, uint64_t, void *), void *arg) { struct avl64node *node; struct bitmap_node *ext; int error = 0; pthread_mutex_lock(&bmap->bt_lock); avl_for_each(bmap->bt_tree, node) { ext = container_of(node, struct bitmap_node, btn_node); error = fn(ext->btn_start, ext->btn_length, arg); if (error) break; } pthread_mutex_unlock(&bmap->bt_lock); return error; } /* Iterate the set regions of part of this bitmap. */ int bitmap_iterate_range( struct bitmap *bmap, uint64_t start, uint64_t length, int (*fn)(uint64_t, uint64_t, void *), void *arg) { struct avl64node *firstn; struct avl64node *lastn; struct avl64node *pos; struct avl64node *n; struct avl64node *l; struct bitmap_node *ext; int ret = 0; pthread_mutex_lock(&bmap->bt_lock); avl64_findranges(bmap->bt_tree, start, start + length, &firstn, &lastn); if (firstn == NULL && lastn == NULL) goto out; avl_for_each_range_safe(pos, n, l, firstn, lastn) { ext = container_of(pos, struct bitmap_node, btn_node); ret = fn(ext->btn_start, ext->btn_length, arg); if (ret) break; } out: pthread_mutex_unlock(&bmap->bt_lock); return ret; } /* Do any bitmap extents overlap the given one? (locked) */ static bool __bitmap_test( struct bitmap *bmap, uint64_t start, uint64_t len) { struct avl64node *firstn; struct avl64node *lastn; /* Find any existing nodes over that range. */ avl64_findranges(bmap->bt_tree, start, start + len, &firstn, &lastn); return firstn != NULL && lastn != NULL; } /* Is any part of this range set? */ bool bitmap_test( struct bitmap *bmap, uint64_t start, uint64_t len) { bool res; pthread_mutex_lock(&bmap->bt_lock); res = __bitmap_test(bmap, start, len); pthread_mutex_unlock(&bmap->bt_lock); return res; } /* Are none of the bits set? */ bool bitmap_empty( struct bitmap *bmap) { return bmap->bt_tree->avl_firstino == NULL; } #ifdef DEBUG static int bitmap_dump_fn( uint64_t startblock, uint64_t blockcount, void *arg) { printf("%"PRIu64":%"PRIu64"\n", startblock, blockcount); return 0; } /* Dump bitmap. */ void bitmap_dump( struct bitmap *bmap) { printf("BITMAP DUMP %p\n", bmap); bitmap_iterate(bmap, bitmap_dump_fn, NULL); printf("BITMAP DUMP DONE\n"); } #endif xfsprogs-5.3.0/libfrog/bitmap.h0000644000175000017500000000152013570057155016323 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __LIBFROG_BITMAP_H__ #define __LIBFROG_BITMAP_H__ struct bitmap { pthread_mutex_t bt_lock; struct avl64tree_desc *bt_tree; }; int bitmap_alloc(struct bitmap **bmap); void bitmap_free(struct bitmap **bmap); int bitmap_set(struct bitmap *bmap, uint64_t start, uint64_t length); int bitmap_iterate(struct bitmap *bmap, int (*fn)(uint64_t, uint64_t, void *), void *arg); int bitmap_iterate_range(struct bitmap *bmap, uint64_t start, uint64_t length, int (*fn)(uint64_t, uint64_t, void *), void *arg); bool bitmap_test(struct bitmap *bmap, uint64_t start, uint64_t len); bool bitmap_empty(struct bitmap *bmap); void bitmap_dump(struct bitmap *bmap); #endif /* __LIBFROG_BITMAP_H__ */ xfsprogs-5.3.0/libfrog/bulkstat.c0000644000175000017500000003302713570057155016702 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include #include "xfs.h" #include "fsgeom.h" #include "bulkstat.h" /* * Wrapper functions for BULKSTAT and INUMBERS * =========================================== * * The functions in this file are thin wrappers around the most recent version * of the BULKSTAT and INUMBERS ioctls. BULKSTAT is used to query XFS-specific * stat information about a group of inodes. INUMBERS is used to query * allocation information about batches of XFS inodes. * * At the moment, the public xfrog_* functions provide all functionality of the * V5 interface. If the V5 interface is not available on the running kernel, * the functions will emulate them as best they can with previous versions of * the interface (currently V1). If emulation is not possible, EINVAL will be * returned. * * The XFROG_FLAG_BULKSTAT_FORCE_V[15] flags can be used to force use of a * particular version of the kernel interface for testing. */ /* * Grab the fs geometry information that is needed to needed to emulate v5 with * v1 interfaces. */ static inline int xfrog_bulkstat_prep_v1_emulation( struct xfs_fd *xfd) { if (xfd->fsgeom.blocksize > 0) return 0; return xfd_prepare_geometry(xfd); } /* Bulkstat a single inode using v5 ioctl. */ static int xfrog_bulkstat_single5( struct xfs_fd *xfd, uint64_t ino, unsigned int flags, struct xfs_bulkstat *bulkstat) { struct xfs_bulkstat_req *req; int ret; if (flags & ~(XFS_BULK_IREQ_SPECIAL)) return -EINVAL; ret = xfrog_bulkstat_alloc_req(1, ino, &req); if (ret) return ret; req->hdr.flags = flags; ret = ioctl(xfd->fd, XFS_IOC_BULKSTAT, req); if (ret) { ret = -errno; goto free; } if (req->hdr.ocount == 0) { ret = -ENOENT; goto free; } memcpy(bulkstat, req->bulkstat, sizeof(struct xfs_bulkstat)); free: free(req); return ret; } /* Bulkstat a single inode using v1 ioctl. */ static int xfrog_bulkstat_single1( struct xfs_fd *xfd, uint64_t ino, unsigned int flags, struct xfs_bulkstat *bulkstat) { struct xfs_bstat bstat; struct xfs_fsop_bulkreq bulkreq = { 0 }; int error; if (flags) return -EINVAL; error = xfrog_bulkstat_prep_v1_emulation(xfd); if (error) return error; bulkreq.lastip = (__u64 *)&ino; bulkreq.icount = 1; bulkreq.ubuffer = &bstat; error = ioctl(xfd->fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq); if (error) return -errno; xfrog_bulkstat_v1_to_v5(xfd, bulkstat, &bstat); return 0; } /* Bulkstat a single inode. Returns zero or a negative error code. */ int xfrog_bulkstat_single( struct xfs_fd *xfd, uint64_t ino, unsigned int flags, struct xfs_bulkstat *bulkstat) { int error; if (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V1) goto try_v1; error = xfrog_bulkstat_single5(xfd, ino, flags, bulkstat); if (error == 0 || (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V5)) return error; /* If the v5 ioctl wasn't found, we punt to v1. */ switch (error) { case -EOPNOTSUPP: case -ENOTTY: xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V1; break; } try_v1: return xfrog_bulkstat_single1(xfd, ino, flags, bulkstat); } /* * Set up the necessary control structures to emulate a V5 bulk request ioctl * by calling a V1 bulk request ioctl. This enables callers to run on older * kernels. * * Returns 0 if the emulation should proceed; ECANCELED if there are no * records; or a negative error code. */ static int xfrog_bulk_req_v1_setup( struct xfs_fd *xfd, struct xfs_bulk_ireq *hdr, struct xfs_fsop_bulkreq *bulkreq, size_t rec_size) { void *buf; if (hdr->flags & XFS_BULK_IREQ_AGNO) { uint32_t agno = cvt_ino_to_agno(xfd, hdr->ino); if (hdr->ino == 0) hdr->ino = cvt_agino_to_ino(xfd, hdr->agno, 0); else if (agno < hdr->agno) return -EINVAL; else if (agno > hdr->agno) goto no_results; } if (cvt_ino_to_agno(xfd, hdr->ino) > xfd->fsgeom.agcount) goto no_results; buf = malloc(hdr->icount * rec_size); if (!buf) return -errno; if (hdr->ino) hdr->ino--; bulkreq->lastip = (__u64 *)&hdr->ino, bulkreq->icount = hdr->icount, bulkreq->ocount = (__s32 *)&hdr->ocount, bulkreq->ubuffer = buf; return 0; no_results: hdr->ocount = 0; return -ECANCELED; } /* * Clean up after using a V1 bulk request to emulate a V5 bulk request call. * * If the ioctl was successful, we need to convert the returned V1-format bulk * request data into the V5-format bulk request data and copy it into the * caller's buffer. We also need to free all resources allocated during the * setup setup. */ static int xfrog_bulk_req_v1_cleanup( struct xfs_fd *xfd, struct xfs_bulk_ireq *hdr, struct xfs_fsop_bulkreq *bulkreq, size_t v1_rec_size, uint64_t (*v1_ino)(void *v1_rec), void *v5_records, size_t v5_rec_size, void (*cvt)(struct xfs_fd *xfd, void *v5, void *v1), unsigned int startino_adj, int error) { void *v1_rec = bulkreq->ubuffer; void *v5_rec = v5_records; unsigned int i; if (error == -ECANCELED) { error = 0; goto free; } if (error) goto free; /* * Convert each record from v1 to v5 format, keeping the startino * value up to date and (if desired) stopping at the end of the * AG. */ for (i = 0; i < hdr->ocount; i++, v1_rec += v1_rec_size, v5_rec += v5_rec_size) { uint64_t ino = v1_ino(v1_rec); /* Stop if we hit a different AG. */ if ((hdr->flags & XFS_BULK_IREQ_AGNO) && cvt_ino_to_agno(xfd, ino) != hdr->agno) { hdr->ocount = i; break; } cvt(xfd, v5_rec, v1_rec); hdr->ino = ino + startino_adj; } free: free(bulkreq->ubuffer); return error; } static uint64_t xfrog_bstat_ino(void *v1_rec) { return ((struct xfs_bstat *)v1_rec)->bs_ino; } static void xfrog_bstat_cvt(struct xfs_fd *xfd, void *v5, void *v1) { xfrog_bulkstat_v1_to_v5(xfd, v5, v1); } /* Bulkstat a bunch of inodes using the v5 interface. */ static int xfrog_bulkstat5( struct xfs_fd *xfd, struct xfs_bulkstat_req *req) { int ret; ret = ioctl(xfd->fd, XFS_IOC_BULKSTAT, req); if (ret) return -errno; return 0; } /* Bulkstat a bunch of inodes using the v1 interface. */ static int xfrog_bulkstat1( struct xfs_fd *xfd, struct xfs_bulkstat_req *req) { struct xfs_fsop_bulkreq bulkreq = { 0 }; int error; error = xfrog_bulkstat_prep_v1_emulation(xfd); if (error) return error; error = xfrog_bulk_req_v1_setup(xfd, &req->hdr, &bulkreq, sizeof(struct xfs_bstat)); if (error == -ECANCELED) goto out_teardown; if (error) return error; error = ioctl(xfd->fd, XFS_IOC_FSBULKSTAT, &bulkreq); if (error) error = -errno; out_teardown: return xfrog_bulk_req_v1_cleanup(xfd, &req->hdr, &bulkreq, sizeof(struct xfs_bstat), xfrog_bstat_ino, &req->bulkstat, sizeof(struct xfs_bulkstat), xfrog_bstat_cvt, 1, error); } /* Bulkstat a bunch of inodes. Returns zero or a positive error code. */ int xfrog_bulkstat( struct xfs_fd *xfd, struct xfs_bulkstat_req *req) { int error; if (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V1) goto try_v1; error = xfrog_bulkstat5(xfd, req); if (error == 0 || (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V5)) return error; /* If the v5 ioctl wasn't found, we punt to v1. */ switch (error) { case -EOPNOTSUPP: case -ENOTTY: xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V1; break; } try_v1: return xfrog_bulkstat1(xfd, req); } static bool time_too_big( uint64_t time) { time_t TIME_MAX; memset(&TIME_MAX, 0xFF, sizeof(TIME_MAX)); return time > TIME_MAX; } /* Convert bulkstat data from v5 format to v1 format. */ int xfrog_bulkstat_v5_to_v1( struct xfs_fd *xfd, struct xfs_bstat *bs1, const struct xfs_bulkstat *bs5) { if (bs5->bs_aextents > UINT16_MAX || cvt_off_fsb_to_b(xfd, bs5->bs_extsize_blks) > UINT32_MAX || cvt_off_fsb_to_b(xfd, bs5->bs_cowextsize_blks) > UINT32_MAX || time_too_big(bs5->bs_atime) || time_too_big(bs5->bs_ctime) || time_too_big(bs5->bs_mtime)) return -ERANGE; bs1->bs_ino = bs5->bs_ino; bs1->bs_mode = bs5->bs_mode; bs1->bs_nlink = bs5->bs_nlink; bs1->bs_uid = bs5->bs_uid; bs1->bs_gid = bs5->bs_gid; bs1->bs_rdev = bs5->bs_rdev; bs1->bs_blksize = bs5->bs_blksize; bs1->bs_size = bs5->bs_size; bs1->bs_atime.tv_sec = bs5->bs_atime; bs1->bs_mtime.tv_sec = bs5->bs_mtime; bs1->bs_ctime.tv_sec = bs5->bs_ctime; bs1->bs_atime.tv_nsec = bs5->bs_atime_nsec; bs1->bs_mtime.tv_nsec = bs5->bs_mtime_nsec; bs1->bs_ctime.tv_nsec = bs5->bs_ctime_nsec; bs1->bs_blocks = bs5->bs_blocks; bs1->bs_xflags = bs5->bs_xflags; bs1->bs_extsize = cvt_off_fsb_to_b(xfd, bs5->bs_extsize_blks); bs1->bs_extents = bs5->bs_extents; bs1->bs_gen = bs5->bs_gen; bs1->bs_projid_lo = bs5->bs_projectid & 0xFFFF; bs1->bs_forkoff = bs5->bs_forkoff; bs1->bs_projid_hi = bs5->bs_projectid >> 16; bs1->bs_sick = bs5->bs_sick; bs1->bs_checked = bs5->bs_checked; bs1->bs_cowextsize = cvt_off_fsb_to_b(xfd, bs5->bs_cowextsize_blks); bs1->bs_dmevmask = 0; bs1->bs_dmstate = 0; bs1->bs_aextents = bs5->bs_aextents; return 0; } /* Convert bulkstat data from v1 format to v5 format. */ void xfrog_bulkstat_v1_to_v5( struct xfs_fd *xfd, struct xfs_bulkstat *bs5, const struct xfs_bstat *bs1) { memset(bs5, 0, sizeof(*bs5)); bs5->bs_version = XFS_BULKSTAT_VERSION_V1; bs5->bs_ino = bs1->bs_ino; bs5->bs_mode = bs1->bs_mode; bs5->bs_nlink = bs1->bs_nlink; bs5->bs_uid = bs1->bs_uid; bs5->bs_gid = bs1->bs_gid; bs5->bs_rdev = bs1->bs_rdev; bs5->bs_blksize = bs1->bs_blksize; bs5->bs_size = bs1->bs_size; bs5->bs_atime = bs1->bs_atime.tv_sec; bs5->bs_mtime = bs1->bs_mtime.tv_sec; bs5->bs_ctime = bs1->bs_ctime.tv_sec; bs5->bs_atime_nsec = bs1->bs_atime.tv_nsec; bs5->bs_mtime_nsec = bs1->bs_mtime.tv_nsec; bs5->bs_ctime_nsec = bs1->bs_ctime.tv_nsec; bs5->bs_blocks = bs1->bs_blocks; bs5->bs_xflags = bs1->bs_xflags; bs5->bs_extsize_blks = cvt_b_to_off_fsbt(xfd, bs1->bs_extsize); bs5->bs_extents = bs1->bs_extents; bs5->bs_gen = bs1->bs_gen; bs5->bs_projectid = bstat_get_projid(bs1); bs5->bs_forkoff = bs1->bs_forkoff; bs5->bs_sick = bs1->bs_sick; bs5->bs_checked = bs1->bs_checked; bs5->bs_cowextsize_blks = cvt_b_to_off_fsbt(xfd, bs1->bs_cowextsize); bs5->bs_aextents = bs1->bs_aextents; } /* Allocate a bulkstat request. Returns zero or a negative error code. */ int xfrog_bulkstat_alloc_req( uint32_t nr, uint64_t startino, struct xfs_bulkstat_req **preq) { struct xfs_bulkstat_req *breq; breq = calloc(1, XFS_BULKSTAT_REQ_SIZE(nr)); if (!breq) return -errno; breq->hdr.icount = nr; breq->hdr.ino = startino; *preq = breq; return 0; } /* Set a bulkstat cursor to iterate only a particular AG. */ void xfrog_bulkstat_set_ag( struct xfs_bulkstat_req *req, uint32_t agno) { req->hdr.agno = agno; req->hdr.flags |= XFS_BULK_IREQ_AGNO; } /* Convert a inumbers data from v5 format to v1 format. */ void xfrog_inumbers_v5_to_v1( struct xfs_inogrp *ig1, const struct xfs_inumbers *ig5) { ig1->xi_startino = ig5->xi_startino; ig1->xi_alloccount = ig5->xi_alloccount; ig1->xi_allocmask = ig5->xi_allocmask; } /* Convert a inumbers data from v1 format to v5 format. */ void xfrog_inumbers_v1_to_v5( struct xfs_inumbers *ig5, const struct xfs_inogrp *ig1) { memset(ig5, 0, sizeof(*ig5)); ig5->xi_version = XFS_INUMBERS_VERSION_V1; ig5->xi_startino = ig1->xi_startino; ig5->xi_alloccount = ig1->xi_alloccount; ig5->xi_allocmask = ig1->xi_allocmask; } static uint64_t xfrog_inum_ino(void *v1_rec) { return ((struct xfs_inogrp *)v1_rec)->xi_startino; } static void xfrog_inum_cvt(struct xfs_fd *xfd, void *v5, void *v1) { xfrog_inumbers_v1_to_v5(v5, v1); } /* Query inode allocation bitmask information using v5 ioctl. */ static int xfrog_inumbers5( struct xfs_fd *xfd, struct xfs_inumbers_req *req) { int ret; ret = ioctl(xfd->fd, XFS_IOC_INUMBERS, req); if (ret) return -errno; return 0; } /* Query inode allocation bitmask information using v1 ioctl. */ static int xfrog_inumbers1( struct xfs_fd *xfd, struct xfs_inumbers_req *req) { struct xfs_fsop_bulkreq bulkreq = { 0 }; int error; error = xfrog_bulkstat_prep_v1_emulation(xfd); if (error) return error; error = xfrog_bulk_req_v1_setup(xfd, &req->hdr, &bulkreq, sizeof(struct xfs_inogrp)); if (error == -ECANCELED) goto out_teardown; if (error) return error; error = ioctl(xfd->fd, XFS_IOC_FSINUMBERS, &bulkreq); if (error) error = -errno; out_teardown: return xfrog_bulk_req_v1_cleanup(xfd, &req->hdr, &bulkreq, sizeof(struct xfs_inogrp), xfrog_inum_ino, &req->inumbers, sizeof(struct xfs_inumbers), xfrog_inum_cvt, 64, error); } /* * Query inode allocation bitmask information. Returns zero or a negative * error code. */ int xfrog_inumbers( struct xfs_fd *xfd, struct xfs_inumbers_req *req) { int error; if (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V1) goto try_v1; error = xfrog_inumbers5(xfd, req); if (error == 0 || (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V5)) return error; /* If the v5 ioctl wasn't found, we punt to v1. */ switch (error) { case -EOPNOTSUPP: case -ENOTTY: xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V1; break; } try_v1: return xfrog_inumbers1(xfd, req); } /* Allocate a inumbers request. Returns zero or a negative error code. */ int xfrog_inumbers_alloc_req( uint32_t nr, uint64_t startino, struct xfs_inumbers_req **preq) { struct xfs_inumbers_req *ireq; ireq = calloc(1, XFS_INUMBERS_REQ_SIZE(nr)); if (!ireq) return -errno; ireq->hdr.icount = nr; ireq->hdr.ino = startino; *preq = ireq; return 0; } /* Set an inumbers cursor to iterate only a particular AG. */ void xfrog_inumbers_set_ag( struct xfs_inumbers_req *req, uint32_t agno) { req->hdr.agno = agno; req->hdr.flags |= XFS_BULK_IREQ_AGNO; } xfsprogs-5.3.0/libfrog/bulkstat.h0000644000175000017500000000235613570057155016710 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2019 Oracle, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_BULKSTAT_H__ #define __LIBFROG_BULKSTAT_H__ /* Bulkstat wrappers */ struct xfs_bstat; int xfrog_bulkstat_single(struct xfs_fd *xfd, uint64_t ino, unsigned int flags, struct xfs_bulkstat *bulkstat); int xfrog_bulkstat(struct xfs_fd *xfd, struct xfs_bulkstat_req *req); int xfrog_bulkstat_alloc_req(uint32_t nr, uint64_t startino, struct xfs_bulkstat_req **preq); int xfrog_bulkstat_v5_to_v1(struct xfs_fd *xfd, struct xfs_bstat *bs1, const struct xfs_bulkstat *bstat); void xfrog_bulkstat_v1_to_v5(struct xfs_fd *xfd, struct xfs_bulkstat *bstat, const struct xfs_bstat *bs1); void xfrog_bulkstat_set_ag(struct xfs_bulkstat_req *req, uint32_t agno); struct xfs_inogrp; int xfrog_inumbers(struct xfs_fd *xfd, struct xfs_inumbers_req *req); int xfrog_inumbers_alloc_req(uint32_t nr, uint64_t startino, struct xfs_inumbers_req **preq); void xfrog_inumbers_set_ag(struct xfs_inumbers_req *req, uint32_t agno); void xfrog_inumbers_v5_to_v1(struct xfs_inogrp *ig1, const struct xfs_inumbers *ig); void xfrog_inumbers_v1_to_v5(struct xfs_inumbers *ig, const struct xfs_inogrp *ig1); #endif /* __LIBFROG_BULKSTAT_H__ */ xfsprogs-5.3.0/libfrog/convert.c0000644000175000017500000001743413570057155016535 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "input.h" #include #include size_t numlen( uint64_t val, size_t base) { uint64_t tmp; size_t len; for (len = 0, tmp = val; tmp > 0; tmp = tmp / base) len++; return len == 0 ? 1 : len; } /* * Convert string to int64_t, set errno if the conversion fails or * doesn't fit. Does not allow unit specifiers. Sets errno to zero * prior to conversion so you can check for bad inputs by examining * errno immediately after the call. */ int64_t cvt_s64( char *s, int base) { long long i; char *sp; errno = 0; i = strtoll(s, &sp, base); /* * If the input would over or underflow, return the clamped * value and let the user check errno. If we went all the * way to the end of the input, return the converted value; * errno will be zero. */ if (errno || (*sp == '\0' && sp != s)) return i; /* Not all the input was consumed, return error. */ errno = ERANGE; return INT64_MIN; } /* * Convert string to int32_t, set errno if the conversion fails or * doesn't fit. Does not allow unit specifiers. Sets errno to zero * prior to conversion so you can check for bad inputs by examining * errno immediately after the call. */ int32_t cvt_s32( char *s, int base) { int64_t i; i = cvt_s64(s, base); if (errno) return i; if (i > INT32_MAX || i < INT32_MIN) { errno = ERANGE; return INT32_MIN; } return i; } /* * Convert string to int16_t, set errno if the conversion fails or * doesn't fit. Does not allow unit specifiers. Sets errno to zero * prior to conversion so you can check for bad inputs by examining * errno immediately after the call. */ int16_t cvt_s16( char *s, int base) { int64_t i; i = cvt_s64(s, base); if (errno) return i; if (i > INT16_MAX || i < INT16_MIN) { errno = ERANGE; return INT16_MIN; } return i; } /* * Convert string to uint64_t, set errno if the conversion fails or * doesn't fit. Does not allow unit specifiers. Sets errno to zero * prior to conversion so you can check for bad inputs by examining * errno immediately after the call. */ uint64_t cvt_u64( char *s, int base) { unsigned long long i; char *sp; errno = 0; i = strtoull(s, &sp, base); /* * If the input would over or underflow, return the clamped * value and let the user check errno. If we went all the * way to the end of the input, return the converted value; * errno will be zero. */ if (errno || (*sp == '\0' && sp != s)) return i; /* Not all the input was consumed, return error. */ errno = ERANGE; return UINT64_MAX; } /* * Convert string to uint32_t, set errno if the conversion fails or * doesn't fit. Does not allow unit specifiers. Sets errno to zero * prior to conversion so you can check for bad inputs by examining * errno immediately after the call. */ uint32_t cvt_u32( char *s, int base) { uint64_t i; i = cvt_u64(s, base); if (errno) return i; if (i > UINT32_MAX) { errno = ERANGE; return UINT32_MAX; } return i; } /* * Convert string to uint16_t, set errno if the conversion fails or * doesn't fit. Does not allow unit specifiers. Sets errno to zero * prior to conversion so you can check for bad inputs by examining * errno immediately after the call. */ uint16_t cvt_u16( char *s, int base) { uint64_t i; i = cvt_u64(s, base); if (errno) return i; if (i > UINT16_MAX) { errno = ERANGE; return UINT16_MAX; } return i; } #define EXABYTES(x) ((long long)(x) << 60) #define PETABYTES(x) ((long long)(x) << 50) #define TERABYTES(x) ((long long)(x) << 40) #define GIGABYTES(x) ((long long)(x) << 30) #define MEGABYTES(x) ((long long)(x) << 20) #define KILOBYTES(x) ((long long)(x) << 10) long long cvtnum( size_t blocksize, size_t sectorsize, char *s) { long long i; char *sp; int c; i = strtoll(s, &sp, 0); if (i == 0 && sp == s) return -1LL; if (*sp == '\0') return i; if (sp[1] != '\0') return -1LL; c = tolower(*sp); switch (c) { case 'b': return i * blocksize; case 's': return i * sectorsize; case 'k': return KILOBYTES(i); case 'm': return MEGABYTES(i); case 'g': return GIGABYTES(i); case 't': return TERABYTES(i); case 'p': return PETABYTES(i); case 'e': return EXABYTES(i); } return -1LL; } #define TO_EXABYTES(x) ((x) / EXABYTES(1)) #define TO_PETABYTES(x) ((x) / PETABYTES(1)) #define TO_TERABYTES(x) ((x) / TERABYTES(1)) #define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) #define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) #define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) void cvtstr( double value, char *str, size_t size) { char *fmt; int precise; precise = ((double)value * 1000 == (double)(int)value * 1000); if (value >= EXABYTES(1)) { fmt = precise ? "%.f EiB" : "%.3f EiB"; snprintf(str, size, fmt, TO_EXABYTES(value)); } else if (value >= PETABYTES(1)) { fmt = precise ? "%.f PiB" : "%.3f PiB"; snprintf(str, size, fmt, TO_PETABYTES(value)); } else if (value >= TERABYTES(1)) { fmt = precise ? "%.f TiB" : "%.3f TiB"; snprintf(str, size, fmt, TO_TERABYTES(value)); } else if (value >= GIGABYTES(1)) { fmt = precise ? "%.f GiB" : "%.3f GiB"; snprintf(str, size, fmt, TO_GIGABYTES(value)); } else if (value >= MEGABYTES(1)) { fmt = precise ? "%.f MiB" : "%.3f MiB"; snprintf(str, size, fmt, TO_MEGABYTES(value)); } else if (value >= KILOBYTES(1)) { fmt = precise ? "%.f KiB" : "%.3f KiB"; snprintf(str, size, fmt, TO_KILOBYTES(value)); } else { snprintf(str, size, "%f bytes", value); } } #define MINUTES_TO_SECONDS(m) ((m) * 60) #define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60)) #define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24)) #define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7)) unsigned long cvttime( char *s) { unsigned long i; char *sp; i = strtoul(s, &sp, 0); if (i == 0 && sp == s) return 0; if (*sp == '\0') return i; if ((*sp == 'm' && sp[1] == '\0') || (strcmp(sp, "minutes") == 0) || (strcmp(sp, "minute") == 0)) return MINUTES_TO_SECONDS(i); if ((*sp == 'h' && sp[1] == '\0') || (strcmp(sp, "hours") == 0) || (strcmp(sp, "hour") == 0)) return HOURS_TO_SECONDS(i); if ((*sp == 'd' && sp[1] == '\0') || (strcmp(sp, "days") == 0) || (strcmp(sp, "day") == 0)) return DAYS_TO_SECONDS(i); if ((*sp == 'w' && sp[1] == '\0') || (strcmp(sp, "weeks") == 0) || (strcmp(sp, "week") == 0)) return WEEKS_TO_SECONDS(i); return 0; } /* * Convert from arbitrary user strings into a numeric ID. * If it's all numeric, we convert that inplace, else we do * the name lookup, and return the found identifier. */ prid_t prid_from_string( char *project) { fs_project_t *prj; unsigned long prid_long; char *sp; /* * Allow either a full numeric or a valid projectname, even * if it starts with a digit. */ prid_long = strtoul(project, &sp, 10); if (*project != '\0' && *sp == '\0') { if ((prid_long == ULONG_MAX && errno == ERANGE) || (prid_long > (prid_t)-1)) return -1; return (prid_t)prid_long; } prj = getprnam(project); if (prj) return prj->pr_prid; return -1; } uid_t uid_from_string( char *user) { struct passwd *pwd; unsigned long uid_long; char *sp; uid_long = strtoul(user, &sp, 10); if (sp != user && *sp == '\0') { if ((uid_long == ULONG_MAX && errno == ERANGE) || (uid_long > (uid_t)-1)) return -1; return (uid_t)uid_long; } pwd = getpwnam(user); if (pwd) return pwd->pw_uid; return -1; } gid_t gid_from_string( char *group) { struct group *grp; unsigned long gid_long; char *sp; gid_long = strtoul(group, &sp, 10); if (sp != group && *sp == '\0') { if ((gid_long == ULONG_MAX && errno == ERANGE) || (gid_long > (gid_t)-1)) return -1; return (gid_t)gid_long; } grp = getgrnam(group); if (grp) return grp->gr_gid; return -1; } xfsprogs-5.3.0/libfrog/convert.h0000644000175000017500000000141013570057155016525 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_CONVERT_H__ #define __LIBFROG_CONVERT_H__ extern int64_t cvt_s64(char *s, int base); extern int32_t cvt_s32(char *s, int base); extern int16_t cvt_s16(char *s, int base); extern uint64_t cvt_u64(char *s, int base); extern uint32_t cvt_u32(char *s, int base); extern uint16_t cvt_u16(char *s, int base); extern long long cvtnum(size_t blocksize, size_t sectorsize, char *s); extern void cvtstr(double value, char *str, size_t sz); extern unsigned long cvttime(char *s); extern uid_t uid_from_string(char *user); extern gid_t gid_from_string(char *group); extern prid_t prid_from_string(char *project); #endif /* __LIBFROG_CONVERT_H__ */ xfsprogs-5.3.0/libfrog/crc32.c0000644000175000017500000001277413435336036015771 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Aug 8, 2011 Bob Pearson with help from Joakim Tjernlund and George Spelvin * cleaned up code to current version of sparse and added the slicing-by-8 * algorithm to the closely similar existing slicing-by-4 algorithm. * Oct 15, 2000 Matt Domsch * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks! * Code was from the public domain, copyright abandoned. Code was * subsequently included in the kernel, thus was re-licensed under the * GNU GPL v2. * Oct 12, 2000 Matt Domsch * Same crc32 function was used in 5 other places in the kernel. * I made one version, and deleted the others. * There are various incantations of crc32(). Some use a seed of 0 or ~0. * Some xor at the end with ~0. The generic crc32() function takes * seed as an argument, and doesn't xor at the end. Then individual * users can do whatever they need. * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0. * fs/jffs2 uses seed 0, doesn't xor with ~0. * fs/partitions/efi.c uses seed ~0, xor's with ~0. */ /* see: Documentation/crc32.txt for a description of algorithms */ /* * lifted from the 3.8-rc2 kernel source for xfsprogs. Killed CONFIG_X86 * specific bits for just the generic algorithm. Also removed the big endian * version of the algorithm as XFS only uses the little endian CRC version to * match the hardware acceleration available on Intel CPUs. */ #include #include #include #include "platform_defs.h" /* For endian conversion routines */ #include "xfs_arch.h" #include "crc32defs.h" #include "crc32c.h" /* types specifc to this file */ typedef __u8 u8; typedef __u16 u16; typedef __u32 u32; typedef __u32 u64; #define __pure #if CRC_LE_BITS > 8 # define tole(x) ((__force u32) __constant_cpu_to_le32(x)) #else # define tole(x) (x) #endif #include "crc32table.h" #if CRC_LE_BITS > 8 /* implements slicing-by-4 or slicing-by-8 algorithm */ static inline u32 crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256]) { #if __BYTE_ORDER == __LITTLE_ENDIAN # define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8) # define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \ t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255]) # define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \ t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255]) # elif __BYTE_ORDER == __BIG_ENDIAN # define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8) # define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \ t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255]) # define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \ t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255]) # else # error What endian are you? # endif const u32 *b; size_t rem_len; const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3]; # if CRC_LE_BITS != 32 const u32 *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7]; # endif u32 q; /* Align it */ if (((long)buf & 3) && len) { do { DO_CRC(*buf++); } while ((--len) && ((long)buf)&3); } # if CRC_LE_BITS == 32 rem_len = len & 3; len = len >> 2; # else rem_len = len & 7; len = len >> 3; # endif b = (const u32 *)buf; for (--b; len; --len) { q = crc ^ *++b; /* use pre increment for speed */ # if CRC_LE_BITS == 32 crc = DO_CRC4; # else crc = DO_CRC8; q = *++b; crc ^= DO_CRC4; # endif } len = rem_len; /* And the last few bytes */ if (len) { u8 *p = (u8 *)(b + 1) - 1; do { DO_CRC(*++p); /* use pre increment for speed */ } while (--len); } return crc; #undef DO_CRC #undef DO_CRC4 #undef DO_CRC8 } #endif /** * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32 * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for * other uses, or the previous crc32 value if computing incrementally. * @p: pointer to buffer over which CRC is run * @len: length of buffer @p */ static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p, size_t len, const u32 (*tab)[256], u32 polynomial) { #if CRC_LE_BITS == 1 int i; while (len--) { crc ^= *p++; for (i = 0; i < 8; i++) crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); } # elif CRC_LE_BITS == 2 while (len--) { crc ^= *p++; crc = (crc >> 2) ^ tab[0][crc & 3]; crc = (crc >> 2) ^ tab[0][crc & 3]; crc = (crc >> 2) ^ tab[0][crc & 3]; crc = (crc >> 2) ^ tab[0][crc & 3]; } # elif CRC_LE_BITS == 4 while (len--) { crc ^= *p++; crc = (crc >> 4) ^ tab[0][crc & 15]; crc = (crc >> 4) ^ tab[0][crc & 15]; } # elif CRC_LE_BITS == 8 /* aka Sarwate algorithm */ while (len--) { crc ^= *p++; crc = (crc >> 8) ^ tab[0][crc & 255]; } # else crc = (__force u32) cpu_to_le32(crc); crc = crc32_body(crc, p, len, tab); crc = le32_to_cpu((__force __le32)crc); #endif return crc; } #if CRC_LE_BITS == 1 u32 __pure crc32c_le(u32 crc, unsigned char const *p, size_t len) { return crc32_le_generic(crc, p, len, NULL, CRC32C_POLY_LE); } #else u32 __pure crc32c_le(u32 crc, unsigned char const *p, size_t len) { return crc32_le_generic(crc, p, len, (const u32 (*)[256])crc32ctable_le, CRC32C_POLY_LE); } #endif #ifdef CRC32_SELFTEST # include "crc32cselftest.h" /* * make sure we always return 0 for a successful test run, and non-zero for a * failed run. The build infrastructure is looking for this information to * determine whether to allow the build to proceed. */ int main(int argc, char **argv) { int errors; printf("CRC_LE_BITS = %d\n", CRC_LE_BITS); errors = crc32c_test(); return errors != 0; } #endif /* CRC32_SELFTEST */ xfsprogs-5.3.0/libfrog/crc32c.h0000644000175000017500000000044313570057155016131 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_CRC32C_H__ #define __LIBFROG_CRC32C_H__ extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len); #endif /* __LIBFROG_CRC32C_H__ */ xfsprogs-5.3.0/libfrog/crc32cselftest.h0000644000175000017500000010044413570057155017705 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Aug 8, 2011 Bob Pearson with help from Joakim Tjernlund and George Spelvin * cleaned up code to current version of sparse and added the slicing-by-8 * algorithm to the closely similar existing slicing-by-4 algorithm. * Oct 15, 2000 Matt Domsch * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks! * Code was from the public domain, copyright abandoned. Code was * subsequently included in the kernel, thus was re-licensed under the * GNU GPL v2. * Oct 12, 2000 Matt Domsch * Same crc32 function was used in 5 other places in the kernel. * I made one version, and deleted the others. * There are various incantations of crc32(). Some use a seed of 0 or ~0. * Some xor at the end with ~0. The generic crc32() function takes * seed as an argument, and doesn't xor at the end. Then individual * users can do whatever they need. * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0. * fs/jffs2 uses seed 0, doesn't xor with ~0. * fs/partitions/efi.c uses seed ~0, xor's with ~0. */ /* see: Documentation/crc32.txt for a description of algorithms */ /* * lifted from the 3.8-rc2 kernel source for xfsprogs. Killed CONFIG_X86 * specific bits for just the generic algorithm. Also removed the big endian * version of the algorithm as XFS only uses the little endian CRC version to * match the hardware acceleration available on Intel CPUs. */ /* This is just the crc32 self test bits from crc32.c. */ #ifndef __LIBFROG_CRC32CSELFTEST_H__ #define __LIBFROG_CRC32CSELFTEST_H__ /* 4096 random bytes */ static uint8_t __attribute__((__aligned__(8))) test_buf[] = { 0x5b, 0x85, 0x21, 0xcb, 0x09, 0x68, 0x7d, 0x30, 0xc7, 0x69, 0xd7, 0x30, 0x92, 0xde, 0x59, 0xe4, 0xc9, 0x6e, 0x8b, 0xdb, 0x98, 0x6b, 0xaa, 0x60, 0xa8, 0xb5, 0xbc, 0x6c, 0xa9, 0xb1, 0x5b, 0x2c, 0xea, 0xb4, 0x92, 0x6a, 0x3f, 0x79, 0x91, 0xe4, 0xe9, 0x70, 0x51, 0x8c, 0x7f, 0x95, 0x6f, 0x1a, 0x56, 0xa1, 0x5c, 0x27, 0x03, 0x67, 0x9f, 0x3a, 0xe2, 0x31, 0x11, 0x29, 0x6b, 0x98, 0xfc, 0xc4, 0x53, 0x24, 0xc5, 0x8b, 0xce, 0x47, 0xb2, 0xb9, 0x32, 0xcb, 0xc1, 0xd0, 0x03, 0x57, 0x4e, 0xd4, 0xe9, 0x3c, 0xa1, 0x63, 0xcf, 0x12, 0x0e, 0xca, 0xe1, 0x13, 0xd1, 0x93, 0xa6, 0x88, 0x5c, 0x61, 0x5b, 0xbb, 0xf0, 0x19, 0x46, 0xb4, 0xcf, 0x9e, 0xb6, 0x6b, 0x4c, 0x3a, 0xcf, 0x60, 0xf9, 0x7a, 0x8d, 0x07, 0x63, 0xdb, 0x40, 0xe9, 0x0b, 0x6f, 0xad, 0x97, 0xf1, 0xed, 0xd0, 0x1e, 0x26, 0xfd, 0xbf, 0xb7, 0xc8, 0x04, 0x94, 0xf8, 0x8b, 0x8c, 0xf1, 0xab, 0x7a, 0xd4, 0xdd, 0xf3, 0xe8, 0x88, 0xc3, 0xed, 0x17, 0x8a, 0x9b, 0x40, 0x0d, 0x53, 0x62, 0x12, 0x03, 0x5f, 0x1b, 0x35, 0x32, 0x1f, 0xb4, 0x7b, 0x93, 0x78, 0x0d, 0xdb, 0xce, 0xa4, 0xc0, 0x47, 0xd5, 0xbf, 0x68, 0xe8, 0x5d, 0x74, 0x8f, 0x8e, 0x75, 0x1c, 0xb2, 0x4f, 0x9a, 0x60, 0xd1, 0xbe, 0x10, 0xf4, 0x5c, 0xa1, 0x53, 0x09, 0xa5, 0xe0, 0x09, 0x54, 0x85, 0x5c, 0xdc, 0x07, 0xe7, 0x21, 0x69, 0x7b, 0x8a, 0xfd, 0x90, 0xf1, 0x22, 0xd0, 0xb4, 0x36, 0x28, 0xe6, 0xb8, 0x0f, 0x39, 0xde, 0xc8, 0xf3, 0x86, 0x60, 0x34, 0xd2, 0x5e, 0xdf, 0xfd, 0xcf, 0x0f, 0xa9, 0x65, 0xf0, 0xd5, 0x4d, 0x96, 0x40, 0xe3, 0xdf, 0x3f, 0x95, 0x5a, 0x39, 0x19, 0x93, 0xf4, 0x75, 0xce, 0x22, 0x00, 0x1c, 0x93, 0xe2, 0x03, 0x66, 0xf4, 0x93, 0x73, 0x86, 0x81, 0x8e, 0x29, 0x44, 0x48, 0x86, 0x61, 0x7c, 0x48, 0xa3, 0x43, 0xd2, 0x9c, 0x8d, 0xd4, 0x95, 0xdd, 0xe1, 0x22, 0x89, 0x3a, 0x40, 0x4c, 0x1b, 0x8a, 0x04, 0xa8, 0x09, 0x69, 0x8b, 0xea, 0xc6, 0x55, 0x8e, 0x57, 0xe6, 0x64, 0x35, 0xf0, 0xc7, 0x16, 0x9f, 0x5d, 0x5e, 0x86, 0x40, 0x46, 0xbb, 0xe5, 0x45, 0x88, 0xfe, 0xc9, 0x63, 0x15, 0xfb, 0xf5, 0xbd, 0x71, 0x61, 0xeb, 0x7b, 0x78, 0x70, 0x07, 0x31, 0x03, 0x9f, 0xb2, 0xc8, 0xa7, 0xab, 0x47, 0xfd, 0xdf, 0xa0, 0x78, 0x72, 0xa4, 0x2a, 0xe4, 0xb6, 0xba, 0xc0, 0x1e, 0x86, 0x71, 0xe6, 0x3d, 0x18, 0x37, 0x70, 0xe6, 0xff, 0xe0, 0xbc, 0x0b, 0x22, 0xa0, 0x1f, 0xd3, 0xed, 0xa2, 0x55, 0x39, 0xab, 0xa8, 0x13, 0x73, 0x7c, 0x3f, 0xb2, 0xd6, 0x19, 0xac, 0xff, 0x99, 0xed, 0xe8, 0xe6, 0xa6, 0x22, 0xe3, 0x9c, 0xf1, 0x30, 0xdc, 0x01, 0x0a, 0x56, 0xfa, 0xe4, 0xc9, 0x99, 0xdd, 0xa8, 0xd8, 0xda, 0x35, 0x51, 0x73, 0xb4, 0x40, 0x86, 0x85, 0xdb, 0x5c, 0xd5, 0x85, 0x80, 0x14, 0x9c, 0xfd, 0x98, 0xa9, 0x82, 0xc5, 0x37, 0xff, 0x32, 0x5d, 0xd0, 0x0b, 0xfa, 0xdc, 0x04, 0x5e, 0x09, 0xd2, 0xca, 0x17, 0x4b, 0x1a, 0x8e, 0x15, 0xe1, 0xcc, 0x4e, 0x52, 0x88, 0x35, 0xbd, 0x48, 0xfe, 0x15, 0xa0, 0x91, 0xfd, 0x7e, 0x6c, 0x0e, 0x5d, 0x79, 0x1b, 0x81, 0x79, 0xd2, 0x09, 0x34, 0x70, 0x3d, 0x81, 0xec, 0xf6, 0x24, 0xbb, 0xfb, 0xf1, 0x7b, 0xdf, 0x54, 0xea, 0x80, 0x9b, 0xc7, 0x99, 0x9e, 0xbd, 0x16, 0x78, 0x12, 0x53, 0x5e, 0x01, 0xa7, 0x4e, 0xbd, 0x67, 0xe1, 0x9b, 0x4c, 0x0e, 0x61, 0x45, 0x97, 0xd2, 0xf0, 0x0f, 0xfe, 0x15, 0x08, 0xb7, 0x11, 0x4c, 0xe7, 0xff, 0x81, 0x53, 0xff, 0x91, 0x25, 0x38, 0x7e, 0x40, 0x94, 0xe5, 0xe0, 0xad, 0xe6, 0xd9, 0x79, 0xb6, 0x92, 0xc9, 0xfc, 0xde, 0xc3, 0x1a, 0x23, 0xbb, 0xdd, 0xc8, 0x51, 0x0c, 0x3a, 0x72, 0xfa, 0x73, 0x6f, 0xb7, 0xee, 0x61, 0x39, 0x03, 0x01, 0x3f, 0x7f, 0x94, 0x2e, 0x2e, 0xba, 0x3a, 0xbb, 0xb4, 0xfa, 0x6a, 0x17, 0xfe, 0xea, 0xef, 0x5e, 0x66, 0x97, 0x3f, 0x32, 0x3d, 0xd7, 0x3e, 0xb1, 0xf1, 0x6c, 0x14, 0x4c, 0xfd, 0x37, 0xd3, 0x38, 0x80, 0xfb, 0xde, 0xa6, 0x24, 0x1e, 0xc8, 0xca, 0x7f, 0x3a, 0x93, 0xd8, 0x8b, 0x18, 0x13, 0xb2, 0xe5, 0xe4, 0x93, 0x05, 0x53, 0x4f, 0x84, 0x66, 0xa7, 0x58, 0x5c, 0x7b, 0x86, 0x52, 0x6d, 0x0d, 0xce, 0xa4, 0x30, 0x7d, 0xb6, 0x18, 0x9f, 0xeb, 0xff, 0x22, 0xbb, 0x72, 0x29, 0xb9, 0x44, 0x0b, 0x48, 0x1e, 0x84, 0x71, 0x81, 0xe3, 0x6d, 0x73, 0x26, 0x92, 0xb4, 0x4d, 0x2a, 0x29, 0xb8, 0x1f, 0x72, 0xed, 0xd0, 0xe1, 0x64, 0x77, 0xea, 0x8e, 0x88, 0x0f, 0xef, 0x3f, 0xb1, 0x3b, 0xad, 0xf9, 0xc9, 0x8b, 0xd0, 0xac, 0xc6, 0xcc, 0xa9, 0x40, 0xcc, 0x76, 0xf6, 0x3b, 0x53, 0xb5, 0x88, 0xcb, 0xc8, 0x37, 0xf1, 0xa2, 0xba, 0x23, 0x15, 0x99, 0x09, 0xcc, 0xe7, 0x7a, 0x3b, 0x37, 0xf7, 0x58, 0xc8, 0x46, 0x8c, 0x2b, 0x2f, 0x4e, 0x0e, 0xa6, 0x5c, 0xea, 0x85, 0x55, 0xba, 0x02, 0x0e, 0x0e, 0x48, 0xbc, 0xe1, 0xb1, 0x01, 0x35, 0x79, 0x13, 0x3d, 0x1b, 0xc0, 0x53, 0x68, 0x11, 0xe7, 0x95, 0x0f, 0x9d, 0x3f, 0x4c, 0x47, 0x7b, 0x4d, 0x1c, 0xae, 0x50, 0x9b, 0xcb, 0xdd, 0x05, 0x8d, 0x9a, 0x97, 0xfd, 0x8c, 0xef, 0x0c, 0x1d, 0x67, 0x73, 0xa8, 0x28, 0x36, 0xd5, 0xb6, 0x92, 0x33, 0x40, 0x75, 0x0b, 0x51, 0xc3, 0x64, 0xba, 0x1d, 0xc2, 0xcc, 0xee, 0x7d, 0x54, 0x0f, 0x27, 0x69, 0xa7, 0x27, 0x63, 0x30, 0x29, 0xd9, 0xc8, 0x84, 0xd8, 0xdf, 0x9f, 0x68, 0x8d, 0x04, 0xca, 0xa6, 0xc5, 0xc7, 0x7a, 0x5c, 0xc8, 0xd1, 0xcb, 0x4a, 0xec, 0xd0, 0xd8, 0x20, 0x69, 0xc5, 0x17, 0xcd, 0x78, 0xc8, 0x75, 0x23, 0x30, 0x69, 0xc9, 0xd4, 0xea, 0x5c, 0x4f, 0x6b, 0x86, 0x3f, 0x8b, 0xfe, 0xee, 0x44, 0xc9, 0x7c, 0xb7, 0xdd, 0x3e, 0xe5, 0xec, 0x54, 0x03, 0x3e, 0xaa, 0x82, 0xc6, 0xdf, 0xb2, 0x38, 0x0e, 0x5d, 0xb3, 0x88, 0xd9, 0xd3, 0x69, 0x5f, 0x8f, 0x70, 0x8a, 0x7e, 0x11, 0xd9, 0x1e, 0x7b, 0x38, 0xf1, 0x42, 0x1a, 0xc0, 0x35, 0xf5, 0xc7, 0x36, 0x85, 0xf5, 0xf7, 0xb8, 0x7e, 0xc7, 0xef, 0x18, 0xf1, 0x63, 0xd6, 0x7a, 0xc6, 0xc9, 0x0e, 0x4d, 0x69, 0x4f, 0x84, 0xef, 0x26, 0x41, 0x0c, 0xec, 0xc7, 0xe0, 0x7e, 0x3c, 0x67, 0x01, 0x4c, 0x62, 0x1a, 0x20, 0x6f, 0xee, 0x47, 0x4d, 0xc0, 0x99, 0x13, 0x8d, 0x91, 0x4a, 0x26, 0xd4, 0x37, 0x28, 0x90, 0x58, 0x75, 0x66, 0x2b, 0x0a, 0xdf, 0xda, 0xee, 0x92, 0x25, 0x90, 0x62, 0x39, 0x9e, 0x44, 0x98, 0xad, 0xc1, 0x88, 0xed, 0xe4, 0xb4, 0xaf, 0xf5, 0x8c, 0x9b, 0x48, 0x4d, 0x56, 0x60, 0x97, 0x0f, 0x61, 0x59, 0x9e, 0xa6, 0x27, 0xfe, 0xc1, 0x91, 0x15, 0x38, 0xb8, 0x0f, 0xae, 0x61, 0x7d, 0x26, 0x13, 0x5a, 0x73, 0xff, 0x1c, 0xa3, 0x61, 0x04, 0x58, 0x48, 0x55, 0x44, 0x11, 0xfe, 0x15, 0xca, 0xc3, 0xbd, 0xca, 0xc5, 0xb4, 0x40, 0x5d, 0x1b, 0x7f, 0x39, 0xb5, 0x9c, 0x35, 0xec, 0x61, 0x15, 0x32, 0x32, 0xb8, 0x4e, 0x40, 0x9f, 0x17, 0x1f, 0x0a, 0x4d, 0xa9, 0x91, 0xef, 0xb7, 0xb0, 0xeb, 0xc2, 0x83, 0x9a, 0x6c, 0xd2, 0x79, 0x43, 0x78, 0x5e, 0x2f, 0xe5, 0xdd, 0x1a, 0x3c, 0x45, 0xab, 0x29, 0x40, 0x3a, 0x37, 0x5b, 0x6f, 0xd7, 0xfc, 0x48, 0x64, 0x3c, 0x49, 0xfb, 0x21, 0xbe, 0xc3, 0xff, 0x07, 0xfb, 0x17, 0xe9, 0xc9, 0x0c, 0x4c, 0x5c, 0x15, 0x9e, 0x8e, 0x22, 0x30, 0x0a, 0xde, 0x48, 0x7f, 0xdb, 0x0d, 0xd1, 0x2b, 0x87, 0x38, 0x9e, 0xcc, 0x5a, 0x01, 0x16, 0xee, 0x75, 0x49, 0x0d, 0x30, 0x01, 0x34, 0x6a, 0xb6, 0x9a, 0x5a, 0x2a, 0xec, 0xbb, 0x48, 0xac, 0xd3, 0x77, 0x83, 0xd8, 0x08, 0x86, 0x4f, 0x48, 0x09, 0x29, 0x41, 0x79, 0xa1, 0x03, 0x12, 0xc4, 0xcd, 0x90, 0x55, 0x47, 0x66, 0x74, 0x9a, 0xcc, 0x4f, 0x35, 0x8c, 0xd6, 0x98, 0xef, 0xeb, 0x45, 0xb9, 0x9a, 0x26, 0x2f, 0x39, 0xa5, 0x70, 0x6d, 0xfc, 0xb4, 0x51, 0xee, 0xf4, 0x9c, 0xe7, 0x38, 0x59, 0xad, 0xf4, 0xbc, 0x46, 0xff, 0x46, 0x8e, 0x60, 0x9c, 0xa3, 0x60, 0x1d, 0xf8, 0x26, 0x72, 0xf5, 0x72, 0x9d, 0x68, 0x80, 0x04, 0xf6, 0x0b, 0xa1, 0x0a, 0xd5, 0xa7, 0x82, 0x3a, 0x3e, 0x47, 0xa8, 0x5a, 0xde, 0x59, 0x4f, 0x7b, 0x07, 0xb3, 0xe9, 0x24, 0x19, 0x3d, 0x34, 0x05, 0xec, 0xf1, 0xab, 0x6e, 0x64, 0x8f, 0xd3, 0xe6, 0x41, 0x86, 0x80, 0x70, 0xe3, 0x8d, 0x60, 0x9c, 0x34, 0x25, 0x01, 0x07, 0x4d, 0x19, 0x41, 0x4e, 0x3d, 0x5c, 0x7e, 0xa8, 0xf5, 0xcc, 0xd5, 0x7b, 0xe2, 0x7d, 0x3d, 0x49, 0x86, 0x7d, 0x07, 0xb7, 0x10, 0xe3, 0x35, 0xb8, 0x84, 0x6d, 0x76, 0xab, 0x17, 0xc6, 0x38, 0xb4, 0xd3, 0x28, 0x57, 0xad, 0xd3, 0x88, 0x5a, 0xda, 0xea, 0xc8, 0x94, 0xcc, 0x37, 0x19, 0xac, 0x9c, 0x9f, 0x4b, 0x00, 0x15, 0xc0, 0xc8, 0xca, 0x1f, 0x15, 0xaa, 0xe0, 0xdb, 0xf9, 0x2f, 0x57, 0x1b, 0x24, 0xc7, 0x6f, 0x76, 0x29, 0xfb, 0xed, 0x25, 0x0d, 0xc0, 0xfe, 0xbd, 0x5a, 0xbf, 0x20, 0x08, 0x51, 0x05, 0xec, 0x71, 0xa3, 0xbf, 0xef, 0x5e, 0x99, 0x75, 0xdb, 0x3c, 0x5f, 0x9a, 0x8c, 0xbb, 0x19, 0x5c, 0x0e, 0x93, 0x19, 0xf8, 0x6a, 0xbc, 0xf2, 0x12, 0x54, 0x2f, 0xcb, 0x28, 0x64, 0x88, 0xb3, 0x92, 0x0d, 0x96, 0xd1, 0xa6, 0xe4, 0x1f, 0xf1, 0x4d, 0xa4, 0xab, 0x1c, 0xee, 0x54, 0xf2, 0xad, 0x29, 0x6d, 0x32, 0x37, 0xb2, 0x16, 0x77, 0x5c, 0xdc, 0x2e, 0x54, 0xec, 0x75, 0x26, 0xc6, 0x36, 0xd9, 0x17, 0x2c, 0xf1, 0x7a, 0xdc, 0x4b, 0xf1, 0xe2, 0xd9, 0x95, 0xba, 0xac, 0x87, 0xc1, 0xf3, 0x8e, 0x58, 0x08, 0xd8, 0x87, 0x60, 0xc9, 0xee, 0x6a, 0xde, 0xa4, 0xd2, 0xfc, 0x0d, 0xe5, 0x36, 0xc4, 0x5c, 0x52, 0xb3, 0x07, 0x54, 0x65, 0x24, 0xc1, 0xb1, 0xd1, 0xb1, 0x53, 0x13, 0x31, 0x79, 0x7f, 0x05, 0x76, 0xeb, 0x37, 0x59, 0x15, 0x2b, 0xd1, 0x3f, 0xac, 0x08, 0x97, 0xeb, 0x91, 0x98, 0xdf, 0x6c, 0x09, 0x0d, 0x04, 0x9f, 0xdc, 0x3b, 0x0e, 0x60, 0x68, 0x47, 0x23, 0x15, 0x16, 0xc6, 0x0b, 0x35, 0xf8, 0x77, 0xa2, 0x78, 0x50, 0xd4, 0x64, 0x22, 0x33, 0xff, 0xfb, 0x93, 0x71, 0x46, 0x50, 0x39, 0x1b, 0x9c, 0xea, 0x4e, 0x8d, 0x0c, 0x37, 0xe5, 0x5c, 0x51, 0x3a, 0x31, 0xb2, 0x85, 0x84, 0x3f, 0x41, 0xee, 0xa2, 0xc1, 0xc6, 0x13, 0x3b, 0x54, 0x28, 0xd2, 0x18, 0x37, 0xcc, 0x46, 0x9f, 0x6a, 0x91, 0x3d, 0x5a, 0x15, 0x3c, 0x89, 0xa3, 0x61, 0x06, 0x7d, 0x2e, 0x78, 0xbe, 0x7d, 0x40, 0xba, 0x2f, 0x95, 0xb1, 0x2f, 0x87, 0x3b, 0x8a, 0xbe, 0x6a, 0xf4, 0xc2, 0x31, 0x74, 0xee, 0x91, 0xe0, 0x23, 0xaa, 0x5d, 0x7f, 0xdd, 0xf0, 0x44, 0x8c, 0x0b, 0x59, 0x2b, 0xfc, 0x48, 0x3a, 0xdf, 0x07, 0x05, 0x38, 0x6c, 0xc9, 0xeb, 0x18, 0x24, 0x68, 0x8d, 0x58, 0x98, 0xd3, 0x31, 0xa3, 0xe4, 0x70, 0x59, 0xb1, 0x21, 0xbe, 0x7e, 0x65, 0x7d, 0xb8, 0x04, 0xab, 0xf6, 0xe4, 0xd7, 0xda, 0xec, 0x09, 0x8f, 0xda, 0x6d, 0x24, 0x07, 0xcc, 0x29, 0x17, 0x05, 0x78, 0x1a, 0xc1, 0xb1, 0xce, 0xfc, 0xaa, 0x2d, 0xe7, 0xcc, 0x85, 0x84, 0x84, 0x03, 0x2a, 0x0c, 0x3f, 0xa9, 0xf8, 0xfd, 0x84, 0x53, 0x59, 0x5c, 0xf0, 0xd4, 0x09, 0xf0, 0xd2, 0x6c, 0x32, 0x03, 0xb0, 0xa0, 0x8c, 0x52, 0xeb, 0x23, 0x91, 0x88, 0x43, 0x13, 0x46, 0xf6, 0x1e, 0xb4, 0x1b, 0xf5, 0x8e, 0x3a, 0xb5, 0x3d, 0x00, 0xf6, 0xe5, 0x08, 0x3d, 0x5f, 0x39, 0xd3, 0x21, 0x69, 0xbc, 0x03, 0x22, 0x3a, 0xd2, 0x5c, 0x84, 0xf8, 0x15, 0xc4, 0x80, 0x0b, 0xbc, 0x29, 0x3c, 0xf3, 0x95, 0x98, 0xcd, 0x8f, 0x35, 0xbc, 0xa5, 0x3e, 0xfc, 0xd4, 0x13, 0x9e, 0xde, 0x4f, 0xce, 0x71, 0x9d, 0x09, 0xad, 0xf2, 0x80, 0x6b, 0x65, 0x7f, 0x03, 0x00, 0x14, 0x7c, 0x15, 0x85, 0x40, 0x6d, 0x70, 0xea, 0xdc, 0xb3, 0x63, 0x35, 0x4f, 0x4d, 0xe0, 0xd9, 0xd5, 0x3c, 0x58, 0x56, 0x23, 0x80, 0xe2, 0x36, 0xdd, 0x75, 0x1d, 0x94, 0x11, 0x41, 0x8e, 0xe0, 0x81, 0x8e, 0xcf, 0xe0, 0xe5, 0xf6, 0xde, 0xd1, 0xe7, 0x04, 0x12, 0x79, 0x92, 0x2b, 0x71, 0x2a, 0x79, 0x8b, 0x7c, 0x44, 0x79, 0x16, 0x30, 0x4e, 0xf4, 0xf6, 0x9b, 0xb7, 0x40, 0xa3, 0x5a, 0xa7, 0x69, 0x3e, 0xc1, 0x3a, 0x04, 0xd0, 0x88, 0xa0, 0x3b, 0xdd, 0xc6, 0x9e, 0x7e, 0x1e, 0x1e, 0x8f, 0x44, 0xf7, 0x73, 0x67, 0x1e, 0x1a, 0x78, 0xfa, 0x62, 0xf4, 0xa9, 0xa8, 0xc6, 0x5b, 0xb8, 0xfa, 0x06, 0x7d, 0x5e, 0x38, 0x1c, 0x9a, 0x39, 0xe9, 0x39, 0x98, 0x22, 0x0b, 0xa7, 0xac, 0x0b, 0xf3, 0xbc, 0xf1, 0xeb, 0x8c, 0x81, 0xe3, 0x48, 0x8a, 0xed, 0x42, 0xc2, 0x38, 0xcf, 0x3e, 0xda, 0xd2, 0x89, 0x8d, 0x9c, 0x53, 0xb5, 0x2f, 0x41, 0x01, 0x26, 0x84, 0x9c, 0xa3, 0x56, 0xf6, 0x49, 0xc7, 0xd4, 0x9f, 0x93, 0x1b, 0x96, 0x49, 0x5e, 0xad, 0xb3, 0x84, 0x1f, 0x3c, 0xa4, 0xe0, 0x9b, 0xd1, 0x90, 0xbc, 0x38, 0x6c, 0xdd, 0x95, 0x4d, 0x9d, 0xb1, 0x71, 0x57, 0x2d, 0x34, 0xe8, 0xb8, 0x42, 0xc7, 0x99, 0x03, 0xc7, 0x07, 0x30, 0x65, 0x91, 0x55, 0xd5, 0x90, 0x70, 0x97, 0x37, 0x68, 0xd4, 0x11, 0xf9, 0xe8, 0xce, 0xec, 0xdc, 0x34, 0xd5, 0xd3, 0xb7, 0xc4, 0xb8, 0x97, 0x05, 0x92, 0xad, 0xf8, 0xe2, 0x36, 0x64, 0x41, 0xc9, 0xc5, 0x41, 0x77, 0x52, 0xd7, 0x2c, 0xa5, 0x24, 0x2f, 0xd9, 0x34, 0x0b, 0x47, 0x35, 0xa7, 0x28, 0x8b, 0xc5, 0xcd, 0xe9, 0x46, 0xac, 0x39, 0x94, 0x3c, 0x10, 0xc6, 0x29, 0x73, 0x0e, 0x0e, 0x5d, 0xe0, 0x71, 0x03, 0x8a, 0x72, 0x0e, 0x26, 0xb0, 0x7d, 0x84, 0xed, 0x95, 0x23, 0x49, 0x5a, 0x45, 0x83, 0x45, 0x60, 0x11, 0x4a, 0x46, 0x31, 0xd4, 0xd8, 0x16, 0x54, 0x98, 0x58, 0xed, 0x6d, 0xcc, 0x5d, 0xd6, 0x50, 0x61, 0x9f, 0x9d, 0xc5, 0x3e, 0x9d, 0x32, 0x47, 0xde, 0x96, 0xe1, 0x5d, 0xd8, 0xf8, 0xb4, 0x69, 0x6f, 0xb9, 0x15, 0x90, 0x57, 0x7a, 0xf6, 0xad, 0xb0, 0x5b, 0xf5, 0xa6, 0x36, 0x94, 0xfd, 0x84, 0xce, 0x1c, 0x0f, 0x4b, 0xd0, 0xc2, 0x5b, 0x6b, 0x56, 0xef, 0x73, 0x93, 0x0b, 0xc3, 0xee, 0xd9, 0xcf, 0xd3, 0xa4, 0x22, 0x58, 0xcd, 0x50, 0x6e, 0x65, 0xf4, 0xe9, 0xb7, 0x71, 0xaf, 0x4b, 0xb3, 0xb6, 0x2f, 0x0f, 0x0e, 0x3b, 0xc9, 0x85, 0x14, 0xf5, 0x17, 0xe8, 0x7a, 0x3a, 0xbf, 0x5f, 0x5e, 0xf8, 0x18, 0x48, 0xa6, 0x72, 0xab, 0x06, 0x95, 0xe9, 0xc8, 0xa7, 0xf4, 0x32, 0x44, 0x04, 0x0c, 0x84, 0x98, 0x73, 0xe3, 0x89, 0x8d, 0x5f, 0x7e, 0x4a, 0x42, 0x8f, 0xc5, 0x28, 0xb1, 0x82, 0xef, 0x1c, 0x97, 0x31, 0x3b, 0x4d, 0xe0, 0x0e, 0x10, 0x10, 0x97, 0x93, 0x49, 0x78, 0x2f, 0x0d, 0x86, 0x8b, 0xa1, 0x53, 0xa9, 0x81, 0x20, 0x79, 0xe7, 0x07, 0x77, 0xb6, 0xac, 0x5e, 0xd2, 0x05, 0xcd, 0xe9, 0xdb, 0x8a, 0x94, 0x82, 0x8a, 0x23, 0xb9, 0x3d, 0x1c, 0xa9, 0x7d, 0x72, 0x4a, 0xed, 0x33, 0xa3, 0xdb, 0x21, 0xa7, 0x86, 0x33, 0x45, 0xa5, 0xaa, 0x56, 0x45, 0xb5, 0x83, 0x29, 0x40, 0x47, 0x79, 0x04, 0x6e, 0xb9, 0x95, 0xd0, 0x81, 0x77, 0x2d, 0x48, 0x1e, 0xfe, 0xc3, 0xc2, 0x1e, 0xe5, 0xf2, 0xbe, 0xfd, 0x3b, 0x94, 0x9f, 0xc4, 0xc4, 0x26, 0x9d, 0xe4, 0x66, 0x1e, 0x19, 0xee, 0x6c, 0x79, 0x97, 0x11, 0x31, 0x4b, 0x0d, 0x01, 0xcb, 0xde, 0xa8, 0xf6, 0x6d, 0x7c, 0x39, 0x46, 0x4e, 0x7e, 0x3f, 0x94, 0x17, 0xdf, 0xa1, 0x7d, 0xd9, 0x1c, 0x8e, 0xbc, 0x7d, 0x33, 0x7d, 0xe3, 0x12, 0x40, 0xca, 0xab, 0x37, 0x11, 0x46, 0xd4, 0xae, 0xef, 0x44, 0xa2, 0xb3, 0x6a, 0x66, 0x0e, 0x0c, 0x90, 0x7f, 0xdf, 0x5c, 0x66, 0x5f, 0xf2, 0x94, 0x9f, 0xa6, 0x73, 0x4f, 0xeb, 0x0d, 0xad, 0xbf, 0xc0, 0x63, 0x5c, 0xdc, 0x46, 0x51, 0xe8, 0x8e, 0x90, 0x19, 0xa8, 0xa4, 0x3c, 0x91, 0x79, 0xfa, 0x7e, 0x58, 0x85, 0x13, 0x55, 0xc5, 0x19, 0x82, 0x37, 0x1b, 0x0a, 0x02, 0x1f, 0x99, 0x6b, 0x18, 0xf1, 0x28, 0x08, 0xa2, 0x73, 0xb8, 0x0f, 0x2e, 0xcd, 0xbf, 0xf3, 0x86, 0x7f, 0xea, 0xef, 0xd0, 0xbb, 0xa6, 0x21, 0xdf, 0x49, 0x73, 0x51, 0xcc, 0x36, 0xd3, 0x3e, 0xa0, 0xf8, 0x44, 0xdf, 0xd3, 0xa6, 0xbe, 0x8a, 0xd4, 0x57, 0xdd, 0x72, 0x94, 0x61, 0x0f, 0x82, 0xd1, 0x07, 0xb8, 0x7c, 0x18, 0x83, 0xdf, 0x3a, 0xe5, 0x50, 0x6a, 0x82, 0x20, 0xac, 0xa9, 0xa8, 0xff, 0xd9, 0xf3, 0x77, 0x33, 0x5a, 0x9e, 0x7f, 0x6d, 0xfe, 0x5d, 0x33, 0x41, 0x42, 0xe7, 0x6c, 0x19, 0xe0, 0x44, 0x8a, 0x15, 0xf6, 0x70, 0x98, 0xb7, 0x68, 0x4d, 0xfa, 0x97, 0x39, 0xb0, 0x8e, 0xe8, 0x84, 0x8b, 0x75, 0x30, 0xb7, 0x7d, 0x92, 0x69, 0x20, 0x9c, 0x81, 0xfb, 0x4b, 0xf4, 0x01, 0x50, 0xeb, 0xce, 0x0c, 0x1c, 0x6c, 0xb5, 0x4a, 0xd7, 0x27, 0x0c, 0xce, 0xbb, 0xe5, 0x85, 0xf0, 0xb6, 0xee, 0xd5, 0x70, 0xdd, 0x3b, 0xfc, 0xd4, 0x99, 0xf1, 0x33, 0xdd, 0x8b, 0xc4, 0x2f, 0xae, 0xab, 0x74, 0x96, 0x32, 0xc7, 0x4c, 0x56, 0x3c, 0x89, 0x0f, 0x96, 0x0b, 0x42, 0xc0, 0xcb, 0xee, 0x0f, 0x0b, 0x8c, 0xfb, 0x7e, 0x47, 0x7b, 0x64, 0x48, 0xfd, 0xb2, 0x00, 0x80, 0x89, 0xa5, 0x13, 0x55, 0x62, 0xfc, 0x8f, 0xe2, 0x42, 0x03, 0xb7, 0x4e, 0x2a, 0x79, 0xb4, 0x82, 0xea, 0x23, 0x49, 0xda, 0xaf, 0x52, 0x63, 0x1e, 0x60, 0x03, 0x89, 0x06, 0x44, 0x46, 0x08, 0xc3, 0xc4, 0x87, 0x70, 0x2e, 0xda, 0x94, 0xad, 0x6b, 0xe0, 0xe4, 0xd1, 0x8a, 0x06, 0xc2, 0xa8, 0xc0, 0xa7, 0x43, 0x3c, 0x47, 0x52, 0x0e, 0xc3, 0x77, 0x81, 0x11, 0x67, 0x0e, 0xa0, 0x70, 0x04, 0x47, 0x29, 0x40, 0x86, 0x0d, 0x34, 0x56, 0xa7, 0xc9, 0x35, 0x59, 0x68, 0xdc, 0x93, 0x81, 0x70, 0xee, 0x86, 0xd9, 0x80, 0x06, 0x40, 0x4f, 0x1a, 0x0d, 0x40, 0x30, 0x0b, 0xcb, 0x96, 0x47, 0xc1, 0xb7, 0x52, 0xfd, 0x56, 0xe0, 0x72, 0x4b, 0xfb, 0xbd, 0x92, 0x45, 0x61, 0x71, 0xc2, 0x33, 0x11, 0xbf, 0x52, 0x83, 0x79, 0x26, 0xe0, 0x49, 0x6b, 0xb7, 0x05, 0x8b, 0xe8, 0x0e, 0x87, 0x31, 0xd7, 0x9d, 0x8a, 0xf5, 0xc0, 0x5f, 0x2e, 0x58, 0x4a, 0xdb, 0x11, 0xb3, 0x6c, 0x30, 0x2a, 0x46, 0x19, 0xe3, 0x27, 0x84, 0x1f, 0x63, 0x6e, 0xf6, 0x57, 0xc7, 0xc9, 0xd8, 0x5e, 0xba, 0xb3, 0x87, 0xd5, 0x83, 0x26, 0x34, 0x21, 0x9e, 0x65, 0xde, 0x42, 0xd3, 0xbe, 0x7b, 0xbc, 0x91, 0x71, 0x44, 0x4d, 0x99, 0x3b, 0x31, 0xe5, 0x3f, 0x11, 0x4e, 0x7f, 0x13, 0x51, 0x3b, 0xae, 0x79, 0xc9, 0xd3, 0x81, 0x8e, 0x25, 0x40, 0x10, 0xfc, 0x07, 0x1e, 0xf9, 0x7b, 0x9a, 0x4b, 0x6c, 0xe3, 0xb3, 0xad, 0x1a, 0x0a, 0xdd, 0x9e, 0x59, 0x0c, 0xa2, 0xcd, 0xae, 0x48, 0x4a, 0x38, 0x5b, 0x47, 0x41, 0x94, 0x65, 0x6b, 0xbb, 0xeb, 0x5b, 0xe3, 0xaf, 0x07, 0x5b, 0xd4, 0x4a, 0xa2, 0xc9, 0x5d, 0x2f, 0x64, 0x03, 0xd7, 0x3a, 0x2c, 0x6e, 0xce, 0x76, 0x95, 0xb4, 0xb3, 0xc0, 0xf1, 0xe2, 0x45, 0x73, 0x7a, 0x5c, 0xab, 0xc1, 0xfc, 0x02, 0x8d, 0x81, 0x29, 0xb3, 0xac, 0x07, 0xec, 0x40, 0x7d, 0x45, 0xd9, 0x7a, 0x59, 0xee, 0x34, 0xf0, 0xe9, 0xd5, 0x7b, 0x96, 0xb1, 0x3d, 0x95, 0xcc, 0x86, 0xb5, 0xb6, 0x04, 0x2d, 0xb5, 0x92, 0x7e, 0x76, 0xf4, 0x06, 0xa9, 0xa3, 0x12, 0x0f, 0xb1, 0xaf, 0x26, 0xba, 0x7c, 0xfc, 0x7e, 0x1c, 0xbc, 0x2c, 0x49, 0x97, 0x53, 0x60, 0x13, 0x0b, 0xa6, 0x61, 0x83, 0x89, 0x42, 0xd4, 0x17, 0x0c, 0x6c, 0x26, 0x52, 0xc3, 0xb3, 0xd4, 0x67, 0xf5, 0xe3, 0x04, 0xb7, 0xf4, 0xcb, 0x80, 0xb8, 0xcb, 0x77, 0x56, 0x3e, 0xaa, 0x57, 0x54, 0xee, 0xb4, 0x2c, 0x67, 0xcf, 0xf2, 0xdc, 0xbe, 0x55, 0xf9, 0x43, 0x1f, 0x6e, 0x22, 0x97, 0x67, 0x7f, 0xc4, 0xef, 0xb1, 0x26, 0x31, 0x1e, 0x27, 0xdf, 0x41, 0x80, 0x47, 0x6c, 0xe2, 0xfa, 0xa9, 0x8c, 0x2a, 0xf6, 0xf2, 0xab, 0xf0, 0x15, 0xda, 0x6c, 0xc8, 0xfe, 0xb5, 0x23, 0xde, 0xa9, 0x05, 0x3f, 0x06, 0x54, 0x4c, 0xcd, 0xe1, 0xab, 0xfc, 0x0e, 0x62, 0x33, 0x31, 0x73, 0x2c, 0x76, 0xcb, 0xb4, 0x47, 0x1e, 0x20, 0xad, 0xd8, 0xf2, 0x31, 0xdd, 0xc4, 0x8b, 0x0c, 0x77, 0xbe, 0xe1, 0x8b, 0x26, 0x00, 0x02, 0x58, 0xd6, 0x8d, 0xef, 0xad, 0x74, 0x67, 0xab, 0x3f, 0xef, 0xcb, 0x6f, 0xb0, 0xcc, 0x81, 0x44, 0x4c, 0xaf, 0xe9, 0x49, 0x4f, 0xdb, 0xa0, 0x25, 0xa4, 0xf0, 0x89, 0xf1, 0xbe, 0xd8, 0x10, 0xff, 0xb1, 0x3b, 0x4b, 0xfa, 0x98, 0xf5, 0x79, 0x6d, 0x1e, 0x69, 0x4d, 0x57, 0xb1, 0xc8, 0x19, 0x1b, 0xbd, 0x1e, 0x8c, 0x84, 0xb7, 0x7b, 0xe8, 0xd2, 0x2d, 0x09, 0x41, 0x41, 0x37, 0x3d, 0xb1, 0x6f, 0x26, 0x5d, 0x71, 0x16, 0x3d, 0xb7, 0x83, 0x27, 0x2c, 0xa7, 0xb6, 0x50, 0xbd, 0x91, 0x86, 0xab, 0x24, 0xa1, 0x38, 0xfd, 0xea, 0x71, 0x55, 0x7e, 0x9a, 0x07, 0x77, 0x4b, 0xfa, 0x61, 0x66, 0x20, 0x1e, 0x28, 0x95, 0x18, 0x1b, 0xa4, 0xa0, 0xfd, 0xc0, 0x89, 0x72, 0x43, 0xd9, 0x3b, 0x49, 0x5a, 0x3f, 0x9d, 0xbf, 0xdb, 0xb4, 0x46, 0xea, 0x42, 0x01, 0x77, 0x23, 0x68, 0x95, 0xb6, 0x24, 0xb3, 0xa8, 0x6c, 0x28, 0x3b, 0x11, 0x40, 0x7e, 0x18, 0x65, 0x6d, 0xd8, 0x24, 0x42, 0x7d, 0x88, 0xc0, 0x52, 0xd9, 0x05, 0xe4, 0x95, 0x90, 0x87, 0x8c, 0xf4, 0xd0, 0x6b, 0xb9, 0x83, 0x99, 0x34, 0x6d, 0xfe, 0x54, 0x40, 0x94, 0x52, 0x21, 0x4f, 0x14, 0x25, 0xc5, 0xd6, 0x5e, 0x95, 0xdc, 0x0a, 0x2b, 0x89, 0x20, 0x11, 0x84, 0x48, 0xd6, 0x3a, 0xcd, 0x5c, 0x24, 0xad, 0x62, 0xe3, 0xb1, 0x93, 0x25, 0x8d, 0xcd, 0x7e, 0xfc, 0x27, 0xa3, 0x37, 0xfd, 0x84, 0xfc, 0x1b, 0xb2, 0xf1, 0x27, 0x38, 0x5a, 0xb7, 0xfc, 0xf2, 0xfa, 0x95, 0x66, 0xd4, 0xfb, 0xba, 0xa7, 0xd7, 0xa3, 0x72, 0x69, 0x48, 0x48, 0x8c, 0xeb, 0x28, 0x89, 0xfe, 0x33, 0x65, 0x5a, 0x36, 0x01, 0x7e, 0x06, 0x79, 0x0a, 0x09, 0x3b, 0x74, 0x11, 0x9a, 0x6e, 0xbf, 0xd4, 0x9e, 0x58, 0x90, 0x49, 0x4f, 0x4d, 0x08, 0xd4, 0xe5, 0x4a, 0x09, 0x21, 0xef, 0x8b, 0xb8, 0x74, 0x3b, 0x91, 0xdd, 0x36, 0x85, 0x60, 0x2d, 0xfa, 0xd4, 0x45, 0x7b, 0x45, 0x53, 0xf5, 0x47, 0x87, 0x7e, 0xa6, 0x37, 0xc8, 0x78, 0x7a, 0x68, 0x9d, 0x8d, 0x65, 0x2c, 0x0e, 0x91, 0x5c, 0xa2, 0x60, 0xf0, 0x8e, 0x3f, 0xe9, 0x1a, 0xcd, 0xaa, 0xe7, 0xd5, 0x77, 0x18, 0xaf, 0xc9, 0xbc, 0x18, 0xea, 0x48, 0x1b, 0xfb, 0x22, 0x48, 0x70, 0x16, 0x29, 0x9e, 0x5b, 0xc1, 0x2c, 0x66, 0x23, 0xbc, 0xf0, 0x1f, 0xef, 0xaf, 0xe4, 0xd6, 0x04, 0x19, 0x82, 0x7a, 0x0b, 0xba, 0x4b, 0x46, 0xb1, 0x6a, 0x85, 0x5d, 0xb4, 0x73, 0xd6, 0x21, 0xa1, 0x71, 0x60, 0x14, 0xee, 0x0a, 0x77, 0xc4, 0x66, 0x2e, 0xf9, 0x69, 0x30, 0xaf, 0x41, 0x0b, 0xc8, 0x83, 0x3c, 0x53, 0x99, 0x19, 0x27, 0x46, 0xf7, 0x41, 0x6e, 0x56, 0xdc, 0x94, 0x28, 0x67, 0x4e, 0xb7, 0x25, 0x48, 0x8a, 0xc2, 0xe0, 0x60, 0x96, 0xcc, 0x18, 0xf4, 0x84, 0xdd, 0xa7, 0x5e, 0x3e, 0x05, 0x0b, 0x26, 0x26, 0xb2, 0x5c, 0x1f, 0x57, 0x1a, 0x04, 0x7e, 0x6a, 0xe3, 0x2f, 0xb4, 0x35, 0xb6, 0x38, 0x40, 0x40, 0xcd, 0x6f, 0x87, 0x2e, 0xef, 0xa3, 0xd7, 0xa9, 0xc2, 0xe8, 0x0d, 0x27, 0xdf, 0x44, 0x62, 0x99, 0xa0, 0xfc, 0xcf, 0x81, 0x78, 0xcb, 0xfe, 0xe5, 0xa0, 0x03, 0x4e, 0x6c, 0xd7, 0xf4, 0xaf, 0x7a, 0xbb, 0x61, 0x82, 0xfe, 0x71, 0x89, 0xb2, 0x22, 0x7c, 0x8e, 0x83, 0x04, 0xce, 0xf6, 0x5d, 0x84, 0x8f, 0x95, 0x6a, 0x7f, 0xad, 0xfd, 0x32, 0x9c, 0x5e, 0xe4, 0x9c, 0x89, 0x60, 0x54, 0xaa, 0x96, 0x72, 0xd2, 0xd7, 0x36, 0x85, 0xa9, 0x45, 0xd2, 0x2a, 0xa1, 0x81, 0x49, 0x6f, 0x7e, 0x04, 0xfa, 0xe2, 0xfe, 0x90, 0x26, 0x77, 0x5a, 0x33, 0xb8, 0x04, 0x9a, 0x7a, 0xe6, 0x4c, 0x4f, 0xad, 0x72, 0x96, 0x08, 0x28, 0x58, 0x13, 0xf8, 0xc4, 0x1c, 0xf0, 0xc3, 0x45, 0x95, 0x49, 0x20, 0x8c, 0x9f, 0x39, 0x70, 0xe1, 0x77, 0xfe, 0xd5, 0x4b, 0xaf, 0x86, 0xda, 0xef, 0x22, 0x06, 0x83, 0x36, 0x29, 0x12, 0x11, 0x40, 0xbc, 0x3b, 0x86, 0xaa, 0xaa, 0x65, 0x60, 0xc3, 0x80, 0xca, 0xed, 0xa9, 0xf3, 0xb0, 0x79, 0x96, 0xa2, 0x55, 0x27, 0x28, 0x55, 0x73, 0x26, 0xa5, 0x50, 0xea, 0x92, 0x4b, 0x3c, 0x5c, 0x82, 0x33, 0xf0, 0x01, 0x3f, 0x03, 0xc1, 0x08, 0x05, 0xbf, 0x98, 0xf4, 0x9b, 0x6d, 0xa5, 0xa8, 0xb4, 0x82, 0x0c, 0x06, 0xfa, 0xff, 0x2d, 0x08, 0xf3, 0x05, 0x4f, 0x57, 0x2a, 0x39, 0xd4, 0x83, 0x0d, 0x75, 0x51, 0xd8, 0x5b, 0x1b, 0xd3, 0x51, 0x5a, 0x32, 0x2a, 0x9b, 0x32, 0xb2, 0xf2, 0xa4, 0x96, 0x12, 0xf2, 0xae, 0x40, 0x34, 0x67, 0xa8, 0xf5, 0x44, 0xd5, 0x35, 0x53, 0xfe, 0xa3, 0x60, 0x96, 0x63, 0x0f, 0x1f, 0x6e, 0xb0, 0x5a, 0x42, 0xa6, 0xfc, 0x51, 0x0b, 0x60, 0x27, 0xbc, 0x06, 0x71, 0xed, 0x65, 0x5b, 0x23, 0x86, 0x4a, 0x07, 0x3b, 0x22, 0x07, 0x46, 0xe6, 0x90, 0x3e, 0xf3, 0x25, 0x50, 0x1b, 0x4c, 0x7f, 0x03, 0x08, 0xa8, 0x36, 0x6b, 0x87, 0xe5, 0xe3, 0xdb, 0x9a, 0x38, 0x83, 0xff, 0x9f, 0x1a, 0x9f, 0x57, 0xa4, 0x2a, 0xf6, 0x37, 0xbc, 0x1a, 0xff, 0xc9, 0x1e, 0x35, 0x0c, 0xc3, 0x7c, 0xa3, 0xb2, 0xe5, 0xd2, 0xc6, 0xb4, 0x57, 0x47, 0xe4, 0x32, 0x16, 0x6d, 0xa9, 0xae, 0x64, 0xe6, 0x2d, 0x8d, 0xc5, 0x8d, 0x50, 0x8e, 0xe8, 0x1a, 0x22, 0x34, 0x2a, 0xd9, 0xeb, 0x51, 0x90, 0x4a, 0xb1, 0x41, 0x7d, 0x64, 0xf9, 0xb9, 0x0d, 0xf6, 0x23, 0x33, 0xb0, 0x33, 0xf4, 0xf7, 0x3f, 0x27, 0x84, 0xc6, 0x0f, 0x54, 0xa5, 0xc0, 0x2e, 0xec, 0x0b, 0x3a, 0x48, 0x6e, 0x80, 0x35, 0x81, 0x43, 0x9b, 0x90, 0xb1, 0xd0, 0x2b, 0xea, 0x21, 0xdc, 0xda, 0x5b, 0x09, 0xf4, 0xcc, 0x10, 0xb4, 0xc7, 0xfe, 0x79, 0x51, 0xc3, 0xc5, 0xac, 0x88, 0x74, 0x84, 0x0b, 0x4b, 0xca, 0x79, 0x16, 0x29, 0xfb, 0x69, 0x54, 0xdf, 0x41, 0x7e, 0xe9, 0xc7, 0x8e, 0xea, 0xa5, 0xfe, 0xfc, 0x76, 0x0e, 0x90, 0xc4, 0x92, 0x38, 0xad, 0x7b, 0x48, 0xe6, 0x6e, 0xf7, 0x21, 0xfd, 0x4e, 0x93, 0x0a, 0x7b, 0x41, 0x83, 0x68, 0xfb, 0x57, 0x51, 0x76, 0x34, 0xa9, 0x6c, 0x00, 0xaa, 0x4f, 0x66, 0x65, 0x98, 0x4a, 0x4f, 0xa3, 0xa0, 0xef, 0x69, 0x3f, 0xe3, 0x1c, 0x92, 0x8c, 0xfd, 0xd8, 0xe8, 0xde, 0x7c, 0x7f, 0x3e, 0x84, 0x8e, 0x69, 0x3c, 0xf1, 0xf2, 0x05, 0x46, 0xdc, 0x2f, 0x9d, 0x5e, 0x6e, 0x4c, 0xfb, 0xb5, 0x99, 0x2a, 0x59, 0x63, 0xc1, 0x34, 0xbc, 0x57, 0xc0, 0x0d, 0xb9, 0x61, 0x25, 0xf3, 0x33, 0x23, 0x51, 0xb6, 0x0d, 0x07, 0xa6, 0xab, 0x94, 0x4a, 0xb7, 0x2a, 0xea, 0xee, 0xac, 0xa3, 0xc3, 0x04, 0x8b, 0x0e, 0x56, 0xfe, 0x44, 0xa7, 0x39, 0xe2, 0xed, 0xed, 0xb4, 0x22, 0x2b, 0xac, 0x12, 0x32, 0x28, 0x91, 0xd8, 0xa5, 0xab, 0xff, 0x5f, 0xe0, 0x4b, 0xda, 0x78, 0x17, 0xda, 0xf1, 0x01, 0x5b, 0xcd, 0xe2, 0x5f, 0x50, 0x45, 0x73, 0x2b, 0xe4, 0x76, 0x77, 0xf4, 0x64, 0x1d, 0x43, 0xfb, 0x84, 0x7a, 0xea, 0x91, 0xae, 0xf9, 0x9e, 0xb7, 0xb4, 0xb0, 0x91, 0x5f, 0x16, 0x35, 0x9a, 0x11, 0xb8, 0xc7, 0xc1, 0x8c, 0xc6, 0x10, 0x8d, 0x2f, 0x63, 0x4a, 0xa7, 0x57, 0x3a, 0x51, 0xd6, 0x32, 0x2d, 0x64, 0x72, 0xd4, 0x66, 0xdc, 0x10, 0xa6, 0x67, 0xd6, 0x04, 0x23, 0x9d, 0x0a, 0x11, 0x77, 0xdd, 0x37, 0x94, 0x17, 0x3c, 0xbf, 0x8b, 0x65, 0xb0, 0x2e, 0x5e, 0x66, 0x47, 0x64, 0xac, 0xdd, 0xf0, 0x84, 0xfd, 0x39, 0xfa, 0x15, 0x5d, 0xef, 0xae, 0xca, 0xc1, 0x36, 0xa7, 0x5c, 0xbf, 0xc7, 0x08, 0xc2, 0x66, 0x00, 0x74, 0x74, 0x4e, 0x27, 0x3f, 0x55, 0x8a, 0xb7, 0x38, 0x66, 0x83, 0x6d, 0xcf, 0x99, 0x9e, 0x60, 0x8f, 0xdd, 0x2e, 0x62, 0x22, 0x0e, 0xef, 0x0c, 0x98, 0xa7, 0x85, 0x74, 0x3b, 0x9d, 0xec, 0x9e, 0xa9, 0x19, 0x72, 0xa5, 0x7f, 0x2c, 0x39, 0xb7, 0x7d, 0xb7, 0xf1, 0x12, 0x65, 0x27, 0x4b, 0x5a, 0xde, 0x17, 0xfe, 0xad, 0x44, 0xf3, 0x20, 0x4d, 0xfd, 0xe4, 0x1f, 0xb5, 0x81, 0xb0, 0x36, 0x37, 0x08, 0x6f, 0xc3, 0x0c, 0xe9, 0x85, 0x98, 0x82, 0xa9, 0x62, 0x0c, 0xc4, 0x97, 0xc0, 0x50, 0xc8, 0xa7, 0x3c, 0x50, 0x9f, 0x43, 0xb9, 0xcd, 0x5e, 0x4d, 0xfa, 0x1c, 0x4b, 0x0b, 0xa9, 0x98, 0x85, 0x38, 0x92, 0xac, 0x8d, 0xe4, 0xad, 0x9b, 0x98, 0xab, 0xd9, 0x38, 0xac, 0x62, 0x52, 0xa3, 0x22, 0x63, 0x0f, 0xbf, 0x95, 0x48, 0xdf, 0x69, 0xe7, 0x8b, 0x33, 0xd5, 0xb2, 0xbd, 0x05, 0x49, 0x49, 0x9d, 0x57, 0x73, 0x19, 0x33, 0xae, 0xfa, 0x33, 0xf1, 0x19, 0xa8, 0x80, 0xce, 0x04, 0x9f, 0xbc, 0x1d, 0x65, 0x82, 0x1b, 0xe5, 0x3a, 0x51, 0xc8, 0x1c, 0x21, 0xe3, 0x5d, 0xf3, 0x7d, 0x9b, 0x2f, 0x2c, 0x1d, 0x4a, 0x7f, 0x9b, 0x68, 0x35, 0xa3, 0xb2, 0x50, 0xf7, 0x62, 0x79, 0xcd, 0xf4, 0x98, 0x4f, 0xe5, 0x63, 0x7c, 0x3e, 0x45, 0x31, 0x8c, 0x16, 0xa0, 0x12, 0xc8, 0x58, 0xce, 0x39, 0xa6, 0xbc, 0x54, 0xdb, 0xc5, 0xe0, 0xd5, 0xba, 0xbc, 0xb9, 0x04, 0xf4, 0x8d, 0xe8, 0x2f, 0x15, 0x9d, }; /* 100 test cases */ static struct crc_test { uint32_t crc; /* random starting crc */ uint32_t start; /* random 6 bit offset in buf */ uint32_t length; /* random 11 bit length of test */ uint32_t crc32c_le; /* expected crc32c_le result */ } test[] = { {0x674bf11d, 0x00000038, 0x00000542, 0xf6e93d6c}, {0x35c672c6, 0x0000003a, 0x000001aa, 0x0fe92aca}, {0x496da28e, 0x00000039, 0x000005af, 0x52e1ebb8}, {0x09a9b90e, 0x00000027, 0x000001f8, 0x0798af9a}, {0xdc97e5a9, 0x00000025, 0x000003b6, 0x18eb3152}, {0x47c58900, 0x0000000a, 0x000000b9, 0xd00d08c7}, {0x292561e8, 0x0000000c, 0x00000403, 0x8ba966bc}, {0x415037f6, 0x00000003, 0x00000676, 0x11d694a2}, {0x3466e707, 0x00000026, 0x00000042, 0x6ab3208d}, {0xafd1281b, 0x00000023, 0x000002ee, 0xba4603c5}, {0xd3857b18, 0x00000028, 0x000004a2, 0xe6071c6f}, {0x1d825a8f, 0x0000002b, 0x0000050b, 0x179ec30a}, {0x5033e3bc, 0x0000000b, 0x00000078, 0x0903beb8}, {0x94f1fb5e, 0x0000000f, 0x000003a2, 0x6a7cb4fa}, {0xc9a0fe14, 0x00000009, 0x00000473, 0xdb535801}, {0x88a034b1, 0x0000001c, 0x000005ad, 0x92bed597}, {0xf0f72239, 0x00000020, 0x0000026d, 0x192a3f1b}, {0xcc20a5e3, 0x0000003b, 0x0000067a, 0xccbaec1a}, {0xce589c95, 0x0000002b, 0x00000641, 0x7eabae4d}, {0x78edc885, 0x00000035, 0x000005be, 0x28c72982}, {0x9d40a377, 0x0000003b, 0x00000038, 0xc3cd4d18}, {0x703d0e01, 0x0000003c, 0x000006f1, 0xbca8f0e7}, {0x776bf505, 0x0000000f, 0x000005b2, 0x713f60b3}, {0x4a3e7854, 0x00000027, 0x000004b8, 0xebd08fd5}, {0x209172dd, 0x0000003b, 0x00000356, 0x64406c59}, {0x3ba4cc5b, 0x0000002f, 0x00000203, 0x7421890e}, {0xfc62f297, 0x00000000, 0x00000079, 0xe9347603}, {0x64280b8b, 0x00000016, 0x000007ab, 0x1bef9060}, {0x97dd724b, 0x00000033, 0x000007ad, 0x34720072}, {0x61394b52, 0x00000035, 0x00000571, 0x48310f59}, {0x29b4faff, 0x00000024, 0x0000006e, 0x783a4213}, {0x29bfb1dc, 0x0000000b, 0x00000244, 0x9e8efd41}, {0x86ae934b, 0x00000035, 0x00000104, 0xfc3d34a5}, {0xc4c1024e, 0x0000002e, 0x000006b1, 0x17a52ae2}, {0x3287a80a, 0x00000026, 0x00000496, 0x886d935a}, {0xa4db423e, 0x00000023, 0x0000045d, 0xeaaeaeb2}, {0x7a1078df, 0x00000015, 0x0000014a, 0x8e900a4b}, {0x6048bd5b, 0x00000006, 0x0000006a, 0xd74662b1}, {0xd8f9ea20, 0x0000003d, 0x00000277, 0xd26752ba}, {0xea5ec3b4, 0x0000002a, 0x000004fe, 0x8b1fcd62}, {0x2dfb005d, 0x00000016, 0x00000345, 0xf54342fe}, {0x5a214ade, 0x00000020, 0x000005b6, 0x5b95b988}, {0xf0ab9cca, 0x00000032, 0x00000515, 0x2e1176be}, {0x91b444f9, 0x0000002e, 0x000007f8, 0x66120546}, {0x1b5d2ddb, 0x0000002e, 0x0000012c, 0xf256a5cc}, {0xd824d1bb, 0x0000003a, 0x000007b5, 0x4af1dd69}, {0x0470180c, 0x00000034, 0x000001f0, 0x56f0a04a}, {0xffaa3a3f, 0x00000036, 0x00000299, 0x74f6b6b2}, {0x6406cfeb, 0x00000023, 0x00000600, 0x085951fd}, {0xb24aaa38, 0x0000003e, 0x000004a1, 0xc65387eb}, {0x58b2ab7c, 0x00000039, 0x000002b4, 0x1ca9257b}, {0x3db85970, 0x00000006, 0x000002b6, 0xfd196d76}, {0x857830c5, 0x00000003, 0x00000590, 0x5ef88339}, {0xe1fcd978, 0x0000003e, 0x000007d8, 0x2c3714d9}, {0xb982a768, 0x00000016, 0x000006e0, 0x58576548}, {0x1d581ce8, 0x0000001e, 0x0000058b, 0xfd7c57de}, {0x2456719b, 0x00000025, 0x00000503, 0xd5fedd59}, {0xfae6d8f2, 0x00000000, 0x0000055d, 0x1cc3b17b}, {0xcba828e3, 0x00000039, 0x000002ce, 0x270eed73}, {0x13d25952, 0x0000000a, 0x0000072d, 0x91ecbb11}, {0x0342be3f, 0x00000015, 0x00000599, 0x05ed8d0c}, {0xeaa344e0, 0x00000014, 0x000004d8, 0x0b09ad5b}, {0xbbb52021, 0x0000003b, 0x00000272, 0xf8d511fb}, {0xb66384dc, 0x0000001d, 0x000007fc, 0x5ad832cc}, {0x616c01b6, 0x00000022, 0x000002c8, 0x1214d196}, {0xce2bdaad, 0x00000016, 0x0000062a, 0x5747218a}, {0x00fe84d7, 0x00000005, 0x00000205, 0xde8f14de}, {0xbebdcb4c, 0x00000006, 0x0000055d, 0x3563b7b9}, {0xd8b1a02a, 0x00000010, 0x00000387, 0x071475d0}, {0x3b96cad2, 0x00000036, 0x00000347, 0x54c79d60}, {0xc94c1ed7, 0x00000005, 0x0000038b, 0x4c53eee6}, {0x1aad454e, 0x00000025, 0x000002b2, 0x10137a3c}, {0xa4fec9a6, 0x00000000, 0x000006d6, 0xaa9d6c73}, {0x1bbe71e2, 0x0000001f, 0x000002fd, 0xb63d23e7}, {0x4201c7e4, 0x00000002, 0x000002b7, 0x7f53e9cf}, {0x23fddc96, 0x00000003, 0x00000627, 0x13c1cd83}, {0xd82ba25c, 0x00000016, 0x0000063e, 0x49ff5867}, {0x786f2032, 0x0000002d, 0x0000060f, 0x8467f211}, {0xfebe4e1f, 0x0000002a, 0x000004f2, 0x3f9683b2}, {0x1a6e0a39, 0x00000008, 0x00000672, 0x76a3f874}, {0x56000ab8, 0x0000000e, 0x000000e5, 0x863b702f}, {0x4717fe0c, 0x00000000, 0x000006ec, 0xdc6c58ff}, {0xd5d5d68e, 0x0000003c, 0x000003a3, 0x0622cc95}, {0xc25dd6c6, 0x00000024, 0x000006c0, 0xe85605cd}, {0xe9b11300, 0x00000023, 0x00000683, 0x31da5f06}, {0x95cd285e, 0x00000001, 0x00000047, 0xa1f2e784}, {0xd9245a25, 0x0000001e, 0x000003a6, 0xb07cc616}, {0x103279db, 0x00000006, 0x0000039b, 0xbf943b6c}, {0x1cba3172, 0x00000027, 0x000001c8, 0x2c01af1c}, {0x8f613739, 0x0000000c, 0x000001df, 0x0fe5f56d}, {0x1c6aa90d, 0x0000001b, 0x0000053c, 0xf8943b2d}, {0xaabe5b93, 0x0000003d, 0x00000715, 0xe4d89272}, {0xf15dd038, 0x00000006, 0x000006db, 0x7c2f6bbb}, {0x584dd49c, 0x00000020, 0x000007bc, 0xabbf388b}, {0x5d8c9506, 0x00000020, 0x00000470, 0x1dca1f4e}, {0xb80d17b0, 0x00000032, 0x00000346, 0x5c170e23}, {0xdaf0592e, 0x00000023, 0x000007b0, 0xc0e9d672}, {0x4793cc85, 0x0000000d, 0x00000706, 0xc18bdc86}, {0x82ebf64e, 0x00000009, 0x000007c3, 0xa874fcdd}, {0xb18a0319, 0x00000026, 0x000007db, 0x9dc0bb48}, }; static int crc32c_test(void) { int i; int errors = 0; int bytes = 0; struct timeval start, stop; uint64_t usec; /* keep static to prevent cache warming code from * getting eliminated by the compiler */ static uint32_t crc; /* pre-warm the cache */ for (i = 0; i < 100; i++) { bytes += 2*test[i].length; crc ^= crc32c_le(test[i].crc, test_buf + test[i].start, test[i].length); } gettimeofday(&start, NULL); for (i = 0; i < 100; i++) { if (test[i].crc32c_le != crc32c_le(test[i].crc, test_buf + test[i].start, test[i].length)) errors++; } gettimeofday(&stop, NULL); usec = stop.tv_usec - start.tv_usec + 1000000 * (stop.tv_sec - start.tv_sec); if (errors) printf("crc32c: %d self tests failed\n", errors); else { printf("crc32c: tests passed, %d bytes in %" PRIu64 " usec\n", bytes, usec); } return errors; } #endif /* __LIBFROG_CRC32CSELFTEST_H__ */ xfsprogs-5.3.0/libfrog/crc32defs.h0000644000175000017500000000416513435336036016633 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Use slice-by-8, which is the fastest variant. * * Calculate checksum 8 bytes at a time with a clever slicing algorithm. * This is the fastest algorithm, but comes with a 8KiB lookup table. * Most modern processors have enough cache to hold this table without * thrashing the cache. * * The Linux kernel uses this as the default implementation "unless you * have a good reason not to". The reason why Kconfig urges you to pick * SLICEBY8 is because people challenged the assertion that we should * always use slice by 8, so Darrick wrote a crc microbenchmark utility * and ran it on as many machines as he could get his hands on to show * that sb8 was the fastest. * * Every 64-bit machine (and most of the 32-bit ones too) saw the best * results with sb8. Any machine with more than 4K of cache saw better * results. The spreadsheet still exists today[1]; note that * 'crc32-kern-le' corresponds to the slice by 4 algorithm which is the * default unless CRC_LE_BITS is defined explicitly. * * FWIW, there are a handful of board defconfigs in the kernel that * don't pick sliceby8. These are all embedded 32-bit mips/ppc systems * with very small cache sizes which experience cache thrashing with the * slice by 8 algorithm, and therefore chose to pick defaults that are * saner for their particular board configuration. For nearly all of * XFS' perceived userbase (which we assume are 32 and 64-bit machines * with sufficiently large CPU cache and largeish storage devices) slice * by 8 is the right choice. * * [1] https://goo.gl/0LSzsG ("crc32c_bench") */ #define CRC_LE_BITS 64 /* * This is the CRC32c polynomial, as outlined by Castagnoli. * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+ * x^8+x^6+x^0 */ #define CRC32C_POLY_LE 0x82F63B78 /* * Little-endian CRC computation. Used with serial bit streams sent * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC. */ #if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \ CRC_LE_BITS & CRC_LE_BITS-1 # error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}" #endif xfsprogs-5.3.0/libfrog/fsgeom.c0000644000175000017500000001075113570057155016330 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. */ #include "libxfs.h" #include "fsgeom.h" #include "util.h" void xfs_report_geom( struct xfs_fsop_geom *geo, const char *mntpoint, const char *logname, const char *rtname) { int isint; int lazycount; int dirversion; int logversion; int attrversion; int projid32bit; int crcs_enabled; int cimode; int ftype_enabled; int finobt_enabled; int spinodes; int rmapbt_enabled; int reflink_enabled; isint = geo->logstart > 0; lazycount = geo->flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0; dirversion = geo->flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1; logversion = geo->flags & XFS_FSOP_GEOM_FLAGS_LOGV2 ? 2 : 1; attrversion = geo->flags & XFS_FSOP_GEOM_FLAGS_ATTR2 ? 2 : \ (geo->flags & XFS_FSOP_GEOM_FLAGS_ATTR ? 1 : 0); cimode = geo->flags & XFS_FSOP_GEOM_FLAGS_DIRV2CI ? 1 : 0; projid32bit = geo->flags & XFS_FSOP_GEOM_FLAGS_PROJID32 ? 1 : 0; crcs_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_V5SB ? 1 : 0; ftype_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0; finobt_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_FINOBT ? 1 : 0; spinodes = geo->flags & XFS_FSOP_GEOM_FLAGS_SPINODES ? 1 : 0; rmapbt_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_RMAPBT ? 1 : 0; reflink_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_REFLINK ? 1 : 0; printf(_( "meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u\n" " =%-22s reflink=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d\n" "log =%-22s bsize=%-6d blocks=%u, version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"), mntpoint, geo->inodesize, geo->agcount, geo->agblocks, "", geo->sectsize, attrversion, projid32bit, "", crcs_enabled, finobt_enabled, spinodes, rmapbt_enabled, "", reflink_enabled, "", geo->blocksize, (unsigned long long)geo->datablocks, geo->imaxpct, "", geo->sunit, geo->swidth, dirversion, geo->dirblocksize, cimode, ftype_enabled, isint ? _("internal log") : logname ? logname : _("external"), geo->blocksize, geo->logblocks, logversion, "", geo->logsectsize, geo->logsunit / geo->blocksize, lazycount, !geo->rtblocks ? _("none") : rtname ? rtname : _("external"), geo->rtextsize * geo->blocksize, (unsigned long long)geo->rtblocks, (unsigned long long)geo->rtextents); } /* Try to obtain the xfs geometry. On error returns a negative error code. */ int xfrog_geometry( int fd, struct xfs_fsop_geom *fsgeo) { int ret; memset(fsgeo, 0, sizeof(*fsgeo)); ret = ioctl(fd, XFS_IOC_FSGEOMETRY, fsgeo); if (!ret) return 0; ret = ioctl(fd, XFS_IOC_FSGEOMETRY_V4, fsgeo); if (!ret) return 0; ret = ioctl(fd, XFS_IOC_FSGEOMETRY_V1, fsgeo); if (!ret) return 0; return -errno; } /* * Prepare xfs_fd structure for future ioctl operations by computing the xfs * geometry for @xfd->fd. Returns zero or a negative error code. */ int xfd_prepare_geometry( struct xfs_fd *xfd) { int ret; ret = xfrog_geometry(xfd->fd, &xfd->fsgeom); if (ret) return ret; xfd->agblklog = log2_roundup(xfd->fsgeom.agblocks); xfd->blocklog = highbit32(xfd->fsgeom.blocksize); xfd->inodelog = highbit32(xfd->fsgeom.inodesize); xfd->inopblog = xfd->blocklog - xfd->inodelog; xfd->aginolog = xfd->agblklog + xfd->inopblog; xfd->blkbb_log = xfd->blocklog - BBSHIFT; return 0; } /* Open a file on an XFS filesystem. Returns zero or a negative error code. */ int xfd_open( struct xfs_fd *xfd, const char *pathname, int flags) { int ret; xfd->fd = open(pathname, flags); if (xfd->fd < 0) return -errno; ret = xfd_prepare_geometry(xfd); if (ret) { xfd_close(xfd); return ret; } return 0; } /* * Release any resources associated with this xfs_fd structure. Returns zero * or a negative error code. */ int xfd_close( struct xfs_fd *xfd) { int ret = 0; if (xfd->fd < 0) return 0; ret = close(xfd->fd); xfd->fd = -1; if (ret < 0) return -errno; return 0; } /* Try to obtain an AG's geometry. Returns zero or a negative error code. */ int xfrog_ag_geometry( int fd, unsigned int agno, struct xfs_ag_geometry *ageo) { int ret; ageo->ag_number = agno; ret = ioctl(fd, XFS_IOC_AG_GEOMETRY, ageo); if (ret) return -errno; return 0; } xfsprogs-5.3.0/libfrog/fsgeom.h0000644000175000017500000001064013570057155016332 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef __LIBFROG_FSGEOM_H__ #define __LIBFROG_FSGEOM_H__ void xfs_report_geom(struct xfs_fsop_geom *geo, const char *mntpoint, const char *logname, const char *rtname); int xfrog_geometry(int fd, struct xfs_fsop_geom *fsgeo); int xfrog_ag_geometry(int fd, unsigned int agno, struct xfs_ag_geometry *ageo); /* * Structure for recording whatever observations we want about the level of * xfs runtime support for this fd. Right now we only store the fd and fs * geometry. */ struct xfs_fd { /* ioctl file descriptor */ int fd; /* filesystem geometry */ struct xfs_fsop_geom fsgeom; /* log2 of sb_agblocks (rounded up) */ unsigned int agblklog; /* log2 of sb_blocksize */ unsigned int blocklog; /* log2 of sb_inodesize */ unsigned int inodelog; /* log2 of sb_inopblock */ unsigned int inopblog; /* bits for agino in inum */ unsigned int aginolog; /* log2 of sb_blocksize / sb_sectsize */ unsigned int blkbb_log; /* XFROG_FLAG_* state flags */ unsigned int flags; }; /* Only use v1 bulkstat/inumbers ioctls. */ #define XFROG_FLAG_BULKSTAT_FORCE_V1 (1 << 0) /* Only use v5 bulkstat/inumbers ioctls. */ #define XFROG_FLAG_BULKSTAT_FORCE_V5 (1 << 1) /* Static initializers */ #define XFS_FD_INIT(_fd) { .fd = (_fd), } #define XFS_FD_INIT_EMPTY XFS_FD_INIT(-1) int xfd_prepare_geometry(struct xfs_fd *xfd); int xfd_open(struct xfs_fd *xfd, const char *pathname, int flags); int xfd_close(struct xfs_fd *xfd); /* Convert AG number and AG inode number into fs inode number. */ static inline uint64_t cvt_agino_to_ino( const struct xfs_fd *xfd, uint32_t agno, uint32_t agino) { return ((uint64_t)agno << xfd->aginolog) + agino; } /* Convert fs inode number into AG number. */ static inline uint32_t cvt_ino_to_agno( const struct xfs_fd *xfd, uint64_t ino) { return ino >> xfd->aginolog; } /* Convert fs inode number into AG inode number. */ static inline uint32_t cvt_ino_to_agino( const struct xfs_fd *xfd, uint64_t ino) { return ino & ((1ULL << xfd->aginolog) - 1); } /* * Convert a linear fs block offset number into bytes. This is the runtime * equivalent of XFS_FSB_TO_B, which means that it is /not/ for segmented fsbno * format (= agno | agbno) that we use internally for the data device. */ static inline uint64_t cvt_off_fsb_to_b( const struct xfs_fd *xfd, uint64_t fsb) { return fsb << xfd->blocklog; } /* * Convert bytes into a (rounded down) linear fs block offset number. This is * the runtime equivalent of XFS_B_TO_FSBT. It does not produce segmented * fsbno numbers (= agno | agbno). */ static inline uint64_t cvt_b_to_off_fsbt( const struct xfs_fd *xfd, uint64_t bytes) { return bytes >> xfd->blocklog; } /* Convert sector number to bytes. */ static inline uint64_t cvt_bbtob( uint64_t daddr) { return daddr << BBSHIFT; } /* Convert bytes to sector number, rounding down. */ static inline uint64_t cvt_btobbt( uint64_t bytes) { return bytes >> BBSHIFT; } /* Convert fs block number to sector number. */ static inline uint64_t cvt_off_fsb_to_bb( struct xfs_fd *xfd, uint64_t fsbno) { return fsbno << xfd->blkbb_log; } /* Convert sector number to fs block number, rounded down. */ static inline uint64_t cvt_bb_to_off_fsbt( struct xfs_fd *xfd, uint64_t daddr) { return daddr >> xfd->blkbb_log; } /* Convert AG number and AG block to fs block number */ static inline uint64_t cvt_agb_to_daddr( struct xfs_fd *xfd, uint32_t agno, uint32_t agbno) { return cvt_off_fsb_to_bb(xfd, (uint64_t)agno * xfd->fsgeom.agblocks + agbno); } /* Convert sector number to AG number. */ static inline uint32_t cvt_daddr_to_agno( struct xfs_fd *xfd, uint64_t daddr) { return cvt_bb_to_off_fsbt(xfd, daddr) / xfd->fsgeom.agblocks; } /* Convert sector number to AG block number. */ static inline uint32_t cvt_daddr_to_agbno( struct xfs_fd *xfd, uint64_t daddr) { return cvt_bb_to_off_fsbt(xfd, daddr) % xfd->fsgeom.agblocks; } /* Convert AG number and AG block to a byte location on disk. */ static inline uint64_t cvt_agbno_to_b( struct xfs_fd *xfd, xfs_agnumber_t agno, xfs_agblock_t agbno) { return cvt_bbtob(cvt_agb_to_daddr(xfd, agno, agbno)); } /* Convert byte location on disk to AG block. */ static inline xfs_agblock_t cvt_b_to_agbno( struct xfs_fd *xfd, uint64_t byteno) { return cvt_daddr_to_agbno(xfd, cvt_btobbt(byteno)); } #endif /* __LIBFROG_FSGEOM_H__ */ xfsprogs-5.3.0/libfrog/gen_crc32table.c0000644000175000017500000000343013435336036017617 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #include #include "crc32defs.h" #include #define ENTRIES_PER_LINE 4 #if CRC_LE_BITS > 8 # define LE_TABLE_ROWS (CRC_LE_BITS/8) # define LE_TABLE_SIZE 256 #else # define LE_TABLE_ROWS 1 # define LE_TABLE_SIZE (1 << CRC_LE_BITS) #endif static uint32_t crc32ctable_le[LE_TABLE_ROWS][256]; /** * crc32init_le() - allocate and initialize LE table data * * crc is the crc of the byte i; other entries are filled in based on the * fact that crctable[i^j] = crctable[i] ^ crctable[j]. * */ static void crc32init_le_generic(const uint32_t polynomial, uint32_t (*tab)[256]) { unsigned i, j; uint32_t crc = 1; tab[0][0] = 0; for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) { crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); for (j = 0; j < LE_TABLE_SIZE; j += 2 * i) tab[0][i + j] = crc ^ tab[0][j]; } for (i = 0; i < LE_TABLE_SIZE; i++) { crc = tab[0][i]; for (j = 1; j < LE_TABLE_ROWS; j++) { crc = tab[0][crc & 0xff] ^ (crc >> 8); tab[j][i] = crc; } } } static void crc32cinit_le(void) { crc32init_le_generic(CRC32C_POLY_LE, crc32ctable_le); } static void output_table(uint32_t (*table)[256], int rows, int len, char *trans) { int i, j; for (j = 0 ; j < rows; j++) { printf("{"); for (i = 0; i < len - 1; i++) { if (i % ENTRIES_PER_LINE == 0) printf("\n"); printf("%s(0x%8.8xL), ", trans, table[j][i]); } printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]); } } int main(int argc, char** argv) { printf("/* this file is generated - do not edit */\n\n"); if (CRC_LE_BITS > 1) { crc32cinit_le(); printf("static u32 crc32ctable_le[%d][%d] = {", LE_TABLE_ROWS, LE_TABLE_SIZE); output_table(crc32ctable_le, LE_TABLE_ROWS, LE_TABLE_SIZE, "tole"); printf("};\n"); } return 0; } xfsprogs-5.3.0/libfrog/linux.c0000644000175000017500000001306613570057155016211 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include #include #include "libxfs_priv.h" #include "xfs_fs.h" #include "init.h" extern char *progname; static int max_block_alignment; #ifndef BLKGETSIZE64 # define BLKGETSIZE64 _IOR(0x12,114,size_t) #endif #ifndef BLKBSZSET # define BLKBSZSET _IOW(0x12,113,size_t) #endif #ifndef BLKSSZGET # define BLKSSZGET _IO(0x12,104) #endif #ifndef RAMDISK_MAJOR #define RAMDISK_MAJOR 1 /* ramdisk major number */ #endif #define PROC_MOUNTED "/proc/mounts" /* * Check if the filesystem is mounted. Be verbose if asked, and * optionally restrict check to /writable/ mounts (i.e. RO is OK) */ #define CHECK_MOUNT_VERBOSE 0x1 #define CHECK_MOUNT_WRITABLE 0x2 static int platform_check_mount(char *name, char *block, struct stat *s, int flags) { FILE *f; struct stat st, mst; struct mntent *mnt; char mounts[MAXPATHLEN]; if (!s) { /* If either fails we are not mounted */ if (stat(block, &st) < 0) return 0; if ((st.st_mode & S_IFMT) != S_IFBLK) return 0; s = &st; } strcpy(mounts, (!access(PROC_MOUNTED, R_OK)) ? PROC_MOUNTED : MOUNTED); if ((f = setmntent(mounts, "r")) == NULL) { /* Unexpected failure, warn unconditionally */ fprintf(stderr, _("%s: %s possibly contains a mounted filesystem\n"), progname, name); return 1; } /* * This whole business is to work out if our block device is mounted * after we lost ustat(2), see: * 4e7a824 libxfs/linux.c: Replace use of ustat by stat * We don't really want to stat every single mounted directory, * as that may include tmpfs, cgroups, procfs or - worst - hung nfs * servers. So first, a simple check: does the "dev" start with "/" ? */ while ((mnt = getmntent(f)) != NULL) { if (mnt->mnt_fsname[0] != '/') continue; if (stat(mnt->mnt_dir, &mst) < 0) continue; if (mst.st_dev != s->st_rdev) continue; /* Found our device, is RO OK? */ if ((flags & CHECK_MOUNT_WRITABLE) && hasmntopt(mnt, MNTOPT_RO)) continue; else break; } endmntent(f); /* No mounts contained the condition we were looking for */ if (mnt == NULL) return 0; if (flags & CHECK_MOUNT_VERBOSE) { if (flags & CHECK_MOUNT_WRITABLE) { fprintf(stderr, _("%s: %s contains a mounted and writable filesystem\n"), progname, name); } else { fprintf(stderr, _("%s: %s contains a mounted filesystem\n"), progname, name); } } return 1; } int platform_check_ismounted(char *name, char *block, struct stat *s, int verbose) { int flags; flags = verbose ? CHECK_MOUNT_VERBOSE : 0; return platform_check_mount(name, block, s, flags); } int platform_check_iswritable(char *name, char *block, struct stat *s) { int flags; /* Writable checks are always verbose */ flags = CHECK_MOUNT_WRITABLE | CHECK_MOUNT_VERBOSE; return platform_check_mount(name, block, s, flags); } int platform_set_blocksize(int fd, char *path, dev_t device, int blocksize, int fatal) { int error = 0; if (major(device) != RAMDISK_MAJOR) { if ((error = ioctl(fd, BLKBSZSET, &blocksize)) < 0) { fprintf(stderr, _("%s: %s - cannot set blocksize " "%d on block device %s: %s\n"), progname, fatal ? "error": "warning", blocksize, path, strerror(errno)); } } return error; } void platform_flush_device(int fd, dev_t device) { struct stat st; if (major(device) == RAMDISK_MAJOR) return; if (fstat(fd, &st) < 0) return; if (S_ISREG(st.st_mode)) fsync(fd); else ioctl(fd, BLKFLSBUF, 0); } void platform_findsizes(char *path, int fd, long long *sz, int *bsz) { struct stat st; uint64_t size; int error; if (fstat(fd, &st) < 0) { fprintf(stderr, _("%s: " "cannot stat the device file \"%s\": %s\n"), progname, path, strerror(errno)); exit(1); } if ((st.st_mode & S_IFMT) == S_IFREG) { struct dioattr da; *sz = (long long)(st.st_size >> 9); if (ioctl(fd, XFS_IOC_DIOINFO, &da) < 0) { /* * fall back to BBSIZE; mkfs might fail if there's a * size mismatch between the image & the host fs... */ *bsz = BBSIZE; } else *bsz = da.d_miniosz; if (*bsz > max_block_alignment) max_block_alignment = *bsz; return; } error = ioctl(fd, BLKGETSIZE64, &size); if (error >= 0) { /* BLKGETSIZE64 returns size in bytes not 512-byte blocks */ *sz = (long long)(size >> 9); } else { /* If BLKGETSIZE64 fails, try BLKGETSIZE */ unsigned long tmpsize; error = ioctl(fd, BLKGETSIZE, &tmpsize); if (error < 0) { fprintf(stderr, _("%s: can't determine device size\n"), progname); exit(1); } *sz = (long long)tmpsize; } if (ioctl(fd, BLKSSZGET, bsz) < 0) { fprintf(stderr, _("%s: warning - cannot get sector size " "from block device %s: %s\n"), progname, path, strerror(errno)); *bsz = BBSIZE; } if (*bsz > max_block_alignment) max_block_alignment = *bsz; } char * platform_findrawpath(char *path) { return path; } char * platform_findblockpath(char *path) { return path; } int platform_direct_blockdev(void) { return 1; } int platform_align_blockdev(void) { if (!max_block_alignment) return getpagesize(); return max_block_alignment; } /* How many CPUs are online? */ int platform_nproc(void) { long nproc = sysconf(_SC_NPROCESSORS_ONLN); if (nproc < 1) return 1; if (nproc >= INT_MAX) return INT_MAX; return nproc; } unsigned long platform_physmem(void) { struct sysinfo si; if (sysinfo(&si) < 0) { fprintf(stderr, _("%s: can't determine memory size\n"), progname); exit(1); } return (si.totalram >> 10) * si.mem_unit; /* kilobytes */ } xfsprogs-5.3.0/libfrog/list_sort.c0000644000175000017500000000665213242461543017073 0ustar nathansnathans/* List sorting code from Linux::lib/list_sort.c. */ #include #include #include "list.h" #define unlikely(x) (x) #define MAX_LIST_LENGTH_BITS 20 /* * Returns a list organized in an intermediate format suited * to chaining of merge() calls: null-terminated, no reserved or * sentinel head node, "prev" links not maintained. */ static struct list_head *merge(void *priv, int (*cmp)(void *priv, struct list_head *a, struct list_head *b), struct list_head *a, struct list_head *b) { struct list_head head, *tail = &head; while (a && b) { /* if equal, take 'a' -- important for sort stability */ if ((*cmp)(priv, a, b) <= 0) { tail->next = a; a = a->next; } else { tail->next = b; b = b->next; } tail = tail->next; } tail->next = a?:b; return head.next; } /* * Combine final list merge with restoration of standard doubly-linked * list structure. This approach duplicates code from merge(), but * runs faster than the tidier alternatives of either a separate final * prev-link restoration pass, or maintaining the prev links * throughout. */ static void merge_and_restore_back_links(void *priv, int (*cmp)(void *priv, struct list_head *a, struct list_head *b), struct list_head *head, struct list_head *a, struct list_head *b) { struct list_head *tail = head; unsigned count = 0; while (a && b) { /* if equal, take 'a' -- important for sort stability */ if ((*cmp)(priv, a, b) <= 0) { tail->next = a; a->prev = tail; a = a->next; } else { tail->next = b; b->prev = tail; b = b->next; } tail = tail->next; } tail->next = a ? : b; do { /* * In worst cases this loop may run many iterations. * Continue callbacks to the client even though no * element comparison is needed, so the client's cmp() * routine can invoke cond_resched() periodically. */ if (unlikely(!(++count))) (*cmp)(priv, tail->next, tail->next); tail->next->prev = tail; tail = tail->next; } while (tail->next); tail->next = head; head->prev = tail; } /** * list_sort - sort a list * @priv: private data, opaque to list_sort(), passed to @cmp * @head: the list to sort * @cmp: the elements comparison function * * This function implements "merge sort", which has O(nlog(n)) * complexity. * * The comparison function @cmp must return a negative value if @a * should sort before @b, and a positive value if @a should sort after * @b. If @a and @b are equivalent, and their original relative * ordering is to be preserved, @cmp must return 0. */ void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, struct list_head *a, struct list_head *b)) { struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists -- last slot is a sentinel */ int lev; /* index into part[] */ int max_lev = 0; struct list_head *list; if (list_empty(head)) return; memset(part, 0, sizeof(part)); head->prev->next = NULL; list = head->next; while (list) { struct list_head *cur = list; list = list->next; cur->next = NULL; for (lev = 0; part[lev]; lev++) { cur = merge(priv, cmp, part[lev], cur); part[lev] = NULL; } if (lev > max_lev) { if (unlikely(lev >= ARRAY_SIZE(part)-1)) { lev--; } max_lev = lev; } part[lev] = cur; } for (lev = 0; lev < max_lev; lev++) if (part[lev]) list = merge(priv, cmp, part[lev], list); merge_and_restore_back_links(priv, cmp, head, part[max_lev], list); } xfsprogs-5.3.0/libfrog/logging.c0000644000175000017500000000052413570057155016473 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include #include "logging.h" /* Print an error. */ void xfrog_perror( int error, const char *s) { errno = error < 0 ? -error : error; perror(s); } xfsprogs-5.3.0/libfrog/logging.h0000644000175000017500000000040013570057155016471 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2019 Oracle, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_LOGGING_H__ #define __LIBFROG_LOGGING_H__ void xfrog_perror(int error, const char *s); #endif /* __LIBFROG_LOGGING_H__ */ xfsprogs-5.3.0/libfrog/paths.c0000644000175000017500000003052113570057155016164 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include #include #include #include #include #include #include "paths.h" #include "input.h" #include "projects.h" #include extern char *progname; int fs_count; int xfs_fs_count; struct fs_path *fs_table; struct fs_path *fs_path; char *mtab_file; #define PROC_MOUNTS "/proc/self/mounts" static int fs_device_number( const char *name, dev_t *devnum) { struct stat sbuf; if (stat(name, &sbuf) < 0) return errno; /* * We want to match st_rdev if the path provided is a device * special file. Otherwise we are looking for the the * device id for the containing filesystem, in st_dev. */ if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) *devnum = sbuf.st_rdev; else *devnum = sbuf.st_dev; return 0; } /* * Find the FS table entry for the given path. The "flags" argument * is a mask containing FS_MOUNT_POINT or FS_PROJECT_PATH (or both) * to indicate the type of table entry sought. * fs_table_lookup() finds the fs table entry for the filesystem hosting * the file represented in the "dir" argument. To compare against actual * mount point entries, use fs_table_lookup_mount() instead. */ struct fs_path * fs_table_lookup( const char *dir, uint flags) { uint i; dev_t dev = 0; if (fs_device_number(dir, &dev)) return NULL; for (i = 0; i < fs_count; i++) { if (flags && !(flags & fs_table[i].fs_flags)) continue; if (fs_table[i].fs_datadev == dev) return &fs_table[i]; } return NULL; } static struct fs_path * __fs_table_lookup_mount( const char *dir, const char *blkdev) { uint i; char rpath[PATH_MAX]; char dpath[PATH_MAX]; if (!dir && !blkdev) return NULL; if (dir && !realpath(dir, dpath)) return NULL; if (blkdev && !realpath(blkdev, dpath)) return NULL; for (i = 0; i < fs_count; i++) { if (fs_table[i].fs_flags != FS_MOUNT_POINT) continue; if (dir && !realpath(fs_table[i].fs_dir, rpath)) continue; if (blkdev && !realpath(fs_table[i].fs_name, rpath)) continue; if (strcmp(rpath, dpath) == 0) return &fs_table[i]; } return NULL; } /* * Find the FS table entry describing an actual mount for the given path. * Unlike fs_table_lookup(), fs_table_lookup_mount() compares the "dir" * argument to actual mount point entries in the table. Accordingly, it * will find matches only if the "dir" argument is indeed mounted. */ struct fs_path * fs_table_lookup_mount( const char *dir) { return __fs_table_lookup_mount(dir, NULL); } /* * Find the FS table entry describing an actual mount for the block device. * Unlike fs_table_lookup(), fs_table_lookup_blkdev() compares the "bdev" * argument to actual mount point names in the table. Accordingly, it * will find matches only if the "bdev" argument is indeed mounted. */ struct fs_path * fs_table_lookup_blkdev( const char *bdev) { return __fs_table_lookup_mount(NULL, bdev); } static int fs_table_insert( char *dir, uint prid, uint flags, char *fsname, char *fslog, char *fsrt) { dev_t datadev, logdev, rtdev; struct fs_path *tmp_fs_table; int error; datadev = logdev = rtdev = 0; error = fs_device_number(dir, &datadev); if (error) goto out_nodev; if (fslog) { error = fs_device_number(fslog, &logdev); if (error) goto out_nodev; } if (fsrt) { error = fs_device_number(fsrt, &rtdev); if (error) goto out_nodev; } if (!platform_test_xfs_path(dir)) flags |= FS_FOREIGN; /* * Make copies of the directory and data device path. * The log device and real-time device, if non-null, * are already the result of strdup() calls so we * don't need to duplicate those. In fact, this * function is assumed to "consume" both of those * pointers, meaning if an error occurs they will * both get freed. */ error = ENOMEM; dir = strdup(dir); if (!dir) goto out_nodev; fsname = strdup(fsname); if (!fsname) goto out_noname; tmp_fs_table = realloc(fs_table, sizeof(fs_path_t) * (fs_count + 1)); if (!tmp_fs_table) goto out_norealloc; fs_table = tmp_fs_table; /* Put foreign filesystems at the end, xfs filesystems at the front */ if (flags & FS_FOREIGN || fs_count == 0) { fs_path = &fs_table[fs_count]; } else { /* move foreign fs entries down, insert new one just before */ memmove(&fs_table[xfs_fs_count + 1], &fs_table[xfs_fs_count], sizeof(fs_path_t)*(fs_count - xfs_fs_count)); fs_path = &fs_table[xfs_fs_count]; } fs_path->fs_dir = dir; fs_path->fs_prid = prid; fs_path->fs_flags = flags; fs_path->fs_name = fsname; fs_path->fs_log = fslog; fs_path->fs_rt = fsrt; fs_path->fs_datadev = datadev; fs_path->fs_logdev = logdev; fs_path->fs_rtdev = rtdev; fs_count++; if (!(flags & FS_FOREIGN)) xfs_fs_count++; return 0; out_norealloc: free(fsname); out_noname: free(dir); out_nodev: /* "Consume" fslog and fsrt even if there's an error */ free(fslog); free(fsrt); return error; } /* Remove all the cached entries in the fs table. */ void fs_table_destroy(void) { int i; struct fs_path *fsp; for (i = 0, fsp = fs_table; i < fs_count; i++, fsp++) { free(fsp->fs_name); free(fsp->fs_dir); free(fsp->fs_log); free(fsp->fs_rt); } fs_count = 0; xfs_fs_count = 0; free(fs_table); fs_table = NULL; } /* * Table iteration (cursor-based) interfaces */ /* * Initialize an fs_table cursor. If a directory path is supplied, * the cursor is set up to appear as though the table contains only * a single entry which represents the directory specified. * Otherwise it is set up to prepare for visiting all entries in the * global table, starting with the first. "flags" can be either * FS_MOUNT_POINT or FS_PROJECT_PATH to limit what type of entries * will be selected by fs_cursor_next_entry(). 0 can be used as a * wild card (selecting either type). */ void fs_cursor_initialise( char *dir, uint flags, fs_cursor_t *cur) { fs_path_t *path; memset(cur, 0, sizeof(*cur)); if (dir) { if ((path = fs_table_lookup(dir, flags)) == NULL) return; cur->local = *path; cur->count = 1; cur->table = &cur->local; } else { cur->count = fs_count; cur->table = fs_table; } cur->flags = flags; } /* * Use the cursor to find the next entry in the table having the * type specified by the cursor's "flags" field. */ struct fs_path * fs_cursor_next_entry( fs_cursor_t *cur) { while (cur->index < cur->count) { fs_path_t *next = &cur->table[cur->index++]; if (!cur->flags || (cur->flags & next->fs_flags)) return next; } return NULL; } #if defined(HAVE_GETMNTENT) #include /* * Determines whether the "logdev" or "rtdev" mount options are * present for the given mount point. If so, the value for each (a * device path) is returned in the pointers whose addresses are * provided. The pointers are assigned NULL for an option not * present. Note that the path buffers returned are allocated * dynamically and it is the caller's responsibility to free them. */ static int fs_extract_mount_options( struct mntent *mnt, char **logp, char **rtp) { char *fslog, *fsrt; /* * Extract log device and realtime device from mount options. * * Note: the glibc hasmntopt implementation requires that the * character in mnt_opts immediately after the search string * must be a NULL ('\0'), a comma (','), or an equals ('='). * Therefore we cannot search for 'logdev=' directly. */ if ((fslog = hasmntopt(mnt, "logdev")) && fslog[6] == '=') fslog += 7; if ((fsrt = hasmntopt(mnt, "rtdev")) && fsrt[5] == '=') fsrt += 6; /* Do this only after we've finished processing mount options */ if (fslog) { fslog = strndup(fslog, strcspn(fslog, " ,")); if (!fslog) goto out_nomem; } if (fsrt) { fsrt = strndup(fsrt, strcspn(fsrt, " ,")); if (!fsrt) { free(fslog); goto out_nomem; } } *logp = fslog; *rtp = fsrt; return 0; out_nomem: *logp = NULL; *rtp = NULL; fprintf(stderr, _("%s: unable to extract mount options for \"%s\"\n"), progname, mnt->mnt_dir); return ENOMEM; } /* * If *path is NULL, initialize the fs table with all xfs mount points in mtab * If *path is specified, search for that path in mtab * * Everything - path, devices, and mountpoints - are boiled down to realpath() * for comparison, but fs_table is populated with what comes from getmntent. */ static int fs_table_initialise_mounts( char *path) { struct mntent *mnt; FILE *mtp; char *fslog, *fsrt; int error, found; char rpath[PATH_MAX], rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX]; error = found = 0; fslog = fsrt = NULL; if (!mtab_file) { mtab_file = PROC_MOUNTS; if (access(mtab_file, R_OK) != 0) mtab_file = MOUNTED; } if ((mtp = setmntent(mtab_file, "r")) == NULL) return ENOENT; /* Use realpath to resolve symlinks, relative paths, etc */ if (path) if (!realpath(path, rpath)) return errno; while ((mnt = getmntent(mtp)) != NULL) { if (!realpath(mnt->mnt_dir, rmnt_dir)) continue; if (!realpath(mnt->mnt_fsname, rmnt_fsname)) continue; if (path && ((strcmp(rpath, rmnt_dir) != 0) && (strcmp(rpath, rmnt_fsname) != 0))) continue; if (fs_extract_mount_options(mnt, &fslog, &fsrt)) continue; (void) fs_table_insert(mnt->mnt_dir, 0, FS_MOUNT_POINT, mnt->mnt_fsname, fslog, fsrt); if (path) { found = 1; break; } } endmntent(mtp); if (path && !found) error = ENXIO; return error; } #else # error "How do I extract info about mounted filesystems on this platform?" #endif /* * Given a directory, match it up to a filesystem mount point. */ static struct fs_path * fs_mount_point_from_path( const char *dir) { fs_cursor_t cursor; fs_path_t *fs; dev_t dev = 0; if (fs_device_number(dir, &dev)) return NULL; fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor); while ((fs = fs_cursor_next_entry(&cursor))) { if (fs->fs_datadev == dev) break; } return fs; } static void fs_table_insert_mount( char *mount) { int error; error = fs_table_initialise_mounts(mount); if (error) fprintf(stderr, _("%s: cannot setup path for mount %s: %s\n"), progname, mount, strerror(error)); } static int fs_table_initialise_projects( char *project) { fs_project_path_t *path; fs_path_t *fs; prid_t prid = 0; int error = 0, found = 0; if (project) prid = prid_from_string(project); setprpathent(); while ((path = getprpathent()) != NULL) { if (project && prid != path->pp_prid) continue; fs = fs_mount_point_from_path(path->pp_pathname); if (!fs) { fprintf(stderr, _("%s: cannot find mount point for path `%s': %s\n"), progname, path->pp_pathname, strerror(errno)); continue; } (void) fs_table_insert(path->pp_pathname, path->pp_prid, FS_PROJECT_PATH, fs->fs_name, NULL, NULL); if (project) { found = 1; break; } } endprpathent(); if (project && !found) error = ENOENT; return error; } static void fs_table_insert_project( char *project) { int error; error = fs_table_initialise_projects(project); if (error) fprintf(stderr, _("%s: cannot setup path for project %s: %s\n"), progname, project, strerror(error)); } /* * Initialize fs_table to contain the given set of mount points and * projects. If mount_count is zero, mounts is ignored and the * table is populated with mounted filesystems. If project_count is * zero, projects is ignored and the table is populated with all * projects defined in the projects file. */ void fs_table_initialise( int mount_count, char *mounts[], int project_count, char *projects[]) { int error; int i; if (mount_count) { for (i = 0; i < mount_count; i++) fs_table_insert_mount(mounts[i]); } else { error = fs_table_initialise_mounts(NULL); if (error) goto out_error; } if (project_count) { for (i = 0; i < project_count; i++) fs_table_insert_project(projects[i]); } else { error = fs_table_initialise_projects(NULL); if (error) goto out_error; } return; out_error: fprintf(stderr, _("%s: cannot initialise path table: %s\n"), progname, strerror(error)); } void fs_table_insert_project_path( char *dir, prid_t prid) { fs_path_t *fs; int error = 0; fs = fs_mount_point_from_path(dir); if (fs) error = fs_table_insert(dir, prid, FS_PROJECT_PATH, fs->fs_name, NULL, NULL); else error = ENOENT; if (error) { fprintf(stderr, _("%s: cannot setup path for project dir %s: %s\n"), progname, dir, strerror(error)); exit(1); } } xfsprogs-5.3.0/libfrog/paths.h0000644000175000017500000000360713570057155016176 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_PATH_H__ #define __LIBFROG_PATH_H__ #include "platform_defs.h" /* * XFS Filesystem Paths * * Utility routines for iterating and searching through the list * of known mounted filesystems and project paths. */ #define FS_MOUNT_POINT (1<<0) #define FS_PROJECT_PATH (1<<1) #define FS_FOREIGN (1<<2) typedef struct fs_path { char *fs_name; /* Data device for filesystem */ dev_t fs_datadev; char *fs_log; /* External log device, if any */ dev_t fs_logdev; char *fs_rt; /* Realtime device, if any */ dev_t fs_rtdev; char *fs_dir; /* Directory / mount point */ uint fs_flags; /* FS_{MOUNT_POINT,PROJECT_PATH}*/ uint fs_prid; /* Project ID for tree root */ } fs_path_t; extern int fs_count; /* number of entries in fs table */ extern int xfs_fs_count; /* number of xfs entries in fs table */ extern fs_path_t *fs_table; /* array of entries in fs table */ extern fs_path_t *fs_path; /* current entry in the fs table */ extern char *mtab_file; extern void fs_table_initialise(int, char *[], int, char *[]); extern void fs_table_destroy(void); extern void fs_table_insert_project_path(char *__dir, uint __projid); extern fs_path_t *fs_table_lookup(const char *__dir, uint __flags); extern fs_path_t *fs_table_lookup_mount(const char *__dir); extern fs_path_t *fs_table_lookup_blkdev(const char *bdev); typedef struct fs_cursor { uint count; /* total count of mount entries */ uint index; /* current position in table */ uint flags; /* iterator flags: mounts/trees */ fs_path_t *table; /* local/global table pointer */ fs_path_t local; /* space for single-entry table */ } fs_cursor_t; extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); #endif /* __LIBFROG_PATH_H__ */ xfsprogs-5.3.0/libfrog/platform.h0000644000175000017500000000160013570057155016672 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_PLATFORM_H__ #define __LIBFROG_PLATFORM_H__ int platform_check_ismounted(char *path, char *block, struct stat *sptr, int verbose); int platform_check_iswritable(char *path, char *block, struct stat *sptr); int platform_set_blocksize(int fd, char *path, dev_t device, int bsz, int fatal); void platform_flush_device(int fd, dev_t device); char *platform_findrawpath(char *path); char *platform_findblockpath(char *path); int platform_direct_blockdev(void); int platform_align_blockdev(void); unsigned long platform_physmem(void); /* in kilobytes */ void platform_findsizes(char *path, int fd, long long *sz, int *bsz); int platform_nproc(void); void platform_findsizes(char *path, int fd, long long *sz, int *bsz); #endif /* __LIBFROG_PLATFORM_H__ */ xfsprogs-5.3.0/libfrog/projects.c0000644000175000017500000000610513570057155016677 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include #include "projects.h" #define PROJID "/etc/projid" #define PROJECT_PATHS "/etc/projects" char *projid_file; char *projects_file; static FILE *projects; static FILE *project_paths; void setprfiles(void) { if (!projid_file) projid_file = PROJID; if (!projects_file) projects_file = PROJECT_PATHS; } void setprent(void) { setprfiles(); projects = fopen(projid_file, "r"); } void setprpathent(void) { setprfiles(); project_paths = fopen(projects_file, "r"); } void endprent(void) { if (projects) fclose(projects); projects = NULL; } void endprpathent(void) { if (project_paths) fclose(project_paths); project_paths = NULL; } fs_project_t * getprent(void) { static fs_project_t p; static char projects_buffer[512]; char *idstart, *idend; size_t size = sizeof(projects_buffer) - 1; if (!projects) return NULL; for (;;) { if (!fgets(projects_buffer, size, projects)) break; /* * /etc/projid file format -- "name:id\n", ignore "^#..." */ if (projects_buffer[0] == '#') continue; idstart = strchr(projects_buffer, ':'); if (!idstart) continue; if ((idstart + 1) - projects_buffer >= size) continue; idend = strchr(idstart+1, ':'); if (idend) *idend = '\0'; *idstart = '\0'; p.pr_prid = atoi(idstart+1); p.pr_name = &projects_buffer[0]; return &p; } return NULL; } fs_project_t * getprnam( char *name) { fs_project_t *p = NULL; setprent(); while ((p = getprent()) != NULL) if (strcmp(p->pr_name, name) == 0) break; endprent(); return p; } fs_project_t * getprprid( prid_t prid) { fs_project_t *p = NULL; setprent(); while ((p = getprent()) != NULL) if (p->pr_prid == prid) break; endprent(); return p; } fs_project_path_t * getprpathent(void) { static fs_project_path_t pp; static char project_paths_buffer[1024]; char *nmstart, *nmend; size_t size = sizeof(project_paths_buffer) - 1; if (!project_paths) return NULL; for (;;) { if (!fgets(project_paths_buffer, size, project_paths)) break; /* * /etc/projects format -- "id:pathname\n", ignore "^#..." */ if (project_paths_buffer[0] == '#') continue; nmstart = strchr(project_paths_buffer, ':'); if (!nmstart) continue; if ((nmstart + 1) - project_paths_buffer >= size) continue; nmend = strchr(nmstart + 1, '\n'); if (nmend) *nmend = '\0'; *nmstart = '\0'; pp.pp_pathname = nmstart + 1; pp.pp_prid = atoi(&project_paths_buffer[0]); return &pp; } return NULL; } int getprojid( const char *name, int fd, prid_t *projid) { struct fsxattr fsx; if (xfsctl(name, fd, FS_IOC_FSGETXATTR, &fsx)) { perror("FS_IOC_FSGETXATTR"); return -1; } *projid = fsx.fsx_projid; return 0; } int setprojid( const char *name, int fd, prid_t projid) { struct fsxattr fsx; int error; if ((error = xfsctl(name, fd, FS_IOC_FSGETXATTR, &fsx)) == 0) { fsx.fsx_projid = projid; error = xfsctl(name, fd, FS_IOC_FSSETXATTR, &fsx); } return error; } xfsprogs-5.3.0/libfrog/projects.h0000644000175000017500000000203213570057155016677 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_PROJECTS_H__ #define __LIBFROG_PROJECTS_H__ #include "platform_defs.h" #include "xfs.h" extern int setprojid(const char *__name, int __fd, prid_t __id); extern int getprojid(const char *__name, int __fd, prid_t *__id); typedef struct fs_project { prid_t pr_prid; /* project identifier */ char *pr_name; /* project name */ } fs_project_t; extern void setprent(void); extern void endprent(void); extern fs_project_t *getprent(void); extern fs_project_t *getprnam(char *__name); extern fs_project_t *getprprid(prid_t __id); typedef struct fs_project_path { prid_t pp_prid; /* project identifier */ char *pp_pathname; /* pathname to root of project tree */ } fs_project_path_t; extern void setprpathent(void); extern void endprpathent(void); extern fs_project_path_t *getprpathent(void); extern void setprfiles(void); extern char *projid_file; extern char *projects_file; #endif /* __LIBFROG_PROJECTS_H__ */ xfsprogs-5.3.0/libfrog/ptvar.c0000644000175000017500000000534613570057155016210 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include #include #include #include #include #include #include "platform_defs.h" #include "ptvar.h" /* * Per-thread Variables * * This data structure manages a lockless per-thread variable. We * implement this by allocating an array of memory regions, and as each * thread tries to acquire its own region, we hand out the array * elements to each thread. This way, each thread gets its own * cacheline and (after the first access) doesn't have to contend for a * lock for each access. */ struct ptvar { pthread_key_t key; pthread_mutex_t lock; size_t nr_used; size_t nr_counters; size_t data_size; unsigned char data[0]; }; #define PTVAR_SIZE(nr, sz) (sizeof(struct ptvar) + ((nr) * (size))) /* Allocate a new per-thread counter. */ int ptvar_alloc( size_t nr, size_t size, struct ptvar **pptv) { struct ptvar *ptv; int ret; #ifdef _SC_LEVEL1_DCACHE_LINESIZE long l1_dcache; /* Try to prevent cache pingpong by aligning to cacheline size. */ l1_dcache = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); if (l1_dcache > 0) size = roundup(size, l1_dcache); #endif ptv = malloc(PTVAR_SIZE(nr, size)); if (!ptv) return -errno; ptv->data_size = size; ptv->nr_counters = nr; ptv->nr_used = 0; memset(ptv->data, 0, nr * size); ret = -pthread_mutex_init(&ptv->lock, NULL); if (ret) goto out; ret = -pthread_key_create(&ptv->key, NULL); if (ret) goto out_mutex; *pptv = ptv; return 0; out_mutex: pthread_mutex_destroy(&ptv->lock); out: free(ptv); return ret; } /* Free per-thread counter. */ void ptvar_free( struct ptvar *ptv) { pthread_key_delete(ptv->key); pthread_mutex_destroy(&ptv->lock); free(ptv); } /* Get a reference to this thread's variable. */ void * ptvar_get( struct ptvar *ptv, int *retp) { void *p; int ret; p = pthread_getspecific(ptv->key); if (!p) { pthread_mutex_lock(&ptv->lock); assert(ptv->nr_used < ptv->nr_counters); p = &ptv->data[(ptv->nr_used++) * ptv->data_size]; ret = -pthread_setspecific(ptv->key, p); if (ret) goto out_unlock; pthread_mutex_unlock(&ptv->lock); } *retp = 0; return p; out_unlock: ptv->nr_used--; pthread_mutex_unlock(&ptv->lock); *retp = ret; return NULL; } /* Iterate all of the per-thread variables. */ int ptvar_foreach( struct ptvar *ptv, ptvar_iter_fn fn, void *foreach_arg) { size_t i; int ret = 0; pthread_mutex_lock(&ptv->lock); for (i = 0; i < ptv->nr_used; i++) { ret = fn(ptv, &ptv->data[i * ptv->data_size], foreach_arg); if (ret) break; } pthread_mutex_unlock(&ptv->lock); return ret; } xfsprogs-5.3.0/libfrog/ptvar.h0000644000175000017500000000125413570057155016207 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __LIBFROG_PTVAR_H__ #define __LIBFROG_PTVAR_H__ struct ptvar; int ptvar_alloc(size_t nr, size_t size, struct ptvar **pptv); void ptvar_free(struct ptvar *ptv); void *ptvar_get(struct ptvar *ptv, int *ret); /* * Visit each per-thread value. Return 0 to continue iteration or nonzero to * stop iterating and return to the caller. */ typedef int (*ptvar_iter_fn)(struct ptvar *ptv, void *data, void *foreach_arg); int ptvar_foreach(struct ptvar *ptv, ptvar_iter_fn fn, void *foreach_arg); #endif /* __LIBFROG_PTVAR_H__ */ xfsprogs-5.3.0/libfrog/radix-tree.c0000644000175000017500000004510413435336036017112 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig * Copyright (C) 2005 SGI, Christoph Lameter */ #include #include #include #include #include "platform_defs.h" #include "radix-tree.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #define RADIX_TREE_MAP_SHIFT 6 #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) #define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) #ifdef RADIX_TREE_TAGS #define RADIX_TREE_TAG_LONGS \ ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) #endif struct radix_tree_node { unsigned int count; void *slots[RADIX_TREE_MAP_SIZE]; #ifdef RADIX_TREE_TAGS unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; #endif }; struct radix_tree_path { struct radix_tree_node *node; int offset; }; #define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) #define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2) static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH]; /* * Radix tree node cache. */ #define radix_tree_node_alloc(r) ((struct radix_tree_node *) \ calloc(1, sizeof(struct radix_tree_node))) #define radix_tree_node_free(n) free(n) #ifdef RADIX_TREE_TAGS static inline void tag_set(struct radix_tree_node *node, unsigned int tag, int offset) { *((uint32_t *)node->tags[tag] + (offset >> 5)) |= (1 << (offset & 31)); } static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, int offset) { uint32_t *p = (uint32_t*)node->tags[tag] + (offset >> 5); uint32_t m = 1 << (offset & 31); *p &= ~m; } static inline int tag_get(struct radix_tree_node *node, unsigned int tag, int offset) { return 1 & (((const uint32_t *)node->tags[tag])[offset >> 5] >> (offset & 31)); } /* * Returns 1 if any slot in the node has this tag set. * Otherwise returns 0. */ static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) { int idx; for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { if (node->tags[tag][idx]) return 1; } return 0; } #endif /* * Return the maximum key which can be store into a * radix tree with height HEIGHT. */ static inline unsigned long radix_tree_maxindex(unsigned int height) { return height_to_maxindex[height]; } /* * Extend a radix tree so it can store key @index. */ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) { struct radix_tree_node *node; unsigned int height; #ifdef RADIX_TREE_TAGS char tags[RADIX_TREE_MAX_TAGS]; int tag; #endif /* Figure out what the height should be. */ height = root->height + 1; while (index > radix_tree_maxindex(height)) height++; if (root->rnode == NULL) { root->height = height; goto out; } #ifdef RADIX_TREE_TAGS /* * Prepare the tag status of the top-level node for propagation * into the newly-pushed top-level node(s) */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { tags[tag] = 0; if (any_tag_set(root->rnode, tag)) tags[tag] = 1; } #endif do { if (!(node = radix_tree_node_alloc(root))) return -ENOMEM; /* Increase the height. */ node->slots[0] = root->rnode; #ifdef RADIX_TREE_TAGS /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (tags[tag]) tag_set(node, tag, 0); } #endif node->count = 1; root->rnode = node; root->height++; } while (height > root->height); out: return 0; } /** * radix_tree_insert - insert into a radix tree * @root: radix tree root * @index: index key * @item: item to insert * * Insert an item into the radix tree at position @index. */ int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item) { struct radix_tree_node *node = NULL, *slot; unsigned int height, shift; int offset; int error; /* Make sure the tree is high enough. */ if ((!index && !root->rnode) || index > radix_tree_maxindex(root->height)) { error = radix_tree_extend(root, index); if (error) return error; } slot = root->rnode; height = root->height; shift = (height-1) * RADIX_TREE_MAP_SHIFT; offset = 0; /* uninitialised var warning */ do { if (slot == NULL) { /* Have to add a child node. */ if (!(slot = radix_tree_node_alloc(root))) return -ENOMEM; if (node) { node->slots[offset] = slot; node->count++; } else root->rnode = slot; } /* Go a level down */ offset = (index >> shift) & RADIX_TREE_MAP_MASK; node = slot; slot = node->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } while (height > 0); if (slot != NULL) return -EEXIST; ASSERT(node); node->count++; node->slots[offset] = item; #ifdef RADIX_TREE_TAGS ASSERT(!tag_get(node, 0, offset)); ASSERT(!tag_get(node, 1, offset)); #endif return 0; } static inline void **__lookup_slot(struct radix_tree_root *root, unsigned long index) { unsigned int height, shift; struct radix_tree_node **slot; height = root->height; if (index > radix_tree_maxindex(height)) return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = &root->rnode; while (height > 0) { if (*slot == NULL) return NULL; slot = (struct radix_tree_node **) ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK)); shift -= RADIX_TREE_MAP_SHIFT; height--; } return (void **)slot; } /** * radix_tree_lookup_slot - lookup a slot in a radix tree * @root: radix tree root * @index: index key * * Lookup the slot corresponding to the position @index in the radix tree * @root. This is useful for update-if-exists operations. */ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) { return __lookup_slot(root, index); } /** * radix_tree_lookup - perform lookup operation on a radix tree * @root: radix tree root * @index: index key * * Lookup the item at the position @index in the radix tree @root. */ void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) { void **slot; slot = __lookup_slot(root, index); return slot != NULL ? *slot : NULL; } /** * raid_tree_first_key - find the first index key in the radix tree * @root: radix tree root * @index: where the first index will be placed * * Returns the first entry and index key in the radix tree @root. */ void *radix_tree_lookup_first(struct radix_tree_root *root, unsigned long *index) { unsigned int height, shift; struct radix_tree_node *slot; unsigned long i; height = root->height; *index = 0; if (height == 0) return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; for (; height > 1; height--) { for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) break; } ASSERT(i < RADIX_TREE_MAP_SIZE); *index |= (i << shift); shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) { *index |= i; return slot->slots[i]; } } return NULL; } #ifdef RADIX_TREE_TAGS /** * radix_tree_tag_set - set a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Set the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. From * the root all the way down to the leaf node. * * Returns the address of the tagged item. Setting a tag on a not-present * item is a bug. */ void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag) { unsigned int height, shift; struct radix_tree_node *slot; height = root->height; if (index > radix_tree_maxindex(height)) return NULL; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; while (height > 0) { int offset; offset = (index >> shift) & RADIX_TREE_MAP_MASK; if (!tag_get(slot, tag, offset)) tag_set(slot, tag, offset); slot = slot->slots[offset]; ASSERT(slot != NULL); shift -= RADIX_TREE_MAP_SHIFT; height--; } return slot; } /** * radix_tree_tag_clear - clear a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Clear the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. If * this causes the leaf node to have no tags set then clear the tag in the * next-to-leaf node, etc. * * Returns the address of the tagged item on success, else NULL. ie: * has the same return value and semantics as radix_tree_lookup(). */ void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag) { struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; struct radix_tree_node *slot; unsigned int height, shift; void *ret = NULL; height = root->height; if (index > radix_tree_maxindex(height)) goto out; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; slot = root->rnode; while (height > 0) { int offset; if (slot == NULL) goto out; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp[1].offset = offset; pathp[1].node = slot; slot = slot->slots[offset]; pathp++; shift -= RADIX_TREE_MAP_SHIFT; height--; } ret = slot; if (ret == NULL) goto out; do { if (!tag_get(pathp->node, tag, pathp->offset)) goto out; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) goto out; pathp--; } while (pathp->node); out: return ret; } #endif static unsigned int __lookup(struct radix_tree_root *root, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index) { unsigned int nr_found = 0; unsigned int shift, height; struct radix_tree_node *slot; unsigned long i; height = root->height; if (height == 0) goto out; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; for ( ; height > 1; height--) { for (i = (index >> shift) & RADIX_TREE_MAP_MASK ; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) break; index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ } if (i == RADIX_TREE_MAP_SIZE) goto out; shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } /* Bottom level: grab some items */ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { index++; if (slot->slots[i]) { results[nr_found++] = slot->slots[i]; if (nr_found == max_items) goto out; } } out: *next_index = index; return nr_found; } /** * radix_tree_gang_lookup - perform multiple lookup on a radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items. Places * them at *@results and returns the number of items which were placed at * *@results. * * The implementation is naive. */ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup(root, results + ret, cur_index, max_items - ret, &next_index); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } /** * radix_tree_gang_lookup_ex - perform multiple lookup on a radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @last_index: don't lookup past this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items starting * @first_index until @last_index up to as many as @max_items. Places * them at *@results and returns the number of items which were placed * at *@results. * * The implementation is naive. */ unsigned int radix_tree_gang_lookup_ex(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned long last_index, unsigned int max_items) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items && cur_index < last_index) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup(root, results + ret, cur_index, max_items - ret, &next_index); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } #ifdef RADIX_TREE_TAGS static unsigned int __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index, unsigned int tag) { unsigned int nr_found = 0; unsigned int shift; unsigned int height = root->height; struct radix_tree_node *slot; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; while (height > 0) { unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; for ( ; i < RADIX_TREE_MAP_SIZE; i++) { if (tag_get(slot, tag, i)) { ASSERT(slot->slots[i] != NULL); break; } index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ } if (i == RADIX_TREE_MAP_SIZE) goto out; height--; if (height == 0) { /* Bottom level: grab some items */ unsigned long j = index & RADIX_TREE_MAP_MASK; for ( ; j < RADIX_TREE_MAP_SIZE; j++) { index++; if (tag_get(slot, tag, j)) { ASSERT(slot->slots[j] != NULL); results[nr_found++] = slot->slots[j]; if (nr_found == max_items) goto out; } } } shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } out: *next_index = index; return nr_found; } /** * radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree * based on a tag * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * @tag: the tag index (< RADIX_TREE_MAX_TAGS) * * Performs an index-ascending scan of the tree for present items which * have the tag indexed by @tag set. Places the items at *@results and * returns the number of items which were placed at *@results. */ unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup_tag(root, results + ret, cur_index, max_items - ret, &next_index, tag); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } #endif /** * radix_tree_shrink - shrink height of a radix tree to minimal * @root radix tree root */ static inline void radix_tree_shrink(struct radix_tree_root *root) { /* try to shrink tree height */ while (root->height > 1 && root->rnode->count == 1 && root->rnode->slots[0]) { struct radix_tree_node *to_free = root->rnode; root->rnode = to_free->slots[0]; root->height--; /* must only free zeroed nodes into the slab */ #ifdef RADIX_TREE_TAGS tag_clear(to_free, 0, 0); tag_clear(to_free, 1, 0); #endif to_free->slots[0] = NULL; to_free->count = 0; radix_tree_node_free(to_free); } } /** * radix_tree_delete - delete an item from a radix tree * @root: radix tree root * @index: index key * * Remove the item at @index from the radix tree rooted at @root. * * Returns the address of the deleted item, or NULL if it was not present. */ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) { struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; struct radix_tree_path *orig_pathp; struct radix_tree_node *slot; unsigned int height, shift; void *ret = NULL; #ifdef RADIX_TREE_TAGS char tags[RADIX_TREE_MAX_TAGS]; int nr_cleared_tags; int tag; #endif int offset; height = root->height; if (index > radix_tree_maxindex(height)) goto out; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; slot = root->rnode; for ( ; height > 0; height--) { if (slot == NULL) goto out; pathp++; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp->offset = offset; pathp->node = slot; slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; } ret = slot; if (ret == NULL) goto out; orig_pathp = pathp; #ifdef RADIX_TREE_TAGS /* * Clear all tags associated with the just-deleted item */ nr_cleared_tags = 0; for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { tags[tag] = 1; if (tag_get(pathp->node, tag, pathp->offset)) { tag_clear(pathp->node, tag, pathp->offset); if (!any_tag_set(pathp->node, tag)) { tags[tag] = 0; nr_cleared_tags++; } } } for (pathp--; nr_cleared_tags && pathp->node; pathp--) { for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (tags[tag]) continue; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) { tags[tag] = 1; nr_cleared_tags--; } } } #endif /* Now free the nodes we do not need anymore */ for (pathp = orig_pathp; pathp->node; pathp--) { pathp->node->slots[pathp->offset] = NULL; pathp->node->count--; if (pathp->node->count) { if (pathp->node == root->rnode) radix_tree_shrink(root); goto out; } /* Node with zero slots in use so free it */ radix_tree_node_free(pathp->node); } root->rnode = NULL; root->height = 0; out: return ret; } #ifdef RADIX_TREE_TAGS /** * radix_tree_tagged - test whether any items in the tree are tagged * @root: radix tree root * @tag: tag to test */ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) { struct radix_tree_node *rnode; rnode = root->rnode; if (!rnode) return 0; return any_tag_set(rnode, tag); } #endif static unsigned long __maxindex(unsigned int height) { unsigned int width = height * RADIX_TREE_MAP_SHIFT; int shift = RADIX_TREE_INDEX_BITS - width; if (shift < 0) return ~0UL; if (shift >= BITS_PER_LONG) return 0UL; return ~0UL >> shift; } static void radix_tree_init_maxindex(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) height_to_maxindex[i] = __maxindex(i); } void radix_tree_init(void) { radix_tree_init_maxindex(); } xfsprogs-5.3.0/libfrog/radix-tree.h0000644000175000017500000000364013570057155017120 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig */ #ifndef __LIBFROG_RADIX_TREE_H__ #define __LIBFROG_RADIX_TREE_H__ #define RADIX_TREE_TAGS struct radix_tree_root { unsigned int height; struct radix_tree_node *rnode; }; #define RADIX_TREE_INIT(mask) { \ .height = 0, \ .rnode = NULL, \ } #define RADIX_TREE(name, mask) \ struct radix_tree_root name = RADIX_TREE_INIT(mask) #define INIT_RADIX_TREE(root, mask) \ do { \ (root)->height = 0; \ (root)->rnode = NULL; \ } while (0) #ifdef RADIX_TREE_TAGS #define RADIX_TREE_MAX_TAGS 2 #endif int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); void *radix_tree_lookup(struct radix_tree_root *, unsigned long); void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); void *radix_tree_lookup_first(struct radix_tree_root *, unsigned long *); void *radix_tree_delete(struct radix_tree_root *, unsigned long); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); unsigned int radix_tree_gang_lookup_ex(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned long last_index, unsigned int max_items); void radix_tree_init(void); #ifdef RADIX_TREE_TAGS void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag); void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag); int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag); unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag); int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); #endif #endif /* __LIBFROG_RADIX_TREE_H__ */ xfsprogs-5.3.0/libfrog/scrub.c0000644000175000017500000000665613570057155016177 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Oracle, Inc. * All Rights Reserved. */ #include "xfs.h" #include "fsgeom.h" #include "scrub.h" /* These must correspond to XFS_SCRUB_TYPE_ */ const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_PROBE] = { .name = "probe", .descr = "metadata", .type = XFROG_SCRUB_TYPE_NONE, }, [XFS_SCRUB_TYPE_SB] = { .name = "sb", .descr = "superblock", .type = XFROG_SCRUB_TYPE_AGHEADER, }, [XFS_SCRUB_TYPE_AGF] = { .name = "agf", .descr = "free space header", .type = XFROG_SCRUB_TYPE_AGHEADER, }, [XFS_SCRUB_TYPE_AGFL] = { .name = "agfl", .descr = "free list", .type = XFROG_SCRUB_TYPE_AGHEADER, }, [XFS_SCRUB_TYPE_AGI] = { .name = "agi", .descr = "inode header", .type = XFROG_SCRUB_TYPE_AGHEADER, }, [XFS_SCRUB_TYPE_BNOBT] = { .name = "bnobt", .descr = "freesp by block btree", .type = XFROG_SCRUB_TYPE_PERAG, }, [XFS_SCRUB_TYPE_CNTBT] = { .name = "cntbt", .descr = "freesp by length btree", .type = XFROG_SCRUB_TYPE_PERAG, }, [XFS_SCRUB_TYPE_INOBT] = { .name = "inobt", .descr = "inode btree", .type = XFROG_SCRUB_TYPE_PERAG, }, [XFS_SCRUB_TYPE_FINOBT] = { .name = "finobt", .descr = "free inode btree", .type = XFROG_SCRUB_TYPE_PERAG, }, [XFS_SCRUB_TYPE_RMAPBT] = { .name = "rmapbt", .descr = "reverse mapping btree", .type = XFROG_SCRUB_TYPE_PERAG, }, [XFS_SCRUB_TYPE_REFCNTBT] = { .name = "refcountbt", .descr = "reference count btree", .type = XFROG_SCRUB_TYPE_PERAG, }, [XFS_SCRUB_TYPE_INODE] = { .name = "inode", .descr = "inode record", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_BMBTD] = { .name = "bmapbtd", .descr = "data block map", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_BMBTA] = { .name = "bmapbta", .descr = "attr block map", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_BMBTC] = { .name = "bmapbtc", .descr = "CoW block map", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_DIR] = { .name = "directory", .descr = "directory entries", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_XATTR] = { .name = "xattr", .descr = "extended attributes", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_SYMLINK] = { .name = "symlink", .descr = "symbolic link", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_PARENT] = { .name = "parent", .descr = "parent pointer", .type = XFROG_SCRUB_TYPE_INODE, }, [XFS_SCRUB_TYPE_RTBITMAP] = { .name = "rtbitmap", .descr = "realtime bitmap", .type = XFROG_SCRUB_TYPE_FS, }, [XFS_SCRUB_TYPE_RTSUM] = { .name = "rtsummary", .descr = "realtime summary", .type = XFROG_SCRUB_TYPE_FS, }, [XFS_SCRUB_TYPE_UQUOTA] = { .name = "usrquota", .descr = "user quotas", .type = XFROG_SCRUB_TYPE_FS, }, [XFS_SCRUB_TYPE_GQUOTA] = { .name = "grpquota", .descr = "group quotas", .type = XFROG_SCRUB_TYPE_FS, }, [XFS_SCRUB_TYPE_PQUOTA] = { .name = "prjquota", .descr = "project quotas", .type = XFROG_SCRUB_TYPE_FS, }, [XFS_SCRUB_TYPE_FSCOUNTERS] = { .name = "fscounters", .descr = "filesystem summary counters", .type = XFROG_SCRUB_TYPE_FS, .flags = XFROG_SCRUB_DESCR_SUMMARY, }, }; /* Invoke the scrub ioctl. Returns zero or negative error code. */ int xfrog_scrub_metadata( struct xfs_fd *xfd, struct xfs_scrub_metadata *meta) { int ret; ret = ioctl(xfd->fd, XFS_IOC_SCRUB_METADATA, meta); if (ret) return -errno; return 0; } xfsprogs-5.3.0/libfrog/scrub.h0000644000175000017500000000204013570057155016163 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2019 Oracle, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_SCRUB_H__ #define __LIBFROG_SCRUB_H__ /* Type info and names for the scrub types. */ enum xfrog_scrub_type { XFROG_SCRUB_TYPE_NONE, /* not metadata */ XFROG_SCRUB_TYPE_AGHEADER, /* per-AG header */ XFROG_SCRUB_TYPE_PERAG, /* per-AG metadata */ XFROG_SCRUB_TYPE_FS, /* per-FS metadata */ XFROG_SCRUB_TYPE_INODE, /* per-inode metadata */ }; /* Catalog of scrub types and names, indexed by XFS_SCRUB_TYPE_* */ struct xfrog_scrub_descr { const char *name; const char *descr; enum xfrog_scrub_type type; unsigned int flags; }; /* * The type of metadata checked by this scrubber is a summary of other types * of metadata. This scrubber should be run after all the others. */ #define XFROG_SCRUB_DESCR_SUMMARY (1 << 0) extern const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR]; int xfrog_scrub_metadata(struct xfs_fd *xfd, struct xfs_scrub_metadata *meta); #endif /* __LIBFROG_SCRUB_H__ */ xfsprogs-5.3.0/libfrog/topology.c0000644000175000017500000001747013570057155016731 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxcmd.h" #ifdef ENABLE_BLKID # include #endif /* ENABLE_BLKID */ #include "xfs_multidisk.h" #include "topology.h" #include "platform.h" #define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog))) #define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog))) #define MEGABYTES(count, blog) ((uint64_t)(count) << (20 - (blog))) void calc_default_ag_geometry( int blocklog, uint64_t dblocks, int multidisk, uint64_t *agsize, uint64_t *agcount) { uint64_t blocks = 0; int shift = 0; /* * First handle the high extreme - the point at which we will * always use the maximum AG size. * * This applies regardless of storage configuration. */ if (dblocks >= TERABYTES(32, blocklog)) { blocks = XFS_AG_MAX_BLOCKS(blocklog); goto done; } /* * For a single underlying storage device over 4TB in size * use the maximum AG size. Between 128MB and 4TB, just use * 4 AGs and scale up smoothly between min/max AG sizes. */ if (!multidisk) { if (dblocks >= TERABYTES(4, blocklog)) { blocks = XFS_AG_MAX_BLOCKS(blocklog); goto done; } else if (dblocks >= MEGABYTES(128, blocklog)) { shift = XFS_NOMULTIDISK_AGLOG; goto calc_blocks; } } /* * For the multidisk configs we choose an AG count based on the number * of data blocks available, trying to keep the number of AGs higher * than the single disk configurations. This makes the assumption that * larger filesystems have more parallelism available to them. */ shift = XFS_MULTIDISK_AGLOG; if (dblocks <= GIGABYTES(512, blocklog)) shift--; if (dblocks <= GIGABYTES(8, blocklog)) shift--; if (dblocks < MEGABYTES(128, blocklog)) shift--; if (dblocks < MEGABYTES(64, blocklog)) shift--; if (dblocks < MEGABYTES(32, blocklog)) shift--; /* * If dblocks is not evenly divisible by the number of * desired AGs, round "blocks" up so we don't lose the * last bit of the filesystem. The same principle applies * to the AG count, so we don't lose the last AG! */ calc_blocks: ASSERT(shift >= 0 && shift <= XFS_MULTIDISK_AGLOG); blocks = dblocks >> shift; if (dblocks & xfs_mask32lo(shift)) { if (blocks < XFS_AG_MAX_BLOCKS(blocklog)) blocks++; } done: *agsize = blocks; *agcount = dblocks / blocks + (dblocks % blocks != 0); } /* * Check for existing filesystem or partition table on device. * Returns: * 1 for existing fs or partition * 0 for nothing found * -1 for internal error */ #ifdef ENABLE_BLKID int check_overwrite( const char *device) { const char *type; blkid_probe pr = NULL; int ret; int fd; long long size; int bsz; if (!device || !*device) return 0; ret = -1; /* will reset on success of all setup calls */ fd = open(device, O_RDONLY); if (fd < 0) goto out; platform_findsizes((char *)device, fd, &size, &bsz); close(fd); /* nothing to overwrite on a 0-length device */ if (size == 0) { ret = 0; goto out; } pr = blkid_new_probe_from_filename(device); if (!pr) goto out; ret = blkid_probe_enable_partitions(pr, 1); if (ret < 0) goto out; ret = blkid_do_fullprobe(pr); if (ret < 0) goto out; /* * Blkid returns 1 for nothing found and 0 when it finds a signature, * but we want the exact opposite, so reverse the return value here. * * In addition print some useful diagnostics about what actually is * on the device. */ if (ret) { ret = 0; goto out; } if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) { fprintf(stderr, _("%s: %s appears to contain an existing " "filesystem (%s).\n"), progname, device, type); } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) { fprintf(stderr, _("%s: %s appears to contain a partition " "table (%s).\n"), progname, device, type); } else { fprintf(stderr, _("%s: %s appears to contain something weird " "according to blkid\n"), progname, device); } ret = 1; out: if (pr) blkid_free_probe(pr); if (ret == -1) fprintf(stderr, _("%s: probe of %s failed, cannot detect " "existing filesystem.\n"), progname, device); return ret; } static void blkid_get_topology( const char *device, int *sunit, int *swidth, int *lsectorsize, int *psectorsize, int force_overwrite) { blkid_topology tp; blkid_probe pr; unsigned long val; struct stat statbuf; /* can't get topology info from a file */ if (!stat(device, &statbuf) && S_ISREG(statbuf.st_mode)) { fprintf(stderr, _("%s: Warning: trying to probe topology of a file %s!\n"), progname, device); return; } pr = blkid_new_probe_from_filename(device); if (!pr) return; tp = blkid_probe_get_topology(pr); if (!tp) goto out_free_probe; val = blkid_topology_get_logical_sector_size(tp); *lsectorsize = val; val = blkid_topology_get_physical_sector_size(tp); *psectorsize = val; val = blkid_topology_get_minimum_io_size(tp); *sunit = val; val = blkid_topology_get_optimal_io_size(tp); *swidth = val; /* * If the reported values are the same as the physical sector size * do not bother to report anything. It will only cause warnings * if people specify larger stripe units or widths manually. */ if (*sunit == *psectorsize || *swidth == *psectorsize) { *sunit = 0; *swidth = 0; } /* * Blkid reports the information in terms of bytes, but we want it in * terms of 512 bytes blocks (only to convert it to bytes later..) */ *sunit = *sunit >> 9; *swidth = *swidth >> 9; if (blkid_topology_get_alignment_offset(tp) != 0) { fprintf(stderr, _("warning: device is not properly aligned %s\n"), device); if (!force_overwrite) { fprintf(stderr, _("Use -f to force usage of a misaligned device\n")); exit(EXIT_FAILURE); } /* Do not use physical sector size if the device is misaligned */ *psectorsize = *lsectorsize; } blkid_free_probe(pr); return; out_free_probe: blkid_free_probe(pr); fprintf(stderr, _("warning: unable to probe device topology for device %s\n"), device); } #else /* ifdef ENABLE_BLKID */ /* * Without blkid, we can't do a good check for signatures. * So instead of some messy attempts, just disable any checks * and always return 'nothing found'. */ # warning BLKID is disabled, so signature detection and block device\ access are not working! int check_overwrite( const char *device) { return 1; } static void blkid_get_topology( const char *device, int *sunit, int *swidth, int *lsectorsize, int *psectorsize, int force_overwrite) { /* * Shouldn't make any difference (no blkid = no block device access), * but make sure this dummy replacement returns with at least some * sanity. */ *lsectorsize = *psectorsize = 512; } #endif /* ENABLE_BLKID */ void get_topology( libxfs_init_t *xi, struct fs_topology *ft, int force_overwrite) { struct stat statbuf; char *dfile = xi->volname ? xi->volname : xi->dname; /* * If our target is a regular file, use platform_findsizes * to try to obtain the underlying filesystem's requirements * for direct IO; we'll set our sector size to that if possible. */ if (xi->disfile || (!stat(dfile, &statbuf) && S_ISREG(statbuf.st_mode))) { int fd; int flags = O_RDONLY; long long dummy; /* with xi->disfile we may not have the file yet! */ if (xi->disfile) flags |= O_CREAT; fd = open(dfile, flags, 0666); if (fd >= 0) { platform_findsizes(dfile, fd, &dummy, &ft->lsectorsize); close(fd); ft->psectorsize = ft->lsectorsize; } else ft->psectorsize = ft->lsectorsize = BBSIZE; } else { blkid_get_topology(dfile, &ft->dsunit, &ft->dswidth, &ft->lsectorsize, &ft->psectorsize, force_overwrite); } if (xi->rtname && !xi->risfile) { int sunit, lsectorsize, psectorsize; blkid_get_topology(xi->rtname, &sunit, &ft->rtswidth, &lsectorsize, &psectorsize, force_overwrite); } } xfsprogs-5.3.0/libfrog/topology.h0000644000175000017500000000146513570057155016733 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_TOPOLOGY_H__ #define __LIBFROG_TOPOLOGY_H__ /* * Device topology information. */ typedef struct fs_topology { int dsunit; /* stripe unit - data subvolume */ int dswidth; /* stripe width - data subvolume */ int rtswidth; /* stripe width - rt subvolume */ int lsectorsize; /* logical sector size &*/ int psectorsize; /* physical sector size */ } fs_topology_t; extern void get_topology( libxfs_init_t *xi, struct fs_topology *ft, int force_overwrite); extern void calc_default_ag_geometry( int blocklog, uint64_t dblocks, int multidisk, uint64_t *agsize, uint64_t *agcount); extern int check_overwrite( const char *device); #endif /* __LIBFROG_TOPOLOGY_H__ */ xfsprogs-5.3.0/libfrog/util.c0000644000175000017500000000071513570057155016024 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "util.h" /* * libfrog is a collection of miscellaneous userspace utilities. * It's a library of Funny Random Oddball Gunk . */ unsigned int log2_roundup(unsigned int i) { unsigned int rval; for (rval = 0; rval < NBBY * sizeof(i); rval++) { if ((1 << rval) >= i) break; } return rval; } xfsprogs-5.3.0/libfrog/util.h0000644000175000017500000000037013570057155016026 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBFROG_UTIL_H__ #define __LIBFROG_UTIL_H__ unsigned int log2_roundup(unsigned int i); #endif /* __LIBFROG_UTIL_H__ */ xfsprogs-5.3.0/libfrog/workqueue.c0000644000175000017500000000775613570057155017112 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include #include #include #include #include #include #include #include "workqueue.h" /* Main processing thread */ static void * workqueue_thread(void *arg) { struct workqueue *wq = arg; struct workqueue_item *wi; /* * Loop pulling work from the passed in work queue. * Check for notification to exit after every chunk of work. */ while (1) { pthread_mutex_lock(&wq->lock); /* * Wait for work. */ while (wq->next_item == NULL && !wq->terminate) { assert(wq->item_count == 0); pthread_cond_wait(&wq->wakeup, &wq->lock); } if (wq->next_item == NULL && wq->terminate) { pthread_mutex_unlock(&wq->lock); break; } /* * Dequeue work from the head of the list. */ assert(wq->item_count > 0); wi = wq->next_item; wq->next_item = wi->next; wq->item_count--; pthread_mutex_unlock(&wq->lock); (wi->function)(wi->queue, wi->index, wi->arg); free(wi); } return NULL; } /* Allocate a work queue and threads. Returns zero or negative error code. */ int workqueue_create( struct workqueue *wq, void *wq_ctx, unsigned int nr_workers) { unsigned int i; int err = 0; memset(wq, 0, sizeof(*wq)); err = -pthread_cond_init(&wq->wakeup, NULL); if (err) return err; err = -pthread_mutex_init(&wq->lock, NULL); if (err) goto out_cond; wq->wq_ctx = wq_ctx; wq->thread_count = nr_workers; wq->threads = malloc(nr_workers * sizeof(pthread_t)); if (!wq->threads) { err = -errno; goto out_mutex; } wq->terminate = false; wq->terminated = false; for (i = 0; i < nr_workers; i++) { err = -pthread_create(&wq->threads[i], NULL, workqueue_thread, wq); if (err) break; } /* * If we encounter errors here, we have to signal and then wait for all * the threads that may have been started running before we can destroy * the workqueue. */ if (err) workqueue_destroy(wq); return err; out_mutex: pthread_mutex_destroy(&wq->lock); out_cond: pthread_cond_destroy(&wq->wakeup); return err; } /* * Create a work item consisting of a function and some arguments and schedule * the work item to be run via the thread pool. Returns zero or a negative * error code. */ int workqueue_add( struct workqueue *wq, workqueue_func_t func, uint32_t index, void *arg) { struct workqueue_item *wi; int ret; assert(!wq->terminated); if (wq->thread_count == 0) { func(wq, index, arg); return 0; } wi = malloc(sizeof(struct workqueue_item)); if (!wi) return -errno; wi->function = func; wi->index = index; wi->arg = arg; wi->queue = wq; wi->next = NULL; /* Now queue the new work structure to the work queue. */ pthread_mutex_lock(&wq->lock); if (wq->next_item == NULL) { assert(wq->item_count == 0); ret = -pthread_cond_signal(&wq->wakeup); if (ret) { pthread_mutex_unlock(&wq->lock); free(wi); return ret; } wq->next_item = wi; } else { wq->last_item->next = wi; } wq->last_item = wi; wq->item_count++; pthread_mutex_unlock(&wq->lock); return 0; } /* * Wait for all pending work items to be processed and tear down the * workqueue thread pool. Returns zero or a negative error code. */ int workqueue_terminate( struct workqueue *wq) { unsigned int i; int ret; pthread_mutex_lock(&wq->lock); wq->terminate = true; pthread_mutex_unlock(&wq->lock); ret = -pthread_cond_broadcast(&wq->wakeup); if (ret) return ret; for (i = 0; i < wq->thread_count; i++) { ret = -pthread_join(wq->threads[i], NULL); if (ret) return ret; } pthread_mutex_lock(&wq->lock); wq->terminated = true; pthread_mutex_unlock(&wq->lock); return 0; } /* Tear down the workqueue. */ void workqueue_destroy( struct workqueue *wq) { assert(wq->terminated); free(wq->threads); pthread_mutex_destroy(&wq->lock); pthread_cond_destroy(&wq->wakeup); memset(wq, 0, sizeof(*wq)); } xfsprogs-5.3.0/libfrog/workqueue.h0000644000175000017500000000205013570057155017075 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __LIBFROG_WORKQUEUE_H__ #define __LIBFROG_WORKQUEUE_H__ #include struct workqueue; typedef void workqueue_func_t(struct workqueue *wq, uint32_t index, void *arg); struct workqueue_item { struct workqueue *queue; struct workqueue_item *next; workqueue_func_t *function; void *arg; uint32_t index; }; struct workqueue { void *wq_ctx; pthread_t *threads; struct workqueue_item *next_item; struct workqueue_item *last_item; pthread_mutex_t lock; pthread_cond_t wakeup; unsigned int item_count; unsigned int thread_count; bool terminate; bool terminated; }; int workqueue_create(struct workqueue *wq, void *wq_ctx, unsigned int nr_workers); int workqueue_add(struct workqueue *wq, workqueue_func_t fn, uint32_t index, void *arg); int workqueue_terminate(struct workqueue *wq); void workqueue_destroy(struct workqueue *wq); #endif /* __LIBFROG_WORKQUEUE_H__ */ xfsprogs-5.3.0/libhandle/Makefile0000644000175000017500000000073513435336036016641 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTLIBRARY = libhandle.la LT_CURRENT = 1 LT_REVISION = 3 LT_AGE = 0 LTLDFLAGS += -Wl,--version-script,libhandle.sym CFILES = handle.c jdm.c LSRCFILES = libhandle.sym default: ltdepend $(LTLIBRARY) include $(BUILDRULES) install: default $(INSTALL_LTLIB) install-dev: default $(INSTALL_LTLIB_DEV) -include .ltdep xfsprogs-5.3.0/libhandle/handle.c0000644000175000017500000002154613435336036016603 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "platform_defs.h" #include "xfs.h" #include "handle.h" #include "parent.h" /* just pick a value we know is more than big enough */ #define MAXHANSIZ 64 /* * The actual content of a handle is supposed to be opaque here. * But, to do handle_to_fshandle, we need to know what it is. Sigh. * However we can get by with knowing only that the first 8 bytes of * a file handle are the file system ID, and that a file system handle * consists of only those 8 bytes. */ #define FSIDSIZE 8 typedef union { int fd; char *path; } comarg_t; static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); static int handle_to_fsfd(void *, char **); static char *path_to_fspath(char *path); /* * Filesystem Handle -> Open File Descriptor Cache * * Maps filesystem handles to a corresponding open file descriptor for that * filesystem. We need this because we're doing handle operations via xfsctl * and we need to remember the open file descriptor for each filesystem. */ struct fdhash { int fsfd; char fsh[FSIDSIZE]; struct fdhash *fnxt; char fspath[MAXPATHLEN]; }; static struct fdhash *fdhash_head = NULL; void fshandle_destroy(void) { struct fdhash *nexth; struct fdhash *h = fdhash_head; while (h) { nexth = h->fnxt; free(h); h = nexth; } fdhash_head = NULL; } int path_to_fshandle( char *path, /* input, path to convert */ void **fshanp, /* output, pointer to data */ size_t *fshlen) /* output, size of returned data */ { int result; int fd; comarg_t obj; struct fdhash *fdhp; char *tmppath; char *fspath; fspath = path_to_fspath(path); if (fspath == NULL) return -1; fd = open(fspath, O_RDONLY); if (fd < 0) return -1; obj.path = path; result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_FSHANDLE, obj, fshanp, fshlen); if (result < 0) { close(fd); return result; } if (handle_to_fsfd(*fshanp, &tmppath) >= 0) { /* this filesystem is already in the cache */ close(fd); } else { /* new filesystem. add it to the cache */ fdhp = malloc(sizeof(struct fdhash)); if (fdhp == NULL) { free(*fshanp); close(fd); errno = ENOMEM; return -1; } fdhp->fsfd = fd; strncpy(fdhp->fspath, fspath, sizeof(fdhp->fspath)); memcpy(fdhp->fsh, *fshanp, FSIDSIZE); fdhp->fnxt = fdhash_head; fdhash_head = fdhp; } return result; } int path_to_handle( char *path, /* input, path to convert */ void **hanp, /* output, pointer to data */ size_t *hlen) /* output, size of returned data */ { int fd; int result; comarg_t obj; char *fspath; fspath = path_to_fspath(path); if (fspath == NULL) return -1; fd = open(fspath, O_RDONLY); if (fd < 0) return -1; obj.path = path; result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_HANDLE, obj, hanp, hlen); close(fd); return result; } /* Given a path, return a suitable "fspath" for use in obtaining * an fd for xfsctl calls. For regular files and directories the * input path is sufficient. For other types the parent directory * is used to avoid issues with opening dangling symlinks and * potentially blocking in an open on a named pipe. Also * symlinks to files on other filesystems would be a problem, * since an fd would be obtained for the wrong fs. */ static char * path_to_fspath(char *path) { static char dirpath[MAXPATHLEN]; struct stat statbuf; if (lstat(path, &statbuf) != 0) return NULL; if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)) return path; strncpy(dirpath, path, MAXPATHLEN); dirpath[MAXPATHLEN-1] = '\0'; return dirname(dirpath); } int fd_to_handle ( int fd, /* input, file descriptor */ void **hanp, /* output, pointer to data */ size_t *hlen) /* output, size of returned data */ { comarg_t obj; obj.fd = fd; return obj_to_handle(NULL, fd, XFS_IOC_FD_TO_HANDLE, obj, hanp, hlen); } int handle_to_fshandle( void *hanp, size_t hlen, void **fshanp, size_t *fshlen) { if (hlen < FSIDSIZE) { errno = EINVAL; return -1; } *fshanp = malloc(FSIDSIZE); if (*fshanp == NULL) { errno = ENOMEM; return -1; } *fshlen = FSIDSIZE; memcpy(*fshanp, hanp, FSIDSIZE); return 0; } static int handle_to_fsfd(void *hanp, char **path) { struct fdhash *fdhp; /* * Look in cache for matching fsid field in the handle * (which is at the start of the handle). * When found return the file descriptor and path that * we have in the cache. */ for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) { if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) { *path = fdhp->fspath; return fdhp->fsfd; } } errno = EBADF; return -1; } static int obj_to_handle( char *fspath, int fsfd, unsigned int opcode, comarg_t obj, void **hanp, size_t *hlen) { char hbuf [MAXHANSIZ]; int ret; uint32_t handlen; xfs_fsop_handlereq_t hreq; if (opcode == XFS_IOC_FD_TO_HANDLE) { hreq.fd = obj.fd; hreq.path = NULL; } else { hreq.fd = 0; hreq.path = obj.path; } hreq.oflags = O_LARGEFILE; hreq.ihandle = NULL; hreq.ihandlen = 0; hreq.ohandle = hbuf; hreq.ohandlen = &handlen; ret = xfsctl(fspath, fsfd, opcode, &hreq); if (ret) return ret; *hanp = malloc(handlen); if (*hanp == NULL) { errno = ENOMEM; return -1; } memcpy(*hanp, hbuf, handlen); *hlen = handlen; return 0; } int open_by_fshandle( void *fshanp, size_t fshlen, int rw) { int fsfd; char *path; xfs_fsop_handlereq_t hreq; if ((fsfd = handle_to_fsfd(fshanp, &path)) < 0) return -1; hreq.fd = 0; hreq.path = NULL; hreq.oflags = rw | O_LARGEFILE; hreq.ihandle = fshanp; hreq.ihandlen = fshlen; hreq.ohandle = NULL; hreq.ohandlen = NULL; return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq); } int open_by_handle( void *hanp, size_t hlen, int rw) { int fsfd; char *path; xfs_fsop_handlereq_t hreq; if ((fsfd = handle_to_fsfd(hanp, &path)) < 0) return -1; hreq.fd = 0; hreq.path = NULL; hreq.oflags = rw | O_LARGEFILE; hreq.ihandle = hanp; hreq.ihandlen = hlen; hreq.ohandle = NULL; hreq.ohandlen = NULL; return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq); } int readlink_by_handle( void *hanp, size_t hlen, void *buf, size_t bufsiz) { int fd; __u32 buflen = (__u32)bufsiz; char *path; xfs_fsop_handlereq_t hreq; if ((fd = handle_to_fsfd(hanp, &path)) < 0) return -1; hreq.fd = 0; hreq.path = NULL; hreq.oflags = O_LARGEFILE; hreq.ihandle = hanp; hreq.ihandlen = hlen; hreq.ohandle = buf; hreq.ohandlen = &buflen; return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq); } /*ARGSUSED4*/ int attr_multi_by_handle( void *hanp, size_t hlen, void *buf, int rtrvcnt, int flags) { int fd; char *path; xfs_fsop_attrmulti_handlereq_t amhreq; if ((fd = handle_to_fsfd(hanp, &path)) < 0) return -1; amhreq.hreq.fd = 0; amhreq.hreq.path = NULL; amhreq.hreq.oflags = O_LARGEFILE; amhreq.hreq.ihandle = hanp; amhreq.hreq.ihandlen = hlen; amhreq.hreq.ohandle = NULL; amhreq.hreq.ohandlen = NULL; amhreq.opcount = rtrvcnt; amhreq.ops = buf; return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq); } int attr_list_by_handle( void *hanp, size_t hlen, void *buf, size_t bufsize, int flags, struct attrlist_cursor *cursor) { int error, fd; char *path; xfs_fsop_attrlist_handlereq_t alhreq; if ((fd = handle_to_fsfd(hanp, &path)) < 0) return -1; alhreq.hreq.fd = 0; alhreq.hreq.path = NULL; alhreq.hreq.oflags = O_LARGEFILE; alhreq.hreq.ihandle = hanp; alhreq.hreq.ihandlen = hlen; alhreq.hreq.ohandle = NULL; alhreq.hreq.ohandlen = NULL; memcpy(&alhreq.pos, cursor, sizeof(alhreq.pos)); alhreq.flags = flags; alhreq.buffer = buf; alhreq.buflen = bufsize; /* prevent needless EINVAL from the kernel */ if (alhreq.buflen > XFS_XATTR_LIST_MAX) alhreq.buflen = XFS_XATTR_LIST_MAX; error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq); memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos)); return error; } int parents_by_handle( void *hanp, size_t hlen, parent_t *buf, size_t bufsiz, unsigned int *count) { errno = EOPNOTSUPP; return -1; } int parentpaths_by_handle( void *hanp, size_t hlen, parent_t *buf, size_t bufsiz, unsigned int *count) { errno = EOPNOTSUPP; return -1; } int fssetdm_by_handle( void *hanp, size_t hlen, struct fsdmidata *fsdmidata) { int fd; char *path; xfs_fsop_setdm_handlereq_t dmhreq; if ((fd = handle_to_fsfd(hanp, &path)) < 0) return -1; dmhreq.hreq.fd = 0; dmhreq.hreq.path = NULL; dmhreq.hreq.oflags = O_LARGEFILE; dmhreq.hreq.ihandle = hanp; dmhreq.hreq.ihandlen = hlen; dmhreq.hreq.ohandle = NULL; dmhreq.hreq.ohandlen = NULL; dmhreq.data = fsdmidata; return xfsctl(path, fd, XFS_IOC_FSSETDM_BY_HANDLE, &dmhreq); } /*ARGSUSED1*/ void free_handle( void *hanp, size_t hlen) { free(hanp); } xfsprogs-5.3.0/libhandle/jdm.c0000644000175000017500000001047613570057155016124 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 1995, 2001-2002, 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "xfs.h" #include "handle.h" #include "jdm.h" #include "parent.h" /* internal fshandle - typecast to a void for external use */ #define FSHANDLE_SZ 8 typedef struct fshandle { char fsh_space[FSHANDLE_SZ]; } fshandle_t; /* private file handle - for use by open_by_fshandle */ #define FILEHANDLE_SZ 24 #define FILEHANDLE_SZ_FOLLOWING 14 #define FILEHANDLE_SZ_PAD 2 typedef struct filehandle { fshandle_t fh_fshandle; /* handle of fs containing this inode */ int16_t fh_sz_following; /* bytes in handle after this member */ char fh_pad[FILEHANDLE_SZ_PAD]; /* padding, must be zeroed */ uint32_t fh_gen; /* generation count */ xfs_ino_t fh_ino; /* 64 bit ino */ } filehandle_t; static void jdm_fill_filehandle( filehandle_t *handlep, fshandle_t *fshandlep, struct xfs_bstat *statp) { handlep->fh_fshandle = *fshandlep; handlep->fh_sz_following = FILEHANDLE_SZ_FOLLOWING; memset(handlep->fh_pad, 0, FILEHANDLE_SZ_PAD); handlep->fh_gen = statp->bs_gen; handlep->fh_ino = statp->bs_ino; } jdm_fshandle_t * jdm_getfshandle( char *mntpnt ) { fshandle_t *fshandlep; size_t fshandlesz; char resolved[MAXPATHLEN]; /* sanity checks */ ASSERT( sizeof( fshandle_t ) == FSHANDLE_SZ ); ASSERT( sizeof( filehandle_t ) == FILEHANDLE_SZ ); ASSERT( sizeof( filehandle_t ) - offsetofmember( filehandle_t, fh_pad ) == FILEHANDLE_SZ_FOLLOWING ); ASSERT( sizeofmember( filehandle_t, fh_pad ) == FILEHANDLE_SZ_PAD ); ASSERT( FILEHANDLE_SZ_PAD == sizeof( int16_t )); fshandlep = NULL; /* for lint */ fshandlesz = sizeof( *fshandlep ); if (!realpath( mntpnt, resolved )) return NULL; if (path_to_fshandle( resolved, ( void ** )&fshandlep, &fshandlesz )) return NULL; assert( fshandlesz == sizeof( *fshandlep )); return ( jdm_fshandle_t * )fshandlep; } /* externally visible functions */ void jdm_new_filehandle( jdm_filehandle_t **handlep, size_t *hlen, jdm_fshandle_t *fshandlep, struct xfs_bstat *statp) { /* allocate and fill filehandle */ *hlen = sizeof(filehandle_t); *handlep = (filehandle_t *) malloc(*hlen); if (*handlep) jdm_fill_filehandle(*handlep, (fshandle_t *) fshandlep, statp); } /* ARGSUSED */ void jdm_delete_filehandle( jdm_filehandle_t *handlep, size_t hlen ) { free(handlep); } intgen_t jdm_open( jdm_fshandle_t *fshp, struct xfs_bstat *statp, intgen_t oflags ) { fshandle_t *fshandlep = ( fshandle_t * )fshp; filehandle_t filehandle; intgen_t fd; jdm_fill_filehandle( &filehandle, fshandlep, statp ); fd = open_by_fshandle( ( void * )&filehandle, sizeof( filehandle ), oflags ); return fd; } intgen_t jdm_readlink( jdm_fshandle_t *fshp, struct xfs_bstat *statp, char *bufp, size_t bufsz ) { fshandle_t *fshandlep = ( fshandle_t * )fshp; filehandle_t filehandle; intgen_t rval; jdm_fill_filehandle( &filehandle, fshandlep, statp ); rval = readlink_by_handle( ( void * )&filehandle, sizeof( filehandle ), ( void * )bufp, bufsz ); return rval; } int jdm_attr_multi( jdm_fshandle_t *fshp, struct xfs_bstat *statp, char *bufp, int rtrvcnt, int flags) { fshandle_t *fshandlep = ( fshandle_t * )fshp; filehandle_t filehandle; int rval; jdm_fill_filehandle( &filehandle, fshandlep, statp ); rval = attr_multi_by_handle ( ( void * )&filehandle, sizeof( filehandle ), (void *) bufp, rtrvcnt, flags); return rval; } int jdm_attr_list( jdm_fshandle_t *fshp, struct xfs_bstat *statp, char *bufp, size_t bufsz, int flags, struct attrlist_cursor *cursor) { fshandle_t *fshandlep = ( fshandle_t * )fshp; filehandle_t filehandle; int rval; /* prevent needless EINVAL from the kernel */ if (bufsz > XFS_XATTR_LIST_MAX) bufsz = XFS_XATTR_LIST_MAX; jdm_fill_filehandle( &filehandle, fshandlep, statp ); rval = attr_list_by_handle (( void * )&filehandle, sizeof( filehandle ), bufp, bufsz, flags, cursor); return rval; } int jdm_parents( jdm_fshandle_t *fshp, struct xfs_bstat *statp, parent_t *bufp, size_t bufsz, unsigned int *count) { errno = EOPNOTSUPP; return -1; } int jdm_parentpaths( jdm_fshandle_t *fshp, struct xfs_bstat *statp, parent_t *bufp, size_t bufsz, unsigned int *count) { errno = EOPNOTSUPP; return -1; } xfsprogs-5.3.0/libhandle/libhandle.sym0000644000175000017500000000147313034246041017644 0ustar nathansnathans/* * The symbol versioning ensures that a new application requiring symbol foo() * can't run with old libhandle.so not providing foo() - the global SONAME * version info can't enforce this since we never change the SONAME. * * Older versions of libhandle (<= 1.0.3) do not to use symbol versioning -- * all the original symbols are in LIBHANDLE_1.0.3 now. */ LIBHANDLE_1.0.3 { global: /* handle.h APIs */ path_to_handle; path_to_fshandle; handle_to_fshandle; free_handle; open_by_fshandle; open_by_handle; readlink_by_handle; attr_multi_by_handle; attr_list_by_handle; parents_by_handle; parentpaths_by_handle; fssetdm_by_handle; /* jdm.h APIs */ jdm_getfshandle; jdm_new_filehandle; jdm_delete_filehandle; jdm_open; jdm_readlink; jdm_attr_multi; jdm_attr_list; jdm_parents; jdm_parentpaths; }; xfsprogs-5.3.0/libxcmd/Makefile0000644000175000017500000000107413435336036016336 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTLIBRARY = libxcmd.la LT_CURRENT = 0 LT_REVISION = 0 LT_AGE = 0 CFILES = command.c input.c help.c quit.c ifeq ($(ENABLE_READLINE),yes) LCFLAGS += -DENABLE_READLINE LTLIBS += $(LIBREADLINE) $(LIBTERMCAP) endif ifeq ($(ENABLE_EDITLINE),yes) LCFLAGS += -DENABLE_EDITLINE LTLIBS += $(LIBEDITLINE) $(LIBTERMCAP) endif default: ltdepend $(LTLIBRARY) include $(BUILDRULES) install install-dev: default -include .ltdep xfsprogs-5.3.0/libxcmd/command.c0000644000175000017500000001136713435336036016466 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "input.h" cmdinfo_t *cmdtab; int ncmds; static iterfunc_t iter_func; static checkfunc_t check_func; struct cmdline { char *cmdline; bool iterate; }; static int ncmdline; static struct cmdline *cmdline; static int compare(const void *a, const void *b) { return strcmp(((const cmdinfo_t *)a)->name, ((const cmdinfo_t *)b)->name); } void add_command( const cmdinfo_t *ci) { cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); cmdtab[ncmds - 1] = *ci; qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); } static int check_command( const cmdinfo_t *ci) { /* always run internal library supplied commands */ if (ci->flags & CMD_FLAG_LIBRARY) return 1; if (check_func) return check_func(ci); return 1; } void add_check_command( checkfunc_t cf) { check_func = cf; } int command_usage( const cmdinfo_t *ci) { printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); return 0; } int command( const cmdinfo_t *ct, int argc, char **argv) { char *cmd = argv[0]; if (!check_command(ct)) return 0; if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { if (ct->argmax == -1) fprintf(stderr, _("bad argument count %d to %s, expected at least %d arguments\n"), argc-1, cmd, ct->argmin); else if (ct->argmin == ct->argmax) fprintf(stderr, _("bad argument count %d to %s, expected %d arguments\n"), argc-1, cmd, ct->argmin); else fprintf(stderr, _("bad argument count %d to %s, expected between %d and %d arguments\n"), argc-1, cmd, ct->argmin, ct->argmax); return 0; } platform_getoptreset(); return ct->cfunc(argc, argv); } const cmdinfo_t * find_command( const char *cmd) { cmdinfo_t *ct; for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { if (strcmp(ct->name, cmd) == 0 || (ct->altname && strcmp(ct->altname, cmd) == 0)) return (const cmdinfo_t *)ct; } return NULL; } void add_user_command(char *optarg) { ncmdline++; cmdline = realloc(cmdline, sizeof(struct cmdline) * (ncmdline)); if (!cmdline) { perror("realloc"); exit(1); } cmdline[ncmdline-1].cmdline = optarg; cmdline[ncmdline-1].iterate = true; } void add_oneshot_user_command(char *optarg) { ncmdline++; cmdline = realloc(cmdline, sizeof(struct cmdline) * (ncmdline)); if (!cmdline) { perror("realloc"); exit(1); } cmdline[ncmdline-1].cmdline = optarg; cmdline[ncmdline-1].iterate = false; } /* * Run a command, iterating as necessary. Return 0 for success, non-zero * if an error occurred. Errors terminate loop iteration immediately. */ static int iterate_command( const cmdinfo_t *ct, int argc, char **argv) { int error = 0; int j; /* if there's nothing to iterate, we're done! */ if (!iter_func) return 0; for (j = iter_func(0); j; j = iter_func(j)) { error = command(ct, argc, argv); if (error) break; } return error; } void add_command_iterator( iterfunc_t func) { iter_func = func; } static int process_input( char *input, bool iterate) { char **v; const cmdinfo_t *ct; int c = 0; int error = 0; v = breakline(input, &c); if (!c) goto out; ct = find_command(v[0]); if (!ct) { fprintf(stderr, _("command \"%s\" not found\n"), v[0]); goto out; } /* oneshot commands don't iterate */ if (!iterate || (ct->flags & CMD_FLAG_ONESHOT)) error = command(ct, c, v); else error = iterate_command(ct, c, v); out: doneline(input, v); return error; } void command_loop(void) { char *input; int done = 0; int i; if (!cmdline) { /* interactive mode */ while (!done) { input = fetchline(); if (!input) break; done = process_input(input, false); } return; } /* command line mode */ for (i = 0; !done && i < ncmdline; i++) { input = strdup(cmdline[i].cmdline); if (!input) { fprintf(stderr, _("cannot strdup command '%s': %s\n"), cmdline[i].cmdline, strerror(errno)); exit(1); } done = process_input(input, cmdline[i].iterate); } free(cmdline); return; } void report_io_times( const char *verb, struct timeval *t2, long long offset, long long count, long long total, int ops, int compact) { char s1[64], s2[64], ts[64]; timestr(t2, ts, sizeof(ts), compact ? VERBOSE_FIXED_TIME : 0); if (!compact) { cvtstr((double)total, s1, sizeof(s1)); cvtstr(tdiv((double)total, *t2), s2, sizeof(s2)); printf(_("%s %lld/%lld bytes at offset %lld\n"), verb, total, count, (long long)offset); printf(_("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n"), s1, ops, ts, s2, tdiv((double)ops, *t2)); } else {/* bytes,ops,time,bytes/sec,ops/sec */ printf("%lld,%d,%s,%.3f,%.3f\n", total, ops, ts, tdiv((double)total, *t2), tdiv((double)ops, *t2)); } } xfsprogs-5.3.0/libxcmd/help.c0000644000175000017500000000275713435336036016003 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "../quota/init.h" static cmdinfo_t help_cmd; static void help_onecmd(const char *cmd, const cmdinfo_t *ct); static void help_oneline(const char *cmd, const cmdinfo_t *ct); static void help_all(void) { const cmdinfo_t *ct; for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) help_oneline(ct->name, ct); printf(_("\nUse 'help commandname' for extended help.\n")); } static int help_f( int argc, char **argv) { const cmdinfo_t *ct; if (argc == 1) { help_all(); return 0; } ct = find_command(argv[1]); if (ct == NULL) { printf(_("command %s not found\n"), argv[1]); return 0; } help_onecmd(argv[1], ct); return 0; } static void help_onecmd( const char *cmd, const cmdinfo_t *ct) { help_oneline(cmd, ct); if (ct->help) ct->help(); } static void help_oneline( const char *cmd, const cmdinfo_t *ct) { if (cmd) printf("%s ", cmd); else { printf("%s ", ct->name); if (ct->altname) printf("(or %s) ", ct->altname); } if (ct->args) printf("%s ", ct->args); printf("-- %s\n", ct->oneline); } void help_init(void) { help_cmd.name = "help"; help_cmd.altname = "?"; help_cmd.cfunc = help_f; help_cmd.argmin = 0; help_cmd.argmax = 1; help_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_LIBRARY; help_cmd.args = _("[command]"); help_cmd.oneline = _("help for one or all commands"); add_command(&help_cmd); } xfsprogs-5.3.0/libxcmd/input.c0000644000175000017500000001007713435336036016204 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "input.h" #include #include #if defined(ENABLE_READLINE) # include # include #elif defined(ENABLE_EDITLINE) # include #endif extern char *progname; static char * get_prompt(void) { static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; if (!prompt[0]) snprintf(prompt, sizeof(prompt), "%s> ", progname); return prompt; } #if defined(ENABLE_READLINE) char * fetchline(void) { char *line; line = readline(get_prompt()); if (line && *line) add_history(line); return line; } #elif defined(ENABLE_EDITLINE) static char *el_get_prompt(EditLine *e) { return get_prompt(); } char * fetchline(void) { static EditLine *el; static History *hist; HistEvent hevent; char *line; int count; if (!el) { hist = history_init(); history(hist, &hevent, H_SETSIZE, 100); el = el_init(progname, stdin, stdout, stderr); el_source(el, NULL); el_set(el, EL_SIGNAL, 1); el_set(el, EL_PROMPT, el_get_prompt); el_set(el, EL_HIST, history, (const char *)hist); } line = strdup(el_gets(el, &count)); if (line) { if (count > 0) line[count-1] = '\0'; if (*line) history(hist, &hevent, H_ENTER, line); } return line; } #else # define MAXREADLINESZ 1024 char * fetchline(void) { char *p, *line = malloc(MAXREADLINESZ); if (!line) return NULL; printf("%s", get_prompt()); fflush(stdout); if (!fgets(line, MAXREADLINESZ, stdin)) { free(line); return NULL; } p = line + strlen(line); if (p != line && p[-1] == '\n') p[-1] = '\0'; return line; } #endif char ** breakline( char *input, int *count) { int c = 0; char *p; char **rval = calloc(sizeof(char *), 1); while (rval && (p = strsep(&input, " ")) != NULL) { if (!*p) continue; c++; rval = realloc(rval, sizeof(*rval) * (c + 1)); if (!rval) { c = 0; break; } rval[c - 1] = p; rval[c] = NULL; } *count = c; return rval; } void doneline( char *input, char **vec) { free(input); free(vec); } struct timeval tsub(struct timeval t1, struct timeval t2) { t1.tv_usec -= t2.tv_usec; if (t1.tv_usec < 0) { t1.tv_usec += 1000000; t1.tv_sec--; } t1.tv_sec -= t2.tv_sec; return t1; } double tdiv(double value, struct timeval tv) { return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); } #define HOURS(sec) ((sec) / (60 * 60)) #define MINUTES(sec) (((sec) % (60 * 60)) / 60) #define SECONDS(sec) ((sec) % 60) #define USEC_TO_100THS(usec) ((usec) / 1000 / 10) void timestr( struct timeval *tv, char *ts, size_t size, int format) { if (format & TERSE_FIXED_TIME) { if (!HOURS(tv->tv_sec)) { snprintf(ts, size, "%u:%02u.%02u", (unsigned int) MINUTES(tv->tv_sec), (unsigned int) SECONDS(tv->tv_sec), (unsigned int) USEC_TO_100THS(tv->tv_usec)); return; } format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ } if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { snprintf(ts, size, "%u:%02u:%02u.%02u", (unsigned int) HOURS(tv->tv_sec), (unsigned int) MINUTES(tv->tv_sec), (unsigned int) SECONDS(tv->tv_sec), (unsigned int) USEC_TO_100THS(tv->tv_usec)); } else { snprintf(ts, size, "0.%04u sec", (unsigned int) tv->tv_usec / 100); } } /* * Convert from a pair of arbitrary user strings into a timespec. */ int timespec_from_string( const char * secs, const char * nsecs, struct timespec * ts) { char* p; if (!secs || !nsecs || !ts) return 1; ts->tv_sec = strtoull(secs, &p, 0); if (*p) return 1; ts->tv_nsec = strtoull(nsecs, &p, 0); if (*p) return 1; return 0; } bool isdigits_only( const char *str) { int i; for (i = 0; i < strlen(str); i++) { if (!isdigit(str[i])) return false; } return true; } #define HAVE_FTW_H 1 /* TODO: configure me */ #ifndef HAVE_FTW_H int nftw( char *dir, int (*fn)(const char *, const struct stat *, int, struct FTW *), int depth, int flags) { fprintf(stderr, "%s: not implemented, no recursion available\n", __FUNCTION__); return 0; } #endif xfsprogs-5.3.0/libxcmd/quit.c0000644000175000017500000000107013435336036016020 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "platform_defs.h" #include "command.h" #include "../quota/init.h" static cmdinfo_t quit_cmd; /* ARGSUSED */ static int quit_f( int argc, char **argv) { return 1; } void quit_init(void) { quit_cmd.name = "quit"; quit_cmd.altname = "q"; quit_cmd.cfunc = quit_f; quit_cmd.argmin = -1; quit_cmd.argmax = -1; quit_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_LIBRARY; quit_cmd.oneline = _("exit the program"); add_command(&quit_cmd); } xfsprogs-5.3.0/libxfs/Makefile0000644000175000017500000000534513570057155016212 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTLIBRARY = libxfs.la LT_CURRENT = 0 LT_REVISION = 0 LT_AGE = 0 # headers to install in include/xfs PKGHFILES = xfs_fs.h \ xfs_types.h \ xfs_da_format.h \ xfs_format.h \ xfs_log_format.h HFILES = \ xfs_ag_resv.h \ xfs_alloc.h \ xfs_alloc_btree.h \ xfs_attr_leaf.h \ xfs_attr_sf.h \ xfs_bit.h \ xfs_bmap.h \ xfs_bmap_btree.h \ xfs_btree.h \ xfs_attr_remote.h \ xfs_cksum.h \ xfs_da_btree.h \ xfs_dir2.h \ xfs_errortag.h \ xfs_ialloc.h \ xfs_ialloc_btree.h \ xfs_inode_buf.h \ xfs_inode_fork.h \ xfs_quota_defs.h \ xfs_refcount.h \ xfs_refcount_btree.h \ xfs_rmap.h \ xfs_rmap_btree.h \ xfs_sb.h \ xfs_shared.h \ xfs_trans_resv.h \ xfs_trans_space.h \ libxfs_io.h \ libxfs_api_defs.h \ init.h \ libxfs_priv.h \ xfs_dir2_priv.h CFILES = cache.c \ defer_item.c \ init.c \ kmem.c \ logitem.c \ rdwr.c \ trans.c \ util.c \ xfs_ag.c \ xfs_ag_resv.c \ xfs_alloc.c \ xfs_alloc_btree.c \ xfs_attr.c \ xfs_attr_leaf.c \ xfs_attr_remote.c \ xfs_bit.c \ xfs_bmap.c \ xfs_bmap_btree.c \ xfs_btree.c \ xfs_da_btree.c \ xfs_da_format.c \ xfs_defer.c \ xfs_dir2.c \ xfs_dir2_block.c \ xfs_dir2_data.c \ xfs_dir2_leaf.c \ xfs_dir2_node.c \ xfs_dir2_sf.c \ xfs_dquot_buf.c \ xfs_ialloc.c \ xfs_iext_tree.c \ xfs_inode_buf.c \ xfs_inode_fork.c \ xfs_ialloc_btree.c \ xfs_log_rlimit.c \ xfs_refcount.c \ xfs_refcount_btree.c \ xfs_rmap.c \ xfs_rmap_btree.c \ xfs_rtbitmap.c \ xfs_sb.c \ xfs_symlink_remote.c \ xfs_trans_inode.c \ xfs_trans_resv.c \ xfs_types.c # # Tracing flags: # -DIO_DEBUG reads and writes of buffers # -DMEM_DEBUG all zone memory use # -DLI_DEBUG log item (ino/buf) manipulation # -DXACT_DEBUG transaction state changes # #LCFLAGS += FCFLAGS = -I. LTLIBS = $(LIBPTHREAD) $(LIBRT) # don't try linking xfs_repair with a debug libxfs. DEBUG = -DNDEBUG default: ltdepend $(LTLIBRARY) # set up include/xfs header directory include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_INC_DIR) install-headers: $(addsuffix -hdrs, $(PKGHFILES)) %-hdrs: $(Q)$(LN_S) -f $(CURDIR)/$* $(TOPDIR)/include/xfs/$* install-dev: install $(INSTALL) -m 644 $(PKGHFILES) $(PKG_INC_DIR) # We need to install the headers before building the dependencies. If we # include the .ltdep file, the makefile decides that it needs to build the # dependencies to remake the makefile before running the header install target, # hence making it impossible to avoid errors being thrown by the dependency # generation. Hence we play games so that we only include this file if we aren't # running the install-headers target. ifndef NODEP -include .ltdep endif xfsprogs-5.3.0/libxfs/cache.c0000644000175000017500000004172513435336036015761 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include #include #include #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_bit.h" #define CACHE_DEBUG 1 #undef CACHE_DEBUG #define CACHE_DEBUG 1 #undef CACHE_ABORT /* #define CACHE_ABORT 1 */ #define CACHE_SHAKE_COUNT 64 static unsigned int cache_generic_bulkrelse(struct cache *, struct list_head *); struct cache * cache_init( int flags, unsigned int hashsize, struct cache_operations *cache_operations) { struct cache * cache; unsigned int i, maxcount; maxcount = hashsize * HASH_CACHE_RATIO; if (!(cache = malloc(sizeof(struct cache)))) return NULL; if (!(cache->c_hash = calloc(hashsize, sizeof(struct cache_hash)))) { free(cache); return NULL; } cache->c_flags = flags; cache->c_count = 0; cache->c_max = 0; cache->c_hits = 0; cache->c_misses = 0; cache->c_maxcount = maxcount; cache->c_hashsize = hashsize; cache->c_hashshift = libxfs_highbit32(hashsize); cache->hash = cache_operations->hash; cache->alloc = cache_operations->alloc; cache->flush = cache_operations->flush; cache->relse = cache_operations->relse; cache->compare = cache_operations->compare; cache->bulkrelse = cache_operations->bulkrelse ? cache_operations->bulkrelse : cache_generic_bulkrelse; pthread_mutex_init(&cache->c_mutex, NULL); for (i = 0; i < hashsize; i++) { list_head_init(&cache->c_hash[i].ch_list); cache->c_hash[i].ch_count = 0; pthread_mutex_init(&cache->c_hash[i].ch_mutex, NULL); } for (i = 0; i <= CACHE_DIRTY_PRIORITY; i++) { list_head_init(&cache->c_mrus[i].cm_list); cache->c_mrus[i].cm_count = 0; pthread_mutex_init(&cache->c_mrus[i].cm_mutex, NULL); } return cache; } static void cache_expand( struct cache * cache) { pthread_mutex_lock(&cache->c_mutex); #ifdef CACHE_DEBUG fprintf(stderr, "doubling cache size to %d\n", 2 * cache->c_maxcount); #endif cache->c_maxcount *= 2; pthread_mutex_unlock(&cache->c_mutex); } void cache_walk( struct cache * cache, cache_walk_t visit) { struct cache_hash * hash; struct list_head * head; struct list_head * pos; unsigned int i; for (i = 0; i < cache->c_hashsize; i++) { hash = &cache->c_hash[i]; head = &hash->ch_list; pthread_mutex_lock(&hash->ch_mutex); for (pos = head->next; pos != head; pos = pos->next) visit((struct cache_node *)pos); pthread_mutex_unlock(&hash->ch_mutex); } } #ifdef CACHE_ABORT #define cache_abort() abort() #else #define cache_abort() do { } while (0) #endif #ifdef CACHE_DEBUG static void cache_zero_check( struct cache_node * node) { if (node->cn_count > 0) { fprintf(stderr, "%s: refcount is %u, not zero (node=%p)\n", __FUNCTION__, node->cn_count, node); cache_abort(); } } #define cache_destroy_check(c) cache_walk((c), cache_zero_check) #else #define cache_destroy_check(c) do { } while (0) #endif void cache_destroy( struct cache * cache) { unsigned int i; cache_destroy_check(cache); for (i = 0; i < cache->c_hashsize; i++) { list_head_destroy(&cache->c_hash[i].ch_list); pthread_mutex_destroy(&cache->c_hash[i].ch_mutex); } for (i = 0; i <= CACHE_DIRTY_PRIORITY; i++) { list_head_destroy(&cache->c_mrus[i].cm_list); pthread_mutex_destroy(&cache->c_mrus[i].cm_mutex); } pthread_mutex_destroy(&cache->c_mutex); free(cache->c_hash); free(cache); } static unsigned int cache_generic_bulkrelse( struct cache * cache, struct list_head * list) { struct cache_node * node; unsigned int count = 0; while (!list_empty(list)) { node = list_entry(list->next, struct cache_node, cn_mru); pthread_mutex_destroy(&node->cn_mutex); list_del_init(&node->cn_mru); cache->relse(node); count++; } return count; } /* * Park unflushable nodes on their own special MRU so that cache_shake() doesn't * end up repeatedly scanning them in the futile attempt to clean them before * reclaim. */ static void cache_add_to_dirty_mru( struct cache *cache, struct cache_node *node) { struct cache_mru *mru = &cache->c_mrus[CACHE_DIRTY_PRIORITY]; pthread_mutex_lock(&mru->cm_mutex); node->cn_old_priority = node->cn_priority; node->cn_priority = CACHE_DIRTY_PRIORITY; list_add(&node->cn_mru, &mru->cm_list); mru->cm_count++; pthread_mutex_unlock(&mru->cm_mutex); } /* * We've hit the limit on cache size, so we need to start reclaiming nodes we've * used. The MRU specified by the priority is shaken. Returns new priority at * end of the call (in case we call again). We are not allowed to reclaim dirty * objects, so we have to flush them first. If flushing fails, we move them to * the "dirty, unreclaimable" list. * * Hence we skip priorities > CACHE_MAX_PRIORITY unless "purge" is set as we * park unflushable (and hence unreclaimable) buffers at these priorities. * Trying to shake unreclaimable buffer lists when there is memory pressure is a * waste of time and CPU and greatly slows down cache node recycling operations. * Hence we only try to free them if we are being asked to purge the cache of * all entries. */ static unsigned int cache_shake( struct cache * cache, unsigned int priority, bool purge) { struct cache_mru *mru; struct cache_hash * hash; struct list_head temp; struct list_head * head; struct list_head * pos; struct list_head * n; struct cache_node * node; unsigned int count; ASSERT(priority <= CACHE_DIRTY_PRIORITY); if (priority > CACHE_MAX_PRIORITY && !purge) priority = 0; mru = &cache->c_mrus[priority]; count = 0; list_head_init(&temp); head = &mru->cm_list; pthread_mutex_lock(&mru->cm_mutex); for (pos = head->prev, n = pos->prev; pos != head; pos = n, n = pos->prev) { node = list_entry(pos, struct cache_node, cn_mru); if (pthread_mutex_trylock(&node->cn_mutex) != 0) continue; /* memory pressure is not allowed to release dirty objects */ if (cache->flush(node) && !purge) { list_del(&node->cn_mru); mru->cm_count--; node->cn_priority = -1; pthread_mutex_unlock(&node->cn_mutex); cache_add_to_dirty_mru(cache, node); continue; } hash = cache->c_hash + node->cn_hashidx; if (pthread_mutex_trylock(&hash->ch_mutex) != 0) { pthread_mutex_unlock(&node->cn_mutex); continue; } ASSERT(node->cn_count == 0); ASSERT(node->cn_priority == priority); node->cn_priority = -1; list_move(&node->cn_mru, &temp); list_del_init(&node->cn_hash); hash->ch_count--; mru->cm_count--; pthread_mutex_unlock(&hash->ch_mutex); pthread_mutex_unlock(&node->cn_mutex); count++; if (!purge && count == CACHE_SHAKE_COUNT) break; } pthread_mutex_unlock(&mru->cm_mutex); if (count > 0) { cache->bulkrelse(cache, &temp); pthread_mutex_lock(&cache->c_mutex); cache->c_count -= count; pthread_mutex_unlock(&cache->c_mutex); } return (count == CACHE_SHAKE_COUNT) ? priority : ++priority; } /* * Allocate a new hash node (updating atomic counter in the process), * unless doing so will push us over the maximum cache size. */ static struct cache_node * cache_node_allocate( struct cache * cache, cache_key_t key) { unsigned int nodesfree; struct cache_node * node; pthread_mutex_lock(&cache->c_mutex); nodesfree = (cache->c_count < cache->c_maxcount); if (nodesfree) { cache->c_count++; if (cache->c_count > cache->c_max) cache->c_max = cache->c_count; } cache->c_misses++; pthread_mutex_unlock(&cache->c_mutex); if (!nodesfree) return NULL; node = cache->alloc(key); if (node == NULL) { /* uh-oh */ pthread_mutex_lock(&cache->c_mutex); cache->c_count--; pthread_mutex_unlock(&cache->c_mutex); return NULL; } pthread_mutex_init(&node->cn_mutex, NULL); list_head_init(&node->cn_mru); node->cn_count = 1; node->cn_priority = 0; node->cn_old_priority = -1; return node; } int cache_overflowed( struct cache * cache) { return cache->c_maxcount == cache->c_max; } static int __cache_node_purge( struct cache * cache, struct cache_node * node) { int count; struct cache_mru * mru; pthread_mutex_lock(&node->cn_mutex); count = node->cn_count; if (count != 0) { pthread_mutex_unlock(&node->cn_mutex); return count; } /* can't purge dirty objects */ if (cache->flush(node)) { pthread_mutex_unlock(&node->cn_mutex); return 1; } mru = &cache->c_mrus[node->cn_priority]; pthread_mutex_lock(&mru->cm_mutex); list_del_init(&node->cn_mru); mru->cm_count--; pthread_mutex_unlock(&mru->cm_mutex); pthread_mutex_unlock(&node->cn_mutex); pthread_mutex_destroy(&node->cn_mutex); list_del_init(&node->cn_hash); cache->relse(node); return 0; } /* * Lookup in the cache hash table. With any luck we'll get a cache * hit, in which case this will all be over quickly and painlessly. * Otherwise, we allocate a new node, taking care not to expand the * cache beyond the requested maximum size (shrink it if it would). * Returns one if hit in cache, otherwise zero. A node is _always_ * returned, however. */ int cache_node_get( struct cache * cache, cache_key_t key, struct cache_node ** nodep) { struct cache_node * node = NULL; struct cache_hash * hash; struct cache_mru * mru; struct list_head * head; struct list_head * pos; struct list_head * n; unsigned int hashidx; int priority = 0; int purged = 0; hashidx = cache->hash(key, cache->c_hashsize, cache->c_hashshift); hash = cache->c_hash + hashidx; head = &hash->ch_list; for (;;) { pthread_mutex_lock(&hash->ch_mutex); for (pos = head->next, n = pos->next; pos != head; pos = n, n = pos->next) { int result; node = list_entry(pos, struct cache_node, cn_hash); result = cache->compare(node, key); switch (result) { case CACHE_HIT: break; case CACHE_PURGE: if ((cache->c_flags & CACHE_MISCOMPARE_PURGE) && !__cache_node_purge(cache, node)) { purged++; hash->ch_count--; } /* FALL THROUGH */ case CACHE_MISS: goto next_object; } /* * node found, bump node's reference count, remove it * from its MRU list, and update stats. */ pthread_mutex_lock(&node->cn_mutex); if (node->cn_count == 0) { ASSERT(node->cn_priority >= 0); ASSERT(!list_empty(&node->cn_mru)); mru = &cache->c_mrus[node->cn_priority]; pthread_mutex_lock(&mru->cm_mutex); mru->cm_count--; list_del_init(&node->cn_mru); pthread_mutex_unlock(&mru->cm_mutex); if (node->cn_old_priority != -1) { ASSERT(node->cn_priority == CACHE_DIRTY_PRIORITY); node->cn_priority = node->cn_old_priority; node->cn_old_priority = -1; } } node->cn_count++; pthread_mutex_unlock(&node->cn_mutex); pthread_mutex_unlock(&hash->ch_mutex); pthread_mutex_lock(&cache->c_mutex); cache->c_hits++; pthread_mutex_unlock(&cache->c_mutex); *nodep = node; return 0; next_object: continue; /* what the hell, gcc? */ } pthread_mutex_unlock(&hash->ch_mutex); /* * not found, allocate a new entry */ node = cache_node_allocate(cache, key); if (node) break; priority = cache_shake(cache, priority, false); /* * We start at 0; if we free CACHE_SHAKE_COUNT we get * back the same priority, if not we get back priority+1. * If we exceed CACHE_MAX_PRIORITY all slots are full; grow it. */ if (priority > CACHE_MAX_PRIORITY) { priority = 0; cache_expand(cache); } } node->cn_hashidx = hashidx; /* add new node to appropriate hash */ pthread_mutex_lock(&hash->ch_mutex); hash->ch_count++; list_add(&node->cn_hash, &hash->ch_list); pthread_mutex_unlock(&hash->ch_mutex); if (purged) { pthread_mutex_lock(&cache->c_mutex); cache->c_count -= purged; pthread_mutex_unlock(&cache->c_mutex); } *nodep = node; return 1; } void cache_node_put( struct cache * cache, struct cache_node * node) { struct cache_mru * mru; pthread_mutex_lock(&node->cn_mutex); #ifdef CACHE_DEBUG if (node->cn_count < 1) { fprintf(stderr, "%s: node put on refcount %u (node=%p)\n", __FUNCTION__, node->cn_count, node); cache_abort(); } if (!list_empty(&node->cn_mru)) { fprintf(stderr, "%s: node put on node (%p) in MRU list\n", __FUNCTION__, node); cache_abort(); } #endif node->cn_count--; if (node->cn_count == 0) { /* add unreferenced node to appropriate MRU for shaker */ mru = &cache->c_mrus[node->cn_priority]; pthread_mutex_lock(&mru->cm_mutex); mru->cm_count++; list_add(&node->cn_mru, &mru->cm_list); pthread_mutex_unlock(&mru->cm_mutex); } pthread_mutex_unlock(&node->cn_mutex); } void cache_node_set_priority( struct cache * cache, struct cache_node * node, int priority) { if (priority < 0) priority = 0; else if (priority > CACHE_MAX_PRIORITY) priority = CACHE_MAX_PRIORITY; pthread_mutex_lock(&node->cn_mutex); ASSERT(node->cn_count > 0); node->cn_priority = priority; node->cn_old_priority = -1; pthread_mutex_unlock(&node->cn_mutex); } int cache_node_get_priority( struct cache_node * node) { int priority; pthread_mutex_lock(&node->cn_mutex); priority = node->cn_priority; pthread_mutex_unlock(&node->cn_mutex); return priority; } /* * Purge a specific node from the cache. Reference count must be zero. */ int cache_node_purge( struct cache * cache, cache_key_t key, struct cache_node * node) { struct list_head * head; struct list_head * pos; struct list_head * n; struct cache_hash * hash; int count = -1; hash = cache->c_hash + cache->hash(key, cache->c_hashsize, cache->c_hashshift); head = &hash->ch_list; pthread_mutex_lock(&hash->ch_mutex); for (pos = head->next, n = pos->next; pos != head; pos = n, n = pos->next) { if ((struct cache_node *)pos != node) continue; count = __cache_node_purge(cache, node); if (!count) hash->ch_count--; break; } pthread_mutex_unlock(&hash->ch_mutex); if (count == 0) { pthread_mutex_lock(&cache->c_mutex); cache->c_count--; pthread_mutex_unlock(&cache->c_mutex); } #ifdef CACHE_DEBUG if (count >= 1) { fprintf(stderr, "%s: refcount was %u, not zero (node=%p)\n", __FUNCTION__, count, node); cache_abort(); } if (count == -1) { fprintf(stderr, "%s: purge node not found! (node=%p)\n", __FUNCTION__, node); cache_abort(); } #endif return count == 0; } /* * Purge all nodes from the cache. All reference counts must be zero. */ void cache_purge( struct cache * cache) { int i; for (i = 0; i <= CACHE_DIRTY_PRIORITY; i++) cache_shake(cache, i, true); #ifdef CACHE_DEBUG if (cache->c_count != 0) { /* flush referenced nodes to disk */ cache_flush(cache); fprintf(stderr, "%s: shake on cache %p left %u nodes!?\n", __FUNCTION__, cache, cache->c_count); cache_abort(); } #endif } /* * Flush all nodes in the cache to disk. */ void cache_flush( struct cache * cache) { struct cache_hash * hash; struct list_head * head; struct list_head * pos; struct cache_node * node; int i; if (!cache->flush) return; for (i = 0; i < cache->c_hashsize; i++) { hash = &cache->c_hash[i]; pthread_mutex_lock(&hash->ch_mutex); head = &hash->ch_list; for (pos = head->next; pos != head; pos = pos->next) { node = (struct cache_node *)pos; pthread_mutex_lock(&node->cn_mutex); cache->flush(node); pthread_mutex_unlock(&node->cn_mutex); } pthread_mutex_unlock(&hash->ch_mutex); } } #define HASH_REPORT (3 * HASH_CACHE_RATIO) void cache_report( FILE *fp, const char *name, struct cache *cache) { int i; unsigned long count, index, total; unsigned long hash_bucket_lengths[HASH_REPORT + 2]; if ((cache->c_hits + cache->c_misses) == 0) return; /* report cache summary */ fprintf(fp, "%s: %p\n" "Max supported entries = %u\n" "Max utilized entries = %u\n" "Active entries = %u\n" "Hash table size = %u\n" "Hits = %llu\n" "Misses = %llu\n" "Hit ratio = %5.2f\n", name, cache, cache->c_maxcount, cache->c_max, cache->c_count, cache->c_hashsize, cache->c_hits, cache->c_misses, (double)cache->c_hits * 100 / (cache->c_hits + cache->c_misses) ); for (i = 0; i <= CACHE_MAX_PRIORITY; i++) fprintf(fp, "MRU %d entries = %6u (%3u%%)\n", i, cache->c_mrus[i].cm_count, cache->c_mrus[i].cm_count * 100 / cache->c_count); i = CACHE_DIRTY_PRIORITY; fprintf(fp, "Dirty MRU %d entries = %6u (%3u%%)\n", i, cache->c_mrus[i].cm_count, cache->c_mrus[i].cm_count * 100 / cache->c_count); /* report hash bucket lengths */ bzero(hash_bucket_lengths, sizeof(hash_bucket_lengths)); for (i = 0; i < cache->c_hashsize; i++) { count = cache->c_hash[i].ch_count; if (count > HASH_REPORT) index = HASH_REPORT + 1; else index = count; hash_bucket_lengths[index]++; } total = 0; for (i = 0; i < HASH_REPORT + 1; i++) { total += i * hash_bucket_lengths[i]; if (hash_bucket_lengths[i] == 0) continue; fprintf(fp, "Hash buckets with %2d entries %6ld (%3ld%%)\n", i, hash_bucket_lengths[i], (i * hash_bucket_lengths[i] * 100) / cache->c_count); } if (hash_bucket_lengths[i]) /* last report bucket is the overflow bucket */ fprintf(fp, "Hash buckets with >%2d entries %6ld (%3ld%%)\n", i - 1, hash_bucket_lengths[i], ((cache->c_count - total) * 100) / cache->c_count); } xfsprogs-5.3.0/libxfs/defer_item.c0000644000175000017500000002642313466663244017027 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_alloc.h" #include "xfs_rmap.h" #include "xfs_refcount.h" #include "xfs_bmap.h" #include "xfs_inode.h" /* Dummy defer item ops, since we don't do logging. */ /* Extent Freeing */ /* Sort bmap items by AG. */ static int xfs_extent_free_diff_items( void *priv, struct list_head *a, struct list_head *b) { struct xfs_mount *mp = priv; struct xfs_extent_free_item *ra; struct xfs_extent_free_item *rb; ra = container_of(a, struct xfs_extent_free_item, xefi_list); rb = container_of(b, struct xfs_extent_free_item, xefi_list); return XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) - XFS_FSB_TO_AGNO(mp, rb->xefi_startblock); } /* Get an EFI. */ STATIC void * xfs_extent_free_create_intent( struct xfs_trans *tp, unsigned int count) { return NULL; } /* Log a free extent to the intent item. */ STATIC void xfs_extent_free_log_item( struct xfs_trans *tp, void *intent, struct list_head *item) { } /* Get an EFD so we can process all the free extents. */ STATIC void * xfs_extent_free_create_done( struct xfs_trans *tp, void *intent, unsigned int count) { return NULL; } /* Process a free extent. */ STATIC int xfs_extent_free_finish_item( struct xfs_trans *tp, struct list_head *item, void *done_item, void **state) { struct xfs_extent_free_item *free; int error; free = container_of(item, struct xfs_extent_free_item, xefi_list); error = xfs_free_extent(tp, free->xefi_startblock, free->xefi_blockcount, &free->xefi_oinfo, XFS_AG_RESV_NONE); kmem_free(free); return error; } /* Abort all pending EFIs. */ STATIC void xfs_extent_free_abort_intent( void *intent) { } /* Cancel a free extent. */ STATIC void xfs_extent_free_cancel_item( struct list_head *item) { struct xfs_extent_free_item *free; free = container_of(item, struct xfs_extent_free_item, xefi_list); kmem_free(free); } const struct xfs_defer_op_type xfs_extent_free_defer_type = { .diff_items = xfs_extent_free_diff_items, .create_intent = xfs_extent_free_create_intent, .abort_intent = xfs_extent_free_abort_intent, .log_item = xfs_extent_free_log_item, .create_done = xfs_extent_free_create_done, .finish_item = xfs_extent_free_finish_item, .cancel_item = xfs_extent_free_cancel_item, }; /* * AGFL blocks are accounted differently in the reserve pools and are not * inserted into the busy extent list. */ STATIC int xfs_agfl_free_finish_item( struct xfs_trans *tp, struct list_head *item, void *done_item, void **state) { struct xfs_mount *mp = tp->t_mountp; struct xfs_extent_free_item *free; struct xfs_buf *agbp; int error; xfs_agnumber_t agno; xfs_agblock_t agbno; free = container_of(item, struct xfs_extent_free_item, xefi_list); ASSERT(free->xefi_blockcount == 1); agno = XFS_FSB_TO_AGNO(mp, free->xefi_startblock); agbno = XFS_FSB_TO_AGBNO(mp, free->xefi_startblock); error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); if (!error) error = xfs_free_agfl_block(tp, agno, agbno, agbp, &free->xefi_oinfo); kmem_free(free); return error; } /* sub-type with special handling for AGFL deferred frees */ const struct xfs_defer_op_type xfs_agfl_free_defer_type = { .diff_items = xfs_extent_free_diff_items, .create_intent = xfs_extent_free_create_intent, .abort_intent = xfs_extent_free_abort_intent, .log_item = xfs_extent_free_log_item, .create_done = xfs_extent_free_create_done, .finish_item = xfs_agfl_free_finish_item, .cancel_item = xfs_extent_free_cancel_item, }; /* Reverse Mapping */ /* Sort rmap intents by AG. */ static int xfs_rmap_update_diff_items( void *priv, struct list_head *a, struct list_head *b) { struct xfs_mount *mp = priv; struct xfs_rmap_intent *ra; struct xfs_rmap_intent *rb; ra = container_of(a, struct xfs_rmap_intent, ri_list); rb = container_of(b, struct xfs_rmap_intent, ri_list); return XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) - XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock); } /* Get an RUI. */ STATIC void * xfs_rmap_update_create_intent( struct xfs_trans *tp, unsigned int count) { return NULL; } /* Log rmap updates in the intent item. */ STATIC void xfs_rmap_update_log_item( struct xfs_trans *tp, void *intent, struct list_head *item) { } /* Get an RUD so we can process all the deferred rmap updates. */ STATIC void * xfs_rmap_update_create_done( struct xfs_trans *tp, void *intent, unsigned int count) { return NULL; } /* Process a deferred rmap update. */ STATIC int xfs_rmap_update_finish_item( struct xfs_trans *tp, struct list_head *item, void *done_item, void **state) { struct xfs_rmap_intent *rmap; int error; rmap = container_of(item, struct xfs_rmap_intent, ri_list); error = xfs_rmap_finish_one(tp, rmap->ri_type, rmap->ri_owner, rmap->ri_whichfork, rmap->ri_bmap.br_startoff, rmap->ri_bmap.br_startblock, rmap->ri_bmap.br_blockcount, rmap->ri_bmap.br_state, (struct xfs_btree_cur **)state); kmem_free(rmap); return error; } /* Clean up after processing deferred rmaps. */ STATIC void xfs_rmap_update_finish_cleanup( struct xfs_trans *tp, void *state, int error) { struct xfs_btree_cur *rcur = state; xfs_rmap_finish_one_cleanup(tp, rcur, error); } /* Abort all pending RUIs. */ STATIC void xfs_rmap_update_abort_intent( void *intent) { } /* Cancel a deferred rmap update. */ STATIC void xfs_rmap_update_cancel_item( struct list_head *item) { struct xfs_rmap_intent *rmap; rmap = container_of(item, struct xfs_rmap_intent, ri_list); kmem_free(rmap); } const struct xfs_defer_op_type xfs_rmap_update_defer_type = { .diff_items = xfs_rmap_update_diff_items, .create_intent = xfs_rmap_update_create_intent, .abort_intent = xfs_rmap_update_abort_intent, .log_item = xfs_rmap_update_log_item, .create_done = xfs_rmap_update_create_done, .finish_item = xfs_rmap_update_finish_item, .finish_cleanup = xfs_rmap_update_finish_cleanup, .cancel_item = xfs_rmap_update_cancel_item, }; /* Reference Counting */ /* Sort refcount intents by AG. */ static int xfs_refcount_update_diff_items( void *priv, struct list_head *a, struct list_head *b) { struct xfs_mount *mp = priv; struct xfs_refcount_intent *ra; struct xfs_refcount_intent *rb; ra = container_of(a, struct xfs_refcount_intent, ri_list); rb = container_of(b, struct xfs_refcount_intent, ri_list); return XFS_FSB_TO_AGNO(mp, ra->ri_startblock) - XFS_FSB_TO_AGNO(mp, rb->ri_startblock); } /* Get an CUI. */ STATIC void * xfs_refcount_update_create_intent( struct xfs_trans *tp, unsigned int count) { return NULL; } /* Log refcount updates in the intent item. */ STATIC void xfs_refcount_update_log_item( struct xfs_trans *tp, void *intent, struct list_head *item) { } /* Get an CUD so we can process all the deferred refcount updates. */ STATIC void * xfs_refcount_update_create_done( struct xfs_trans *tp, void *intent, unsigned int count) { return NULL; } /* Process a deferred refcount update. */ STATIC int xfs_refcount_update_finish_item( struct xfs_trans *tp, struct list_head *item, void *done_item, void **state) { struct xfs_refcount_intent *refc; xfs_fsblock_t new_fsb; xfs_extlen_t new_aglen; int error; refc = container_of(item, struct xfs_refcount_intent, ri_list); error = xfs_refcount_finish_one(tp, refc->ri_type, refc->ri_startblock, refc->ri_blockcount, &new_fsb, &new_aglen, (struct xfs_btree_cur **)state); /* Did we run out of reservation? Requeue what we didn't finish. */ if (!error && new_aglen > 0) { ASSERT(refc->ri_type == XFS_REFCOUNT_INCREASE || refc->ri_type == XFS_REFCOUNT_DECREASE); refc->ri_startblock = new_fsb; refc->ri_blockcount = new_aglen; return -EAGAIN; } kmem_free(refc); return error; } /* Clean up after processing deferred refcounts. */ STATIC void xfs_refcount_update_finish_cleanup( struct xfs_trans *tp, void *state, int error) { struct xfs_btree_cur *rcur = state; xfs_refcount_finish_one_cleanup(tp, rcur, error); } /* Abort all pending CUIs. */ STATIC void xfs_refcount_update_abort_intent( void *intent) { } /* Cancel a deferred refcount update. */ STATIC void xfs_refcount_update_cancel_item( struct list_head *item) { struct xfs_refcount_intent *refc; refc = container_of(item, struct xfs_refcount_intent, ri_list); kmem_free(refc); } const struct xfs_defer_op_type xfs_refcount_update_defer_type = { .diff_items = xfs_refcount_update_diff_items, .create_intent = xfs_refcount_update_create_intent, .abort_intent = xfs_refcount_update_abort_intent, .log_item = xfs_refcount_update_log_item, .create_done = xfs_refcount_update_create_done, .finish_item = xfs_refcount_update_finish_item, .finish_cleanup = xfs_refcount_update_finish_cleanup, .cancel_item = xfs_refcount_update_cancel_item, }; /* Inode Block Mapping */ /* Sort bmap intents by inode. */ static int xfs_bmap_update_diff_items( void *priv, struct list_head *a, struct list_head *b) { struct xfs_bmap_intent *ba; struct xfs_bmap_intent *bb; ba = container_of(a, struct xfs_bmap_intent, bi_list); bb = container_of(b, struct xfs_bmap_intent, bi_list); return ba->bi_owner->i_ino - bb->bi_owner->i_ino; } /* Get an BUI. */ STATIC void * xfs_bmap_update_create_intent( struct xfs_trans *tp, unsigned int count) { return NULL; } /* Log bmap updates in the intent item. */ STATIC void xfs_bmap_update_log_item( struct xfs_trans *tp, void *intent, struct list_head *item) { } /* Get an BUD so we can process all the deferred rmap updates. */ STATIC void * xfs_bmap_update_create_done( struct xfs_trans *tp, void *intent, unsigned int count) { return NULL; } /* Process a deferred rmap update. */ STATIC int xfs_bmap_update_finish_item( struct xfs_trans *tp, struct list_head *item, void *done_item, void **state) { struct xfs_bmap_intent *bmap; xfs_filblks_t count; int error; bmap = container_of(item, struct xfs_bmap_intent, bi_list); count = bmap->bi_bmap.br_blockcount; error = xfs_bmap_finish_one(tp, bmap->bi_owner, bmap->bi_type, bmap->bi_whichfork, bmap->bi_bmap.br_startoff, bmap->bi_bmap.br_startblock, &count, bmap->bi_bmap.br_state); if (!error && count > 0) { ASSERT(bmap->bi_type == XFS_BMAP_UNMAP); bmap->bi_bmap.br_blockcount = count; return -EAGAIN; } kmem_free(bmap); return error; } /* Abort all pending BUIs. */ STATIC void xfs_bmap_update_abort_intent( void *intent) { } /* Cancel a deferred rmap update. */ STATIC void xfs_bmap_update_cancel_item( struct list_head *item) { struct xfs_bmap_intent *bmap; bmap = container_of(item, struct xfs_bmap_intent, bi_list); kmem_free(bmap); } const struct xfs_defer_op_type xfs_bmap_update_defer_type = { .diff_items = xfs_bmap_update_diff_items, .create_intent = xfs_bmap_update_create_intent, .abort_intent = xfs_bmap_update_abort_intent, .log_item = xfs_bmap_update_log_item, .create_done = xfs_bmap_update_create_done, .finish_item = xfs_bmap_update_finish_item, .cancel_item = xfs_bmap_update_cancel_item, }; xfsprogs-5.3.0/libxfs/init.c0000644000175000017500000005065013570057155015660 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "init.h" #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_rmap_btree.h" #include "xfs_refcount_btree.h" #include "libfrog/platform.h" #include "libxfs.h" /* for now */ char *progname = "libxfs"; /* default, changed by each tool */ struct cache *libxfs_bcache; /* global buffer cache */ int libxfs_bhash_size; /* #buckets in bcache */ int use_xfs_buf_lock; /* global flag: use xfs_buf_t locks for MT */ /* * dev_map - map open devices to fd. */ #define MAX_DEVS 10 /* arbitary maximum */ static int nextfakedev = -1; /* device number to give to next fake device */ static struct dev_to_fd { dev_t dev; int fd; } dev_map[MAX_DEVS]={{0}}; /* * Checks whether a given device has a mounted, writable * filesystem, returns 1 if it does & fatal (just warns * if not fatal, but allows us to proceed). * * Useful to tools which will produce uncertain results * if the filesystem is active - repair, check, logprint. */ static int check_isactive(char *name, char *block, int fatal) { struct stat st; if (stat(block, &st) < 0) return 0; if ((st.st_mode & S_IFMT) != S_IFBLK) return 0; if (platform_check_ismounted(name, block, &st, 0) == 0) return 0; if (platform_check_iswritable(name, block, &st)) return fatal ? 1 : 0; return 0; } /* libxfs_device_to_fd: * lookup a device number in the device map * return the associated fd */ int libxfs_device_to_fd(dev_t device) { int d; for (d = 0; d < MAX_DEVS; d++) if (dev_map[d].dev == device) return dev_map[d].fd; fprintf(stderr, _("%s: %s: device %lld is not open\n"), progname, __FUNCTION__, (long long)device); exit(1); /* NOTREACHED */ } /* libxfs_device_open: * open a device and return its device number */ dev_t libxfs_device_open(char *path, int creat, int xflags, int setblksize) { dev_t dev; int fd, d, flags; int readonly, dio, excl; struct stat statb; readonly = (xflags & LIBXFS_ISREADONLY); excl = (xflags & LIBXFS_EXCLUSIVELY) && !creat; dio = (xflags & LIBXFS_DIRECT) && !creat && platform_direct_blockdev(); retry: flags = (readonly ? O_RDONLY : O_RDWR) | \ (creat ? (O_CREAT|O_TRUNC) : 0) | \ (dio ? O_DIRECT : 0) | \ (excl ? O_EXCL : 0); if ((fd = open(path, flags, 0666)) < 0) { if (errno == EINVAL && --dio == 0) goto retry; fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); exit(1); } if (fstat(fd, &statb) < 0) { fprintf(stderr, _("%s: cannot stat %s: %s\n"), progname, path, strerror(errno)); exit(1); } if (!readonly && setblksize && (statb.st_mode & S_IFMT) == S_IFBLK) { if (setblksize == 1) /* use the default blocksize */ (void)platform_set_blocksize(fd, path, statb.st_rdev, XFS_MIN_SECTORSIZE, 0); else { /* given an explicit blocksize to use */ if (platform_set_blocksize(fd, path, statb.st_rdev, setblksize, 1)) exit(1); } } /* * Get the device number from the stat buf - unless * we're not opening a real device, in which case * choose a new fake device number. */ dev = (statb.st_rdev) ? (statb.st_rdev) : (nextfakedev--); for (d = 0; d < MAX_DEVS; d++) if (dev_map[d].dev == dev) { fprintf(stderr, _("%s: device %lld is already open\n"), progname, (long long)dev); exit(1); } for (d = 0; d < MAX_DEVS; d++) if (!dev_map[d].dev) { dev_map[d].dev = dev; dev_map[d].fd = fd; return dev; } fprintf(stderr, _("%s: %s: too many open devices\n"), progname, __FUNCTION__); exit(1); /* NOTREACHED */ } void libxfs_device_close(dev_t dev) { int d; for (d = 0; d < MAX_DEVS; d++) if (dev_map[d].dev == dev) { int fd; fd = dev_map[d].fd; dev_map[d].dev = dev_map[d].fd = 0; fsync(fd); platform_flush_device(fd, dev); close(fd); return; } fprintf(stderr, _("%s: %s: device %lld is not open\n"), progname, __FUNCTION__, (long long)dev); exit(1); } static int check_open(char *path, int flags, char **rawfile, char **blockfile) { int readonly = (flags & LIBXFS_ISREADONLY); int inactive = (flags & LIBXFS_ISINACTIVE); int dangerously = (flags & LIBXFS_DANGEROUSLY); struct stat stbuf; if (stat(path, &stbuf) < 0) { perror(path); return 0; } if (!(*rawfile = platform_findrawpath(path))) { fprintf(stderr, _("%s: " "can't find a character device matching %s\n"), progname, path); return 0; } if (!(*blockfile = platform_findblockpath(path))) { fprintf(stderr, _("%s: " "can't find a block device matching %s\n"), progname, path); return 0; } if (!readonly && !inactive && platform_check_ismounted(path, *blockfile, NULL, 1)) return 0; if (inactive && check_isactive(path, *blockfile, ((readonly|dangerously)?1:0))) return 0; return 1; } /* * Initialize/destroy all of the zone allocators we use. */ static void init_zones(void) { /* initialise zone allocation */ xfs_buf_zone = kmem_zone_init(sizeof(struct xfs_buf), "xfs_buffer"); xfs_inode_zone = kmem_zone_init(sizeof(struct xfs_inode), "xfs_inode"); xfs_ifork_zone = kmem_zone_init(sizeof(struct xfs_ifork), "xfs_ifork"); xfs_ili_zone = kmem_zone_init( sizeof(struct xfs_inode_log_item),"xfs_inode_log_item"); xfs_buf_item_zone = kmem_zone_init( sizeof(struct xfs_buf_log_item), "xfs_buf_log_item"); xfs_da_state_zone = kmem_zone_init( sizeof(struct xfs_da_state), "xfs_da_state"); xfs_btree_cur_zone = kmem_zone_init( sizeof(struct xfs_btree_cur), "xfs_btree_cur"); xfs_bmap_free_item_zone = kmem_zone_init( sizeof(struct xfs_extent_free_item), "xfs_bmap_free_item"); xfs_trans_zone = kmem_zone_init( sizeof(struct xfs_trans), "xfs_trans"); } static int destroy_zones(void) { int leaked = 0; leaked += kmem_zone_destroy(xfs_buf_zone); leaked += kmem_zone_destroy(xfs_ili_zone); leaked += kmem_zone_destroy(xfs_inode_zone); leaked += kmem_zone_destroy(xfs_ifork_zone); leaked += kmem_zone_destroy(xfs_buf_item_zone); leaked += kmem_zone_destroy(xfs_da_state_zone); leaked += kmem_zone_destroy(xfs_btree_cur_zone); leaked += kmem_zone_destroy(xfs_bmap_free_item_zone); leaked += kmem_zone_destroy(xfs_trans_zone); return leaked; } /* * libxfs initialization. * Caller gets a 0 on failure (and we print a message), 1 on success. */ int libxfs_init(libxfs_init_t *a) { char *blockfile; char *dname; char dpath[25]; int fd; char *logname; char logpath[25]; char *rawfile; char *rtname; char rtpath[25]; int rval = 0; int flags; dpath[0] = logpath[0] = rtpath[0] = '\0'; dname = a->dname; logname = a->logname; rtname = a->rtname; a->dfd = a->logfd = a->rtfd = -1; a->ddev = a->logdev = a->rtdev = 0; a->dsize = a->lbsize = a->rtbsize = 0; a->dbsize = a->logBBsize = a->logBBstart = a->rtsize = 0; fd = -1; flags = (a->isreadonly | a->isdirect); radix_tree_init(); if (a->volname) { if(!check_open(a->volname,flags,&rawfile,&blockfile)) goto done; fd = open(rawfile, O_RDONLY); dname = a->dname = a->volname; a->volname = NULL; } if (dname) { if (a->disfile) { a->ddev= libxfs_device_open(dname, a->dcreat, flags, a->setblksize); a->dfd = libxfs_device_to_fd(a->ddev); platform_findsizes(dname, a->dfd, &a->dsize, &a->dbsize); } else { if (!check_open(dname, flags, &rawfile, &blockfile)) goto done; a->ddev = libxfs_device_open(rawfile, a->dcreat, flags, a->setblksize); a->dfd = libxfs_device_to_fd(a->ddev); platform_findsizes(rawfile, a->dfd, &a->dsize, &a->dbsize); } } else a->dsize = 0; if (logname) { if (a->lisfile) { a->logdev = libxfs_device_open(logname, a->lcreat, flags, a->setblksize); a->logfd = libxfs_device_to_fd(a->logdev); platform_findsizes(dname, a->logfd, &a->logBBsize, &a->lbsize); } else { if (!check_open(logname, flags, &rawfile, &blockfile)) goto done; a->logdev = libxfs_device_open(rawfile, a->lcreat, flags, a->setblksize); a->logfd = libxfs_device_to_fd(a->logdev); platform_findsizes(rawfile, a->logfd, &a->logBBsize, &a->lbsize); } } else a->logBBsize = 0; if (rtname) { if (a->risfile) { a->rtdev = libxfs_device_open(rtname, a->rcreat, flags, a->setblksize); a->rtfd = libxfs_device_to_fd(a->rtdev); platform_findsizes(dname, a->rtfd, &a->rtsize, &a->rtbsize); } else { if (!check_open(rtname, flags, &rawfile, &blockfile)) goto done; a->rtdev = libxfs_device_open(rawfile, a->rcreat, flags, a->setblksize); a->rtfd = libxfs_device_to_fd(a->rtdev); platform_findsizes(rawfile, a->rtfd, &a->rtsize, &a->rtbsize); } } else a->rtsize = 0; if (a->dsize < 0) { fprintf(stderr, _("%s: can't get size for data subvolume\n"), progname); goto done; } if (a->logBBsize < 0) { fprintf(stderr, _("%s: can't get size for log subvolume\n"), progname); goto done; } if (a->rtsize < 0) { fprintf(stderr, _("%s: can't get size for realtime subvolume\n"), progname); goto done; } if (!libxfs_bhash_size) libxfs_bhash_size = LIBXFS_BHASHSIZE(sbp); libxfs_bcache = cache_init(a->bcache_flags, libxfs_bhash_size, &libxfs_bcache_operations); use_xfs_buf_lock = a->usebuflock; xfs_dir_startup(); init_zones(); rval = 1; done: if (dpath[0]) unlink(dpath); if (logpath[0]) unlink(logpath); if (rtpath[0]) unlink(rtpath); if (fd >= 0) close(fd); if (!rval && a->ddev) libxfs_device_close(a->ddev); if (!rval && a->logdev) libxfs_device_close(a->logdev); if (!rval && a->rtdev) libxfs_device_close(a->rtdev); return rval; } /* * Initialize realtime fields in the mount structure. */ static int rtmount_init( xfs_mount_t *mp, /* file system mount structure */ int flags) { xfs_buf_t *bp; /* buffer for last block of subvolume */ xfs_daddr_t d; /* address of last block of subvolume */ xfs_sb_t *sbp; /* filesystem superblock copy in mount */ sbp = &mp->m_sb; if (sbp->sb_rblocks == 0) return 0; if (mp->m_rtdev_targp->dev == 0 && !(flags & LIBXFS_MOUNT_DEBUGGER)) { fprintf(stderr, _("%s: filesystem has a realtime subvolume\n"), progname); return -1; } mp->m_rsumlevels = sbp->sb_rextslog + 1; mp->m_rsumsize = (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * sbp->sb_rbmblocks; mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize); mp->m_rbmip = mp->m_rsumip = NULL; /* * Allow debugger to be run without the realtime device present. */ if (flags & LIBXFS_MOUNT_DEBUGGER) return 0; /* * Check that the realtime section is an ok size. */ d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) { fprintf(stderr, _("%s: realtime init - %llu != %llu\n"), progname, (unsigned long long) XFS_BB_TO_FSB(mp, d), (unsigned long long) mp->m_sb.sb_rblocks); return -1; } bp = libxfs_readbuf(mp->m_rtdev, d - XFS_FSB_TO_BB(mp, 1), XFS_FSB_TO_BB(mp, 1), 0, NULL); if (bp == NULL) { fprintf(stderr, _("%s: realtime size check failed\n"), progname); return -1; } libxfs_putbuf(bp); return 0; } static int libxfs_initialize_perag( xfs_mount_t *mp, xfs_agnumber_t agcount, xfs_agnumber_t *maxagi) { xfs_agnumber_t index, max_metadata; xfs_agnumber_t first_initialised = 0; xfs_perag_t *pag; xfs_agino_t agino; xfs_ino_t ino; xfs_sb_t *sbp = &mp->m_sb; int error = -ENOMEM; /* * Walk the current per-ag tree so we don't try to initialise AGs * that already exist (growfs case). Allocate and insert all the * AGs we don't find ready for initialisation. */ for (index = 0; index < agcount; index++) { pag = xfs_perag_get(mp, index); if (pag) { xfs_perag_put(pag); continue; } if (!first_initialised) first_initialised = index; pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); if (!pag) goto out_unwind; pag->pag_agno = index; pag->pag_mount = mp; if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { error = -EEXIST; goto out_unwind; } } /* * If we mount with the inode64 option, or no inode overflows * the legacy 32-bit address space clear the inode32 option. */ agino = XFS_AGB_TO_AGINO(mp, sbp->sb_agblocks - 1); ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32) mp->m_flags |= XFS_MOUNT_32BITINODES; else mp->m_flags &= ~XFS_MOUNT_32BITINODES; if (mp->m_flags & XFS_MOUNT_32BITINODES) { /* * Calculate how much should be reserved for inodes to meet * the max inode percentage. */ if (M_IGEO(mp)->maxicount) { uint64_t icount; icount = sbp->sb_dblocks * sbp->sb_imax_pct; do_div(icount, 100); icount += sbp->sb_agblocks - 1; do_div(icount, sbp->sb_agblocks); max_metadata = icount; } else { max_metadata = agcount; } for (index = 0; index < agcount; index++) { ino = XFS_AGINO_TO_INO(mp, index, agino); if (ino > XFS_MAXINUMBER_32) { index++; break; } pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; xfs_perag_put(pag); } } else { for (index = 0; index < agcount; index++) { pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; xfs_perag_put(pag); } } if (maxagi) *maxagi = index; mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp); return 0; out_unwind: kmem_free(pag); for (; index > first_initialised; index--) { pag = radix_tree_delete(&mp->m_perag_tree, index); kmem_free(pag); } return error; } static struct xfs_buftarg * libxfs_buftarg_alloc( struct xfs_mount *mp, dev_t dev) { struct xfs_buftarg *btp; btp = malloc(sizeof(*btp)); if (!btp) { fprintf(stderr, _("%s: buftarg init failed\n"), progname); exit(1); } btp->bt_mount = mp; btp->dev = dev; return btp; } void libxfs_buftarg_init( struct xfs_mount *mp, dev_t dev, dev_t logdev, dev_t rtdev) { if (mp->m_ddev_targp) { /* should already have all buftargs initialised */ if (mp->m_ddev_targp->dev != dev || mp->m_ddev_targp->bt_mount != mp) { fprintf(stderr, _("%s: bad buftarg reinit, ddev\n"), progname); exit(1); } if (!logdev || logdev == dev) { if (mp->m_logdev_targp != mp->m_ddev_targp) { fprintf(stderr, _("%s: bad buftarg reinit, ldev mismatch\n"), progname); exit(1); } } else if (mp->m_logdev_targp->dev != logdev || mp->m_logdev_targp->bt_mount != mp) { fprintf(stderr, _("%s: bad buftarg reinit, logdev\n"), progname); exit(1); } if (rtdev && (mp->m_rtdev_targp->dev != rtdev || mp->m_rtdev_targp->bt_mount != mp)) { fprintf(stderr, _("%s: bad buftarg reinit, rtdev\n"), progname); exit(1); } return; } mp->m_ddev_targp = libxfs_buftarg_alloc(mp, dev); if (!logdev || logdev == dev) mp->m_logdev_targp = mp->m_ddev_targp; else mp->m_logdev_targp = libxfs_buftarg_alloc(mp, logdev); mp->m_rtdev_targp = libxfs_buftarg_alloc(mp, rtdev); } /* * Mount structure initialization, provides a filled-in xfs_mount_t * such that the numerous XFS_* macros can be used. If dev is zero, * no IO will be performed (no size checks, read root inodes). */ xfs_mount_t * libxfs_mount( xfs_mount_t *mp, xfs_sb_t *sb, dev_t dev, dev_t logdev, dev_t rtdev, int flags) { xfs_daddr_t d; xfs_buf_t *bp; xfs_sb_t *sbp; int error; libxfs_buftarg_init(mp, dev, logdev, rtdev); mp->m_finobt_nores = true; mp->m_flags = (LIBXFS_MOUNT_32BITINODES|LIBXFS_MOUNT_32BITINOOPT); mp->m_sb = *sb; INIT_RADIX_TREE(&mp->m_perag_tree, GFP_KERNEL); sbp = &(mp->m_sb); xfs_sb_mount_common(mp, sb); /* * Set whether we're using stripe alignment. */ if (xfs_sb_version_hasdalign(&mp->m_sb)) { mp->m_dalign = sbp->sb_unit; mp->m_swidth = sbp->sb_width; } xfs_alloc_compute_maxlevels(mp); xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); xfs_ialloc_setup_geometry(mp); xfs_rmapbt_compute_maxlevels(mp); xfs_refcountbt_compute_maxlevels(mp); /* * Check that the data (and log if separate) are an ok size. */ d = (xfs_daddr_t) XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { fprintf(stderr, _("%s: size check failed\n"), progname); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; } /* * We automatically convert v1 inodes to v2 inodes now, so if * the NLINK bit is not set we can't operate on the filesystem. */ if (!(sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT)) { fprintf(stderr, _( "%s: V1 inodes unsupported. Please try an older xfsprogs.\n"), progname); exit(1); } /* Check for supported directory formats */ if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) { fprintf(stderr, _( "%s: V1 directories unsupported. Please try an older xfsprogs.\n"), progname); exit(1); } /* check for unsupported other features */ if (!xfs_sb_good_version(sbp)) { fprintf(stderr, _( "%s: Unsupported features detected. Please try a newer xfsprogs.\n"), progname); exit(1); } xfs_da_mount(mp); if (xfs_sb_version_hasattr2(&mp->m_sb)) mp->m_flags |= LIBXFS_MOUNT_ATTR2; /* Initialize the precomputed transaction reservations values */ xfs_trans_init(mp); if (dev == 0) /* maxtrres, we have no device so leave now */ return mp; bp = libxfs_readbuf(mp->m_dev, d - XFS_FSS_TO_BB(mp, 1), XFS_FSS_TO_BB(mp, 1), !(flags & LIBXFS_MOUNT_DEBUGGER), NULL); if (!bp) { fprintf(stderr, _("%s: data size check failed\n"), progname); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; } else libxfs_putbuf(bp); if (mp->m_logdev_targp->dev && mp->m_logdev_targp->dev != mp->m_ddev_targp->dev) { d = (xfs_daddr_t) XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); if ( (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) || (!(bp = libxfs_readbuf(mp->m_logdev_targp, d - XFS_FSB_TO_BB(mp, 1), XFS_FSB_TO_BB(mp, 1), !(flags & LIBXFS_MOUNT_DEBUGGER), NULL))) ) { fprintf(stderr, _("%s: log size checks failed\n"), progname); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; } if (bp) libxfs_putbuf(bp); } /* Initialize realtime fields in the mount structure */ if (rtmount_init(mp, flags)) { fprintf(stderr, _("%s: realtime device init failed\n"), progname); return NULL; } /* * libxfs_initialize_perag will allocate a perag structure for each ag. * If agcount is corrupted and insanely high, this will OOM the box. * If the agount seems (arbitrarily) high, try to read what would be * the last AG, and if that fails for a relatively high agcount, just * read the first one and let the user know to check the geometry. */ if (sbp->sb_agcount > 1000000) { bp = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, sbp->sb_agcount - 1, 0), 1, !(flags & LIBXFS_MOUNT_DEBUGGER), NULL); if (bp->b_error) { fprintf(stderr, _("%s: read of AG %u failed\n"), progname, sbp->sb_agcount); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; fprintf(stderr, _("%s: limiting reads to AG 0\n"), progname); sbp->sb_agcount = 1; } libxfs_putbuf(bp); } error = libxfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); if (error) { fprintf(stderr, _("%s: perag init failed\n"), progname); exit(1); } return mp; } void libxfs_rtmount_destroy(xfs_mount_t *mp) { if (mp->m_rsumip) libxfs_irele(mp->m_rsumip); if (mp->m_rbmip) libxfs_irele(mp->m_rbmip); mp->m_rsumip = mp->m_rbmip = NULL; } /* * Release any resource obtained during a mount. */ void libxfs_umount(xfs_mount_t *mp) { struct xfs_perag *pag; int agno; libxfs_rtmount_destroy(mp); libxfs_bcache_purge(); for (agno = 0; agno < mp->m_maxagi; agno++) { pag = radix_tree_delete(&mp->m_perag_tree, agno); kmem_free(pag); } kmem_free(mp->m_attr_geo); kmem_free(mp->m_dir_geo); kmem_free(mp->m_rtdev_targp); if (mp->m_logdev_targp != mp->m_ddev_targp) kmem_free(mp->m_logdev_targp); kmem_free(mp->m_ddev_targp); } /* * Release any global resources used by libxfs. */ void libxfs_destroy(void) { int leaked; /* Free everything from the buffer cache before freeing buffer zone */ libxfs_bcache_purge(); libxfs_bcache_free(); cache_destroy(libxfs_bcache); leaked = destroy_zones(); if (getenv("LIBXFS_LEAK_CHECK") && leaked) exit(1); } int libxfs_device_alignment(void) { return platform_align_blockdev(); } void libxfs_report(FILE *fp) { time_t t; char *c; cache_report(fp, "libxfs_bcache", libxfs_bcache); t = time(NULL); c = asctime(localtime(&t)); fprintf(fp, "%s", c); } xfsprogs-5.3.0/libxfs/init.h0000644000175000017500000000035413570057155015661 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef LIBXFS_INIT_H #define LIBXFS_INIT_H struct stat; extern int use_xfs_buf_lock; #endif /* LIBXFS_INIT_H */ xfsprogs-5.3.0/libxfs/kmem.c0000644000175000017500000000336013435336036015640 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #include "libxfs_priv.h" /* * Simple memory interface */ kmem_zone_t * kmem_zone_init(int size, char *name) { kmem_zone_t *ptr = malloc(sizeof(kmem_zone_t)); if (ptr == NULL) { fprintf(stderr, _("%s: zone init failed (%s, %d bytes): %s\n"), progname, name, (int)sizeof(kmem_zone_t), strerror(errno)); exit(1); } ptr->zone_unitsize = size; ptr->zone_name = name; ptr->allocated = 0; return ptr; } int kmem_zone_destroy(kmem_zone_t *zone) { int leaked = 0; if (getenv("LIBXFS_LEAK_CHECK") && zone->allocated) { leaked = 1; fprintf(stderr, "zone %s freed with %d items allocated\n", zone->zone_name, zone->allocated); } free(zone); return leaked; } void * kmem_zone_alloc(kmem_zone_t *zone, int flags) { void *ptr = malloc(zone->zone_unitsize); if (ptr == NULL) { fprintf(stderr, _("%s: zone alloc failed (%s, %d bytes): %s\n"), progname, zone->zone_name, zone->zone_unitsize, strerror(errno)); exit(1); } zone->allocated++; return ptr; } void * kmem_zone_zalloc(kmem_zone_t *zone, int flags) { void *ptr = kmem_zone_alloc(zone, flags); memset(ptr, 0, zone->zone_unitsize); return ptr; } void * kmem_alloc(size_t size, int flags) { void *ptr = malloc(size); if (ptr == NULL) { fprintf(stderr, _("%s: malloc failed (%d bytes): %s\n"), progname, (int)size, strerror(errno)); exit(1); } return ptr; } void * kmem_zalloc(size_t size, int flags) { void *ptr = kmem_alloc(size, flags); memset(ptr, 0, size); return ptr; } void * kmem_realloc(void *ptr, size_t new_size, int flags) { ptr = realloc(ptr, new_size); if (ptr == NULL) { fprintf(stderr, _("%s: realloc failed (%d bytes): %s\n"), progname, (int)new_size, strerror(errno)); exit(1); } return ptr; } xfsprogs-5.3.0/libxfs/libxfs_api_defs.h0000644000175000017500000001550713570057155020045 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBXFS_API_DEFS_H__ #define __LIBXFS_API_DEFS_H__ /* * This file defines all the kernel based functions we expose to userspace * via the libxfs_* namespace. This is kept in a separate header file so * it can be included in both the internal and external libxfs header files * without introducing any depenencies between the two. */ #define xfs_highbit32 libxfs_highbit32 #define xfs_highbit64 libxfs_highbit64 #define xfs_trans_alloc libxfs_trans_alloc #define xfs_trans_alloc_empty libxfs_trans_alloc_empty #define xfs_trans_add_item libxfs_trans_add_item #define xfs_trans_bhold libxfs_trans_bhold #define xfs_trans_bhold_release libxfs_trans_bhold_release #define xfs_trans_binval libxfs_trans_binval #define xfs_trans_bjoin libxfs_trans_bjoin #define xfs_trans_brelse libxfs_trans_brelse #define xfs_trans_commit libxfs_trans_commit #define xfs_trans_cancel libxfs_trans_cancel #define xfs_trans_del_item libxfs_trans_del_item #define xfs_trans_get_buf libxfs_trans_get_buf #define xfs_trans_getsb libxfs_trans_getsb #define xfs_trans_ichgtime libxfs_trans_ichgtime #define xfs_trans_ijoin libxfs_trans_ijoin #define xfs_trans_init libxfs_trans_init #define xfs_trans_inode_alloc_buf libxfs_trans_inode_alloc_buf #define xfs_trans_dirty_buf libxfs_trans_dirty_buf #define xfs_trans_log_buf libxfs_trans_log_buf #define xfs_trans_ordered_buf libxfs_trans_ordered_buf #define xfs_trans_log_inode libxfs_trans_log_inode #define xfs_trans_roll_inode libxfs_trans_roll_inode #define xfs_trans_mod_sb libxfs_trans_mod_sb #define xfs_trans_read_buf libxfs_trans_read_buf #define xfs_trans_read_buf_map libxfs_trans_read_buf_map #define xfs_trans_roll libxfs_trans_roll #define xfs_trans_get_buf_map libxfs_trans_get_buf_map #define xfs_trans_resv_calc libxfs_trans_resv_calc #define xfs_log_get_max_trans_res libxfs_log_get_max_trans_res #define xfs_attr_get libxfs_attr_get #define xfs_attr_set libxfs_attr_set #define xfs_attr_remove libxfs_attr_remove #define xfs_attr_leaf_newentsize libxfs_attr_leaf_newentsize #define xfs_agfl_walk libxfs_agfl_walk #define xfs_alloc_fix_freelist libxfs_alloc_fix_freelist #define xfs_alloc_min_freelist libxfs_alloc_min_freelist #define xfs_alloc_read_agf libxfs_alloc_read_agf #define xfs_bmap_last_offset libxfs_bmap_last_offset #define xfs_iext_lookup_extent libxfs_iext_lookup_extent #define xfs_bmapi_write libxfs_bmapi_write #define xfs_bmapi_read libxfs_bmapi_read #define xfs_bunmapi libxfs_bunmapi #define xfs_rtfree_extent libxfs_rtfree_extent #define xfs_verify_rtbno libxfs_verify_rtbno #define xfs_verify_ino libxfs_verify_ino #define xfs_zero_extent libxfs_zero_extent #define xfs_defer_finish libxfs_defer_finish #define xfs_defer_cancel libxfs_defer_cancel #define xfs_da_hashname libxfs_da_hashname #define xfs_da_shrink_inode libxfs_da_shrink_inode #define xfs_da_read_buf libxfs_da_read_buf #define xfs_dir_createname libxfs_dir_createname #define xfs_dir_init libxfs_dir_init #define xfs_dir_lookup libxfs_dir_lookup #define xfs_dir_replace libxfs_dir_replace #define xfs_dir2_isblock libxfs_dir2_isblock #define xfs_dir2_isleaf libxfs_dir2_isleaf #define xfs_dir2_data_freescan_int libxfs_dir2_data_freescan_int #define xfs_dir2_data_log_entry libxfs_dir2_data_log_entry #define xfs_dir2_data_log_header libxfs_dir2_data_log_header #define xfs_dir2_data_make_free libxfs_dir2_data_make_free #define xfs_dir2_data_use_free libxfs_dir2_data_use_free #define xfs_dir2_shrink_inode libxfs_dir2_shrink_inode #define xfs_da_get_buf libxfs_da_get_buf #define xfs_inode_from_disk libxfs_inode_from_disk #define xfs_inode_to_disk libxfs_inode_to_disk #define xfs_dinode_calc_crc libxfs_dinode_calc_crc #define xfs_idata_realloc libxfs_idata_realloc #define xfs_idestroy_fork libxfs_idestroy_fork #define xfs_inode_validate_extsize libxfs_inode_validate_extsize #define xfs_inode_validate_cowextsize libxfs_inode_validate_cowextsize #define xfs_rmap_alloc libxfs_rmap_alloc #define xfs_rmap_query_range libxfs_rmap_query_range #define xfs_rmap_lookup_le libxfs_rmap_lookup_le #define xfs_rmap_get_rec libxfs_rmap_get_rec #define xfs_rmap_irec_offset_pack libxfs_rmap_irec_offset_pack #define xfs_rmap_irec_offset_unpack libxfs_rmap_irec_offset_unpack #define xfs_rmapbt_init_cursor libxfs_rmapbt_init_cursor #define xfs_btree_del_cursor libxfs_btree_del_cursor #define xfs_mode_to_ftype libxfs_mode_to_ftype #define xfs_log_sb libxfs_log_sb #define xfs_sb_from_disk libxfs_sb_from_disk #define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk #define xfs_sb_to_disk libxfs_sb_to_disk #define xfs_calc_dquots_per_chunk libxfs_calc_dquots_per_chunk #define xfs_dquot_verify libxfs_dquot_verify #define xfs_dqblk_repair libxfs_dqblk_repair #define xfs_symlink_blocks libxfs_symlink_blocks #define xfs_symlink_hdr_ok libxfs_symlink_hdr_ok #define xfs_verify_cksum libxfs_verify_cksum #define xfs_dinode_verify libxfs_dinode_verify #define xfs_alloc_ag_max_usable libxfs_alloc_ag_max_usable #define xfs_allocbt_maxrecs libxfs_allocbt_maxrecs #define xfs_bmbt_maxrecs libxfs_bmbt_maxrecs #define xfs_bmdr_maxrecs libxfs_bmdr_maxrecs #define xfs_btree_init_block libxfs_btree_init_block #define xfs_dir_ino_validate libxfs_dir_ino_validate #define xfs_initialize_perag_data libxfs_initialize_perag_data #define xfs_inobt_maxrecs libxfs_inobt_maxrecs #define xfs_rmapbt_maxrecs libxfs_rmapbt_maxrecs #define xfs_refcountbt_maxrecs libxfs_refcountbt_maxrecs #define xfs_iread_extents libxfs_iread_extents #define xfs_log_calc_minimum_size libxfs_log_calc_minimum_size #define xfs_perag_get libxfs_perag_get #define xfs_perag_put libxfs_perag_put #define xfs_prealloc_blocks libxfs_prealloc_blocks #define xfs_dinode_good_version libxfs_dinode_good_version #define xfs_free_extent libxfs_free_extent #define xfs_refcountbt_init_cursor libxfs_refcountbt_init_cursor #define xfs_refcount_lookup_le libxfs_refcount_lookup_le #define xfs_refcount_get_rec libxfs_refcount_get_rec #define xfs_rmap_lookup_le_range libxfs_rmap_lookup_le_range #define xfs_agfl_size libxfs_agfl_size #define xfs_refc_block libxfs_refc_block #define xfs_rmap_compare libxfs_rmap_compare #define xfs_dir_get_ops libxfs_dir_get_ops #define xfs_default_ifork_ops libxfs_default_ifork_ops #define xfs_fs_geometry libxfs_fs_geometry #define xfs_init_local_fork libxfs_init_local_fork #define xfs_dir2_namecheck libxfs_dir2_namecheck #define xfs_attr_namecheck libxfs_attr_namecheck #define LIBXFS_ATTR_ROOT ATTR_ROOT #define LIBXFS_ATTR_SECURE ATTR_SECURE #define LIBXFS_ATTR_CREATE ATTR_CREATE #define LIBXFS_ATTR_REPLACE ATTR_REPLACE #define xfs_ag_init_headers libxfs_ag_init_headers #define xfs_buf_delwri_submit libxfs_buf_delwri_submit #endif /* __LIBXFS_API_DEFS_H__ */ xfsprogs-5.3.0/libxfs/libxfs_io.h0000644000175000017500000001763213570057155016703 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __LIBXFS_IO_H_ #define __LIBXFS_IO_H_ /* * Kernel equivalent buffer based I/O interface */ struct xfs_buf; struct xfs_mount; struct xfs_perag; /* * IO verifier callbacks need the xfs_mount pointer, so we have to behave * somewhat like the kernel now for userspace IO in terms of having buftarg * based devices... */ struct xfs_buftarg { struct xfs_mount *bt_mount; dev_t dev; }; extern void libxfs_buftarg_init(struct xfs_mount *mp, dev_t ddev, dev_t logdev, dev_t rtdev); #define LIBXFS_BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) #define XB_PAGES 2 struct xfs_buf_map { xfs_daddr_t bm_bn; /* block number for I/O */ int bm_len; /* size of I/O */ }; #define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \ struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) }; struct xfs_buf_ops { char *name; union { __be32 magic[2]; /* v4 and v5 on disk magic values */ __be16 magic16[2]; /* v4 and v5 on disk magic values */ }; void (*verify_read)(struct xfs_buf *); void (*verify_write)(struct xfs_buf *); xfs_failaddr_t (*verify_struct)(struct xfs_buf *); }; typedef struct xfs_buf { struct cache_node b_node; unsigned int b_flags; xfs_daddr_t b_bn; unsigned b_bcount; unsigned int b_length; struct xfs_buftarg *b_target; #define b_dev b_target->dev pthread_mutex_t b_lock; pthread_t b_holder; unsigned int b_recur; void *b_log_item; void *b_transp; void *b_addr; int b_error; const struct xfs_buf_ops *b_ops; struct xfs_perag *b_pag; struct xfs_mount *b_mount; struct xfs_buf_map *b_maps; struct xfs_buf_map __b_map; int b_nmaps; struct list_head b_list; #ifdef XFS_BUF_TRACING struct list_head b_lock_list; const char *b_func; const char *b_file; int b_line; #endif } xfs_buf_t; bool xfs_verify_magic(struct xfs_buf *bp, __be32 dmagic); bool xfs_verify_magic16(struct xfs_buf *bp, __be16 dmagic); /* b_flags bits */ #define LIBXFS_B_EXIT 0x0001 /* ==LIBXFS_EXIT_ON_FAILURE */ #define LIBXFS_B_DIRTY 0x0002 /* buffer has been modified */ #define LIBXFS_B_STALE 0x0004 /* buffer marked as invalid */ #define LIBXFS_B_UPTODATE 0x0008 /* buffer is sync'd to disk */ #define LIBXFS_B_DISCONTIG 0x0010 /* discontiguous buffer */ #define LIBXFS_B_UNCHECKED 0x0020 /* needs verification */ typedef unsigned int xfs_buf_flags_t; #define XFS_BUF_DADDR_NULL ((xfs_daddr_t) (-1LL)) #define xfs_buf_offset(bp, offset) ((bp)->b_addr + (offset)) #define XFS_BUF_ADDR(bp) ((bp)->b_bn) #define XFS_BUF_SIZE(bp) ((bp)->b_bcount) #define XFS_BUF_SET_ADDR(bp,blk) ((bp)->b_bn = (blk)) #define XFS_BUF_SET_PRIORITY(bp,pri) cache_node_set_priority( \ libxfs_bcache, \ (struct cache_node *)(bp), \ (pri)) #define XFS_BUF_PRIORITY(bp) (cache_node_get_priority( \ (struct cache_node *)(bp))) #define xfs_buf_set_ref(bp,ref) ((void) 0) #define xfs_buf_ioerror(bp,err) ((bp)->b_error = (err)) #define xfs_daddr_to_agno(mp,d) \ ((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks)) #define xfs_daddr_to_agbno(mp,d) \ ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks)) /* Buffer Cache Interfaces */ extern struct cache *libxfs_bcache; extern struct cache_operations libxfs_bcache_operations; #define LIBXFS_GETBUF_TRYLOCK (1 << 0) #ifdef XFS_BUF_TRACING #define libxfs_readbuf(dev, daddr, len, flags, ops) \ libxfs_trace_readbuf(__FUNCTION__, __FILE__, __LINE__, \ (dev), (daddr), (len), (flags), (ops)) #define libxfs_readbuf_map(dev, map, nmaps, flags, ops) \ libxfs_trace_readbuf_map(__FUNCTION__, __FILE__, __LINE__, \ (dev), (map), (nmaps), (flags), (ops)) #define libxfs_writebuf(buf, flags) \ libxfs_trace_writebuf(__FUNCTION__, __FILE__, __LINE__, \ (buf), (flags)) #define libxfs_getbuf(dev, daddr, len) \ libxfs_trace_getbuf(__FUNCTION__, __FILE__, __LINE__, \ (dev), (daddr), (len)) #define libxfs_getbuf_map(dev, map, nmaps, flags) \ libxfs_trace_getbuf_map(__FUNCTION__, __FILE__, __LINE__, \ (dev), (map), (nmaps), (flags)) #define libxfs_getbuf_flags(dev, daddr, len, flags) \ libxfs_trace_getbuf_flags(__FUNCTION__, __FILE__, __LINE__, \ (dev), (daddr), (len), (flags)) #define libxfs_putbuf(buf) \ libxfs_trace_putbuf(__FUNCTION__, __FILE__, __LINE__, (buf)) extern xfs_buf_t *libxfs_trace_readbuf(const char *, const char *, int, struct xfs_buftarg *, xfs_daddr_t, int, int, const struct xfs_buf_ops *); extern xfs_buf_t *libxfs_trace_readbuf_map(const char *, const char *, int, struct xfs_buftarg *, struct xfs_buf_map *, int, int, const struct xfs_buf_ops *); extern int libxfs_trace_writebuf(const char *, const char *, int, xfs_buf_t *, int); extern xfs_buf_t *libxfs_trace_getbuf(const char *, const char *, int, struct xfs_buftarg *, xfs_daddr_t, int); extern xfs_buf_t *libxfs_trace_getbuf_map(const char *, const char *, int, struct xfs_buftarg *, struct xfs_buf_map *, int, int); extern xfs_buf_t *libxfs_trace_getbuf_flags(const char *, const char *, int, struct xfs_buftarg *, xfs_daddr_t, int, unsigned int); extern void libxfs_trace_putbuf (const char *, const char *, int, xfs_buf_t *); #else extern xfs_buf_t *libxfs_readbuf(struct xfs_buftarg *, xfs_daddr_t, int, int, const struct xfs_buf_ops *); extern xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int, const struct xfs_buf_ops *); extern int libxfs_writebuf(xfs_buf_t *, int); extern xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int); extern xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int); extern xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int, unsigned int); extern void libxfs_putbuf (xfs_buf_t *); #endif extern void libxfs_readbuf_verify(struct xfs_buf *bp, const struct xfs_buf_ops *ops); extern xfs_buf_t *libxfs_getsb(struct xfs_mount *); extern void libxfs_bcache_purge(void); extern void libxfs_bcache_free(void); extern void libxfs_bcache_flush(void); extern void libxfs_purgebuf(xfs_buf_t *); extern int libxfs_bcache_overflowed(void); /* Buffer (Raw) Interfaces */ extern xfs_buf_t *libxfs_getbufr(struct xfs_buftarg *, xfs_daddr_t, int); extern void libxfs_putbufr(xfs_buf_t *); extern int libxfs_writebuf_int(xfs_buf_t *, int); extern int libxfs_writebufr(struct xfs_buf *); extern int libxfs_readbufr(struct xfs_buftarg *, xfs_daddr_t, xfs_buf_t *, int, int); extern int libxfs_readbufr_map(struct xfs_buftarg *, struct xfs_buf *, int); extern int libxfs_device_zero(struct xfs_buftarg *, xfs_daddr_t, uint); extern int libxfs_bhash_size; #define LIBXFS_BREAD 0x1 #define LIBXFS_BWRITE 0x2 #define LIBXFS_BZERO 0x4 extern void libxfs_iomove (xfs_buf_t *, uint, int, void *, int); static inline int xfs_buf_verify_cksum(struct xfs_buf *bp, unsigned long cksum_offset) { return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), cksum_offset); } static inline void xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset) { xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), cksum_offset); } static inline int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t len) { bp->b_addr = mem; bp->b_bcount = len; return 0; } /* * Allocate an uncached buffer that points nowhere. The refcount will be 1, * and the cache node hash list will be empty to indicate that it's uncached. */ static inline struct xfs_buf * xfs_buf_get_uncached(struct xfs_buftarg *targ, size_t bblen, int flags) { struct xfs_buf *bp; bp = libxfs_getbufr(targ, XFS_BUF_DADDR_NULL, bblen); if (!bp) return NULL; INIT_LIST_HEAD(&bp->b_node.cn_hash); bp->b_node.cn_count = 1; return bp; } /* Push a single buffer on a delwri queue. */ static inline void xfs_buf_delwri_queue(struct xfs_buf *bp, struct list_head *buffer_list) { bp->b_node.cn_count++; list_add_tail(&bp->b_list, buffer_list); } int xfs_buf_delwri_submit(struct list_head *buffer_list); #endif /* __LIBXFS_IO_H__ */ xfsprogs-5.3.0/libxfs/libxfs_priv.h0000644000175000017500000005015013570057155017244 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ /* * This header is effectively a "namespace multiplexor" for the * user level XFS code. It provides all of the necessary stuff * such that we can build some parts of the XFS kernel code in * user space in a controlled fashion, and translates the names * used in the kernel into the names which libxfs is going to * make available to user tools. * * It should only ever be #include'd by XFS "kernel" code being * compiled in user space. * * Our goals here are to... * o "share" large amounts of complex code between user and * kernel space; * o shield the user tools from changes in the bleeding * edge kernel code, merging source changes when * convenient and not immediately (no symlinks); * o i.e. be able to merge changes to the kernel source back * into the affected user tools in a controlled fashion; * o provide a _minimalist_ life-support system for kernel * code in user land, not the "everything + the kitchen * sink" model which libsim had mutated into; * o allow the kernel code to be completely free of code * specifically there to support the user level build. */ /* * define a guard and something we can check to determine what include context * we are running from. */ #ifndef __LIBXFS_INTERNAL_XFS_H__ #define __LIBXFS_INTERNAL_XFS_H__ #include "libxfs_api_defs.h" #include "platform_defs.h" #include "xfs.h" #include "list.h" #include "hlist.h" #include "cache.h" #include "bitops.h" #include "kmem.h" #include "libfrog/radix-tree.h" #include "atomic.h" #include "xfs_types.h" #include "xfs_arch.h" #include "xfs_fs.h" #include "libfrog/crc32c.h" /* Zones used in libxfs allocations that aren't in shared header files */ extern kmem_zone_t *xfs_buf_item_zone; extern kmem_zone_t *xfs_ili_zone; extern kmem_zone_t *xfs_buf_zone; extern kmem_zone_t *xfs_inode_zone; extern kmem_zone_t *xfs_trans_zone; /* CRC stuff, buffer API dependent on it */ #define crc32c(c,p,l) crc32c_le((c),(unsigned char const *)(p),(l)) #include "xfs_cksum.h" /* * This mirrors the kernel include for xfs_buf.h - it's implicitly included in * every files via a similar include in the kernel xfs_linux.h. */ #include "libxfs_io.h" /* for all the support code that uses progname in error messages */ extern char *progname; #undef ASSERT #define ASSERT(ex) assert(ex) /* * We have no need for the "linux" dev_t in userspace, so these * are no-ops, and an xfs_dev_t is stored in VFS_I(ip)->i_rdev */ #define xfs_to_linux_dev_t(dev) dev #define linux_to_xfs_dev_t(dev) dev #ifndef EWRONGFS #define EWRONGFS EINVAL #endif #define xfs_error_level 0 #define STATIC static /* * Starting in Linux 4.15, the %p (raw pointer value) printk modifier * prints a hashed version of the pointer to avoid leaking kernel * pointers into dmesg. If we're trying to debug the kernel we want the * raw values, so override this behavior as best we can. * * In userspace we don't have this problem. */ #define PTR_FMT "%p" #define XFS_IGET_CREATE 0x1 #define XFS_IGET_UNTRUSTED 0x2 extern void cmn_err(int, char *, ...); enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; #define xfs_notice(mp,fmt,args...) cmn_err(CE_NOTE,fmt, ## args) #define xfs_warn(mp,fmt,args...) cmn_err(CE_WARN,fmt, ## args) #define xfs_err(mp,fmt,args...) cmn_err(CE_ALERT,fmt, ## args) #define xfs_alert(mp,fmt,args...) cmn_err(CE_ALERT,fmt, ## args) #define xfs_hex_dump(d,n) ((void) 0) #define xfs_stack_trace() ((void) 0) #define xfs_force_shutdown(d,n) ((void) 0) #define xfs_mod_delalloc(a,b) ((void) 0) /* stop unused var warnings by assigning mp to itself */ #define xfs_corruption_error(e,l,mp,b,sz,fi,ln,fa) do { \ (mp) = (mp); \ cmn_err(CE_ALERT, "%s: XFS_CORRUPTION_ERROR", (e)); \ } while (0) #define XFS_CORRUPTION_ERROR(e, lvl, mp, buf, bufsize) do { \ (mp) = (mp); \ cmn_err(CE_ALERT, "%s: XFS_CORRUPTION_ERROR", (e)); \ } while (0) #define XFS_ERROR_REPORT(e,l,mp) do { \ (mp) = (mp); \ cmn_err(CE_ALERT, "%s: XFS_ERROR_REPORT", (e)); \ } while (0) #define XFS_ERRLEVEL_LOW 1 #define XFS_FORCED_SHUTDOWN(mp) 0 #define XFS_ILOCK_EXCL 0 #define XFS_STATS_INC(mp, count) do { (mp) = (mp); } while (0) #define XFS_STATS_DEC(mp, count, x) do { (mp) = (mp); } while (0) #define XFS_STATS_ADD(mp, count, x) do { (mp) = (mp); } while (0) #define XFS_TEST_ERROR(expr,a,b) ( expr ) #define XFS_WANT_CORRUPTED_GOTO(mp, expr, l) \ { \ if (!(expr)) { \ if ((mp)->m_flags & LIBXFS_MOUNT_WANT_CORRUPTED) \ printf("WANT_CORRUPTED_GOTO at %s:%d\n", \ __func__, __LINE__); \ error = -EFSCORRUPTED; \ goto l; \ } \ } #define XFS_WANT_CORRUPTED_RETURN(mp, expr) \ { \ if (!(expr)) { \ if ((mp)->m_flags & LIBXFS_MOUNT_WANT_CORRUPTED) \ printf("WANT_CORRUPTED_RETURN at %s:%d\n", \ __func__, __LINE__); \ return -EFSCORRUPTED; \ } \ } #ifdef __GNUC__ #define __return_address __builtin_return_address(0) /* * Return the address of a label. Use barrier() so that the optimizer * won't reorder code to refactor the error jumpouts into a single * return, which throws off the reported address. */ #define __this_address ({ __label__ __here; __here: barrier(); &&__here; }) /* Optimization barrier */ /* The "volatile" is due to gcc bugs */ #define barrier() __asm__ __volatile__("": : :"memory") #endif /* Optimization barrier */ #ifndef barrier # define barrier() __memory_barrier() #endif /* miscellaneous kernel routines not in user space */ #define spin_lock_init(a) ((void) 0) #define spin_lock(a) ((void) 0) #define spin_unlock(a) ((void) 0) #define likely(x) (x) #define unlikely(x) (x) #define rcu_read_lock() ((void) 0) #define rcu_read_unlock() ((void) 0) /* Need to be able to handle this bare or in control flow */ static inline bool WARN_ON(bool expr) { return (expr); } #define WARN_ON_ONCE(e) WARN_ON(e) #define percpu_counter_read(x) (*x) #define percpu_counter_read_positive(x) ((*x) > 0 ? (*x) : 0) #define percpu_counter_sum(x) (*x) #define READ_ONCE(x) (x) #define WRITE_ONCE(x, val) ((x) = (val)) /* * prandom_u32 is used for di_gen inode allocation, it must be zero for libxfs * or all sorts of badness can occur! */ #define prandom_u32() 0 #define PAGE_SIZE getpagesize() #define inode_peek_iversion(inode) (inode)->i_version #define inode_set_iversion_queried(inode, version) do { \ (inode)->i_version = (version); \ } while (0) static inline int __do_div(unsigned long long *n, unsigned base) { int __res; __res = (int)(((unsigned long) *n) % (unsigned) base); *n = ((unsigned long) *n) / (unsigned) base; return __res; } #define do_div(n,base) (__do_div((unsigned long long *)&(n), (base))) #define do_mod(a, b) ((a) % (b)) #define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) /** * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder * @dividend: unsigned 64bit dividend * @divisor: unsigned 32bit divisor * @remainder: pointer to unsigned 32bit remainder * * Return: sets ``*remainder``, then returns dividend / divisor * * This is commonly provided by 32bit archs to provide an optimized 64bit * divide. */ static inline uint64_t div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder) { *remainder = dividend % divisor; return dividend / divisor; } #define min_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) /** * swap - swap values of @a and @b * @a: first value * @b: second value */ #define swap(a, b) \ do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) /* * Handling for kernel bitmap types. */ #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, NBBY * sizeof(long)) #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) /* * This is a common helper function for find_next_bit and * find_next_zero_bit. The difference is the "invert" argument, which * is XORed with each fetched word before searching it for one bits. */ static inline unsigned long _find_next_bit(const unsigned long *addr, unsigned long nbits, unsigned long start, unsigned long invert) { unsigned long tmp; if (!nbits || start >= nbits) return nbits; tmp = addr[start / BITS_PER_LONG] ^ invert; /* Handle 1st word. */ tmp &= BITMAP_FIRST_WORD_MASK(start); start = round_down(start, BITS_PER_LONG); while (!tmp) { start += BITS_PER_LONG; if (start >= nbits) return nbits; tmp = addr[start / BITS_PER_LONG] ^ invert; } return min(start + ffs(tmp), nbits); } /* * Find the next set bit in a memory region. */ static inline unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { return _find_next_bit(addr, size, offset, 0UL); } static inline unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { return _find_next_bit(addr, size, offset, ~0UL); } #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) static inline __attribute__((const)) int is_power_of_2(unsigned long n) { return (n != 0 && ((n & (n - 1)) == 0)); } /* * xfs_iroundup: round up argument to next power of two */ static inline uint roundup_pow_of_two(uint v) { int i; uint m; if ((v & (v - 1)) == 0) return v; ASSERT((v & 0x80000000) == 0); if ((v & (v + 1)) == 0) return v + 1; for (i = 0, m = 1; i < 31; i++, m <<= 1) { if (v & m) continue; v |= m; if ((v & (v + 1)) == 0) return v + 1; } ASSERT(0); return 0; } static inline uint64_t roundup_64(uint64_t x, uint32_t y) { x += y - 1; do_div(x, y); return x * y; } /* buffer management */ #define XBF_TRYLOCK 0 #define XBF_UNMAPPED 0 #define XBF_DONE 0 #define xfs_buf_stale(bp) ((bp)->b_flags |= LIBXFS_B_STALE) #define XFS_BUF_UNDELAYWRITE(bp) ((bp)->b_flags &= ~LIBXFS_B_DIRTY) #define XFS_BUF_SET_BDSTRAT_FUNC(a,b) ((void) 0) /* avoid gcc warning */ #define xfs_buf_incore(bt,blkno,len,lockit) ({ \ typeof(blkno) __foo = (blkno); \ typeof(len) __bar = (len); \ (blkno) = __foo; \ (len) = __bar; /* no set-but-unused warning */ \ NULL; \ }) #define xfs_buf_relse(bp) libxfs_putbuf(bp) #define xfs_buf_get(devp,blkno,len) (libxfs_getbuf((devp), (blkno), (len))) #define xfs_bwrite(bp) libxfs_writebuf((bp), 0) #define xfs_buf_oneshot(bp) ((void) 0) #define XBRW_READ LIBXFS_BREAD #define XBRW_WRITE LIBXFS_BWRITE #define xfs_buf_zero(bp,off,len) libxfs_iomove(bp,off,len,NULL,LIBXFS_BZERO) /* mount stuff */ #define XFS_MOUNT_32BITINODES LIBXFS_MOUNT_32BITINODES #define XFS_MOUNT_ATTR2 LIBXFS_MOUNT_ATTR2 #define XFS_MOUNT_SMALL_INUMS 0 /* ignored in userspace */ #define XFS_MOUNT_WSYNC 0 /* ignored in userspace */ #define XFS_MOUNT_NOALIGN 0 /* ignored in userspace */ #define XFS_MOUNT_IKEEP 0 /* ignored in userspace */ #define XFS_MOUNT_SWALLOC 0 /* ignored in userspace */ #define XFS_MOUNT_RDONLY 0 /* ignored in userspace */ #define XFS_MOUNT_BAD_SUMMARY 0 /* ignored in userspace */ #define xfs_trans_set_sync(tp) ((void) 0) #define xfs_trans_agblocks_delta(tp, d) #define xfs_trans_agflist_delta(tp, d) #define xfs_trans_agbtree_delta(tp, d) #define xfs_trans_buf_set_type(tp, bp, t) ({ \ int __t = (t); \ __t = __t; /* no set-but-unused warning */ \ tp = tp; /* no set-but-unused warning */ \ }) #define xfs_trans_buf_copy_type(dbp, sbp) /* no readahead, need to avoid set-but-unused var warnings. */ #define xfs_buf_readahead(a,d,c,ops) ({ \ xfs_daddr_t __d = d; \ __d = __d; /* no set-but-unused warning */ \ }) #define xfs_buf_readahead_map(a,b,c,ops) ((void) 0) /* no readahead */ #define xfs_sort qsort #define xfs_ilock(ip,mode) ((void) 0) #define xfs_ilock_data_map_shared(ip) (0) #define xfs_ilock_attr_map_shared(ip) (0) #define xfs_iunlock(ip,mode) ({ \ typeof(mode) __mode = mode; \ __mode = __mode; /* no set-but-unused warning */ \ }) /* space allocation */ #define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */ #define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */ #define xfs_extent_busy_reuse(mp,ag,bno,len,user) ((void) 0) /* avoid unused variable warning */ #define xfs_extent_busy_insert(tp,ag,bno,len,flags)({ \ xfs_agnumber_t __foo = ag; \ __foo = __foo; /* no set-but-unused warning */ \ }) #define xfs_extent_busy_trim(args,bno,len,busy_gen) ({ \ unsigned __foo = *(busy_gen); \ *(busy_gen) = __foo; \ false; \ }) #define xfs_extent_busy_flush(mp,pag,busy_gen) ((void)(0)) #define xfs_rotorstep 1 #define xfs_bmap_rtalloc(a) (-ENOSYS) #define xfs_get_extsz_hint(ip) (0) #define xfs_get_cowextsz_hint(ip) (0) #define xfs_inode_is_filestream(ip) (0) #define xfs_filestream_lookup_ag(ip) (0) #define xfs_filestream_new_ag(ip,ag) (0) /* quota bits */ #define xfs_trans_mod_dquot_byino(t,i,f,d) ((void) 0) #define xfs_trans_reserve_quota_nblks(t,i,b,n,f) (0) #define xfs_trans_unreserve_quota_nblks(t,i,b,n,f) ((void) 0) #define xfs_qm_dqattach(i) (0) #define uuid_copy(s,d) platform_uuid_copy((s),(d)) #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) #define xfs_icreate_log(tp, agno, agbno, cnt, isize, len, gen) ((void) 0) #define xfs_sb_validate_fsb_count(sbp, nblks) (0) /* * Prototypes for kernel static functions that are aren't in their * associated header files. */ struct xfs_da_args; struct xfs_bmap_free; struct xfs_bmap_free_item; struct xfs_mount; struct xfs_sb; struct xfs_trans; struct xfs_inode; struct xfs_log_item; struct xfs_buf; struct xfs_buf_map; struct xfs_buf_log_item; struct xfs_buftarg; /* xfs_attr.c */ int xfs_attr_rmtval_get(struct xfs_da_args *); /* xfs_bmap.c */ void xfs_bmap_del_free(struct xfs_bmap_free *, struct xfs_bmap_free_item *); /* xfs_mount.c */ int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t); void xfs_mount_common(struct xfs_mount *, struct xfs_sb *); /* * logitem.c and trans.c prototypes */ void xfs_trans_init(struct xfs_mount *); int xfs_trans_roll(struct xfs_trans **); /* xfs_trans_item.c */ void xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *); void xfs_trans_del_item(struct xfs_log_item *); /* xfs_inode_item.c */ void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *); /* xfs_buf_item.c */ void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); void xfs_buf_item_log(struct xfs_buf_log_item *, uint, uint); /* xfs_trans_buf.c */ struct xfs_buf *xfs_trans_buf_item_match(struct xfs_trans *, struct xfs_buftarg *, struct xfs_buf_map *, int); /* local source files */ #define xfs_mod_fdblocks(mp, delta, rsvd) \ libxfs_mod_incore_sb(mp, XFS_TRANS_SB_FDBLOCKS, delta, rsvd) #define xfs_mod_frextents(mp, delta) \ libxfs_mod_incore_sb(mp, XFS_TRANS_SB_FREXTENTS, delta, 0) int libxfs_mod_incore_sb(struct xfs_mount *, int, int64_t, int); /* percpu counters in mp are #defined to the superblock sb_ counters */ #define xfs_reinit_percpu_counters(mp) void xfs_trans_mod_sb(struct xfs_trans *, uint, long); void xfs_verifier_error(struct xfs_buf *bp, int error, xfs_failaddr_t failaddr); void xfs_inode_verifier_error(struct xfs_inode *ip, int error, const char *name, void *buf, size_t bufsz, xfs_failaddr_t failaddr); #define xfs_buf_verifier_error(bp,e,n,bu,bus,fa) \ xfs_verifier_error(bp, e, fa) /* XXX: this is clearly a bug - a shared header needs to export this */ /* xfs_rtalloc.c */ int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t); bool libxfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno); struct xfs_rtalloc_rec { xfs_rtblock_t ar_startext; xfs_rtblock_t ar_extcount; }; typedef int (*xfs_rtalloc_query_range_fn)( struct xfs_trans *tp, struct xfs_rtalloc_rec *rec, void *priv); int libxfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb, xfs_off_t count_fsb); bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t); void xfs_log_item_init(struct xfs_mount *, struct xfs_log_item *, int); #define xfs_log_in_recovery(mp) (false) /* xfs_icache.c */ #define xfs_inode_set_cowblocks_tag(ip) do { } while (0) #define xfs_inode_set_eofblocks_tag(ip) do { } while (0) /* xfs_stats.h */ #define XFS_STATS_CALC_INDEX(member) 0 #define XFS_STATS_INC_OFF(mp, off) #define XFS_STATS_ADD_OFF(mp, off, val) typedef unsigned char u8; unsigned int hweight8(unsigned int w); unsigned int hweight32(unsigned int w); unsigned int hweight64(__u64 w); #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) static inline void set_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); *p |= mask; } static inline void clear_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); *p &= ~mask; } static inline int test_bit(int nr, const volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); return *p & mask; } /* Sets and returns original value of the bit */ static inline int test_and_set_bit(int nr, volatile unsigned long *addr) { if (test_bit(nr, addr)) return 1; set_bit(nr, addr); return 0; } /* Keep static checkers quiet about nonstatic functions by exporting */ int xfs_inode_hasattr(struct xfs_inode *ip); int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args); int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, unsigned char *value, int *valuelenp, int flags); int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags); int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_rtbuf_get(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t block, int issum, struct xfs_buf **bpp); int xfs_rtcheck_range(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, int val, xfs_rtblock_t *new, int *stat); int xfs_rtfind_back(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_rtblock_t limit, xfs_rtblock_t *rtblock); int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_rtblock_t limit, xfs_rtblock_t *rtblock); int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, int val); int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp, int log, xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp, xfs_fsblock_t *rsb, xfs_suminfo_t *sum); int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log, xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp, xfs_fsblock_t *rsb); int xfs_rtfree_range(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, struct xfs_buf **rbpp, xfs_fsblock_t *rsb); int xfs_rtalloc_query_range(struct xfs_trans *tp, struct xfs_rtalloc_rec *low_rec, struct xfs_rtalloc_rec *high_rec, xfs_rtalloc_query_range_fn fn, void *priv); int xfs_rtalloc_query_all(struct xfs_trans *tp, xfs_rtalloc_query_range_fn fn, void *priv); bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno); int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, bool *is_free); /* xfs_bmap_util.h */ struct xfs_bmalloca; int xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz, int rt, int eof, int delay, int convert, xfs_fileoff_t *offp, xfs_extlen_t *lenp); void xfs_bmap_adjacent(struct xfs_bmalloca *ap); int xfs_bmap_last_extent(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *rec, int *is_empty); #endif /* __LIBXFS_INTERNAL_XFS_H__ */ xfsprogs-5.3.0/libxfs/logitem.c0000644000175000017500000000671413570057155016357 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" kmem_zone_t *xfs_buf_item_zone; kmem_zone_t *xfs_ili_zone; /* inode log item zone */ /* * Following functions from fs/xfs/xfs_trans_buf.c */ /* * Check to see if a buffer matching the given parameters is already * a part of the given transaction. */ xfs_buf_t * xfs_trans_buf_item_match( xfs_trans_t *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps) { struct xfs_log_item *lip; struct xfs_buf_log_item *blip; int len = 0; int i; for (i = 0; i < nmaps; i++) len += map[i].bm_len; list_for_each_entry(lip, &tp->t_items, li_trans) { blip = (struct xfs_buf_log_item *)lip; if (blip->bli_item.li_type == XFS_LI_BUF && blip->bli_buf->b_target->dev == btp->dev && XFS_BUF_ADDR(blip->bli_buf) == map[0].bm_bn && blip->bli_buf->b_bcount == BBTOB(len)) { ASSERT(blip->bli_buf->b_map_count == nmaps); return blip->bli_buf; } } return NULL; } /* * The following are from fs/xfs/xfs_buf_item.c */ /* * Allocate a new buf log item to go with the given buffer. * Set the buffer's b_log_item field to point to the new * buf log item. If there are other item's attached to the * buffer (see xfs_buf_attach_iodone() below), then put the * buf log item at the front. */ void xfs_buf_item_init( xfs_buf_t *bp, xfs_mount_t *mp) { xfs_log_item_t *lip; xfs_buf_log_item_t *bip; #ifdef LI_DEBUG fprintf(stderr, "buf_item_init for buffer %p\n", bp); #endif /* * Check to see if there is already a buf log item for * this buffer. If there is, it is guaranteed to be * the first. If we do already have one, there is * nothing to do here so return. */ XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); if (bp->b_log_item != NULL) { lip = bp->b_log_item; if (lip->li_type == XFS_LI_BUF) { #ifdef LI_DEBUG fprintf(stderr, "reused buf item %p for pre-logged buffer %p\n", lip, bp); #endif return; } } bip = (xfs_buf_log_item_t *)kmem_zone_zalloc(xfs_buf_item_zone, KM_SLEEP); #ifdef LI_DEBUG fprintf(stderr, "adding buf item %p for not-logged buffer %p\n", bip, bp); #endif xfs_log_item_init(mp, &bip->bli_item, XFS_LI_BUF); bip->bli_buf = bp; bip->__bli_format.blf_type = XFS_LI_BUF; bip->__bli_format.blf_blkno = (int64_t)XFS_BUF_ADDR(bp); bip->__bli_format.blf_len = (unsigned short)BTOBB(bp->b_bcount); bp->b_log_item = bip; } /* * Mark bytes first through last inclusive as dirty in the buf * item's bitmap. */ void xfs_buf_item_log( xfs_buf_log_item_t *bip, uint first, uint last) { /* * Mark the item as having some dirty data for * quick reference in xfs_buf_item_dirty. */ bip->bli_flags |= XFS_BLI_DIRTY; } /* * Initialize the inode log item for a newly allocated (in-core) inode. */ void xfs_inode_item_init( xfs_inode_t *ip, xfs_mount_t *mp) { xfs_inode_log_item_t *iip; ASSERT(ip->i_itemp == NULL); iip = ip->i_itemp = (xfs_inode_log_item_t *) kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); #ifdef LI_DEBUG fprintf(stderr, "inode_item_init for inode %llu, iip=%p\n", ip->i_ino, iip); #endif xfs_log_item_init(mp, &iip->ili_item, XFS_LI_INODE); iip->ili_inode = ip; } xfsprogs-5.3.0/libxfs/rdwr.c0000644000175000017500000011212213570057155015664 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "init.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "libxfs.h" /* for LIBXFS_EXIT_ON_FAILURE */ /* * Important design/architecture note: * * The userspace code that uses the buffer cache is much less constrained than * the kernel code. The userspace code is pretty nasty in places, especially * when it comes to buffer error handling. Very little of the userspace code * outside libxfs clears bp->b_error - very little code even checks it - so the * libxfs code is tripping on stale errors left by the userspace code. * * We can't clear errors or zero buffer contents in libxfs_getbuf-* like we do * in the kernel, because those functions are used by the libxfs_readbuf_* * functions and hence need to leave the buffers unchanged on cache hits. This * is actually the only way to gather a write error from a libxfs_writebuf() * call - you need to get the buffer again so you can check bp->b_error field - * assuming that the buffer is still in the cache when you check, that is. * * This is very different to the kernel code which does not release buffers on a * write so we can wait on IO and check errors. The kernel buffer cache also * guarantees a buffer of a known initial state from xfs_buf_get() even on a * cache hit. * * IOWs, userspace is behaving quite differently to the kernel and as a result * it leaks errors from reads, invalidations and writes through * libxfs_getbuf/libxfs_readbuf. * * The result of this is that until the userspace code outside libxfs is cleaned * up, functions that release buffers from userspace control (i.e * libxfs_writebuf/libxfs_putbuf) need to zero bp->b_error to prevent * propagation of stale errors into future buffer operations. */ #define BDSTRAT_SIZE (256 * 1024) #define IO_BCOMPARE_CHECK /* XXX: (dgc) Propagate errors, only exit if fail-on-error flag set */ int libxfs_device_zero(struct xfs_buftarg *btp, xfs_daddr_t start, uint len) { xfs_off_t start_offset, end_offset, offset; ssize_t zsize, bytes; char *z; int fd; zsize = min(BDSTRAT_SIZE, BBTOB(len)); if ((z = memalign(libxfs_device_alignment(), zsize)) == NULL) { fprintf(stderr, _("%s: %s can't memalign %d bytes: %s\n"), progname, __FUNCTION__, (int)zsize, strerror(errno)); exit(1); } memset(z, 0, zsize); fd = libxfs_device_to_fd(btp->dev); start_offset = LIBXFS_BBTOOFF64(start); if ((lseek(fd, start_offset, SEEK_SET)) < 0) { fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"), progname, __FUNCTION__, (unsigned long long)start_offset, strerror(errno)); exit(1); } end_offset = LIBXFS_BBTOOFF64(start + len) - start_offset; for (offset = 0; offset < end_offset; ) { bytes = min((ssize_t)(end_offset - offset), zsize); if ((bytes = write(fd, z, bytes)) < 0) { fprintf(stderr, _("%s: %s write failed: %s\n"), progname, __FUNCTION__, strerror(errno)); exit(1); } else if (bytes == 0) { fprintf(stderr, _("%s: %s not progressing?\n"), progname, __FUNCTION__); exit(1); } offset += bytes; } free(z); return 0; } static void unmount_record(void *p) { xlog_op_header_t *op = (xlog_op_header_t *)p; /* the data section must be 32 bit size aligned */ struct { uint16_t magic; uint16_t pad1; uint32_t pad2; /* may as well make it 64 bits */ } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; memset(p, 0, BBSIZE); /* dummy tid to mark this as written from userspace */ op->oh_tid = cpu_to_be32(0xb0c0d0d0); op->oh_len = cpu_to_be32(sizeof(magic)); op->oh_clientid = XFS_LOG; op->oh_flags = XLOG_UNMOUNT_TRANS; op->oh_res2 = 0; /* and the data for this op */ memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic)); } static char *next( char *ptr, int offset, void *private) { struct xfs_buf *buf = (struct xfs_buf *)private; if (buf && (buf->b_bcount < (int)(ptr - (char *)buf->b_addr) + offset)) abort(); return ptr + offset; } /* * Format the log. The caller provides either a buftarg which is used to access * the log via buffers or a direct pointer to a buffer that encapsulates the * entire log. */ int libxfs_log_clear( struct xfs_buftarg *btp, char *dptr, xfs_daddr_t start, uint length, /* basic blocks */ uuid_t *fs_uuid, int version, int sunit, /* bytes */ int fmt, int cycle, bool max) { struct xfs_buf *bp = NULL; int len; xfs_lsn_t lsn; xfs_lsn_t tail_lsn; xfs_daddr_t blk; xfs_daddr_t end_blk; char *ptr; if (((btp && dptr) || (!btp && !dptr)) || (btp && !btp->dev) || !fs_uuid) return -EINVAL; /* first zero the log */ if (btp) libxfs_device_zero(btp, start, length); else memset(dptr, 0, BBTOB(length)); /* * Initialize the log record length and LSNs. XLOG_INIT_CYCLE is a * special reset case where we only write a single record where the lsn * and tail_lsn match. Otherwise, the record lsn starts at block 0 of * the specified cycle and points tail_lsn at the last record of the * previous cycle. */ len = ((version == 2) && sunit) ? BTOBB(sunit) : 2; len = max(len, 2); lsn = xlog_assign_lsn(cycle, 0); if (cycle == XLOG_INIT_CYCLE) tail_lsn = lsn; else tail_lsn = xlog_assign_lsn(cycle - 1, length - len); /* write out the first log record */ ptr = dptr; if (btp) { bp = libxfs_getbufr(btp, start, len); ptr = bp->b_addr; } libxfs_log_header(ptr, fs_uuid, version, sunit, fmt, lsn, tail_lsn, next, bp); if (bp) { bp->b_flags |= LIBXFS_B_DIRTY; libxfs_putbufr(bp); } /* * There's nothing else to do if this is a log reset. The kernel detects * the rest of the log is zeroed and starts at cycle 1. */ if (cycle == XLOG_INIT_CYCLE) return 0; /* * Bump the record size for a full log format if the caller allows it. * This is primarily for performance reasons and most callers don't care * about record size since the log is clean after we're done. */ if (max) len = BTOBB(BDSTRAT_SIZE); /* * Otherwise, fill everything beyond the initial record with records of * the previous cycle so the kernel head/tail detection works correctly. * * We don't particularly care about the record size or content here. * It's only important that the headers are in place such that the * kernel finds 1.) a clean log and 2.) the correct current cycle value. * Therefore, bump up the record size to the max to use larger I/Os and * improve performance. */ cycle--; blk = start + len; if (dptr) dptr += BBTOB(len); end_blk = start + length; len = min(end_blk - blk, len); while (blk < end_blk) { lsn = xlog_assign_lsn(cycle, blk - start); tail_lsn = xlog_assign_lsn(cycle, blk - start - len); ptr = dptr; if (btp) { bp = libxfs_getbufr(btp, blk, len); ptr = bp->b_addr; } /* * Note: pass the full buffer length as the sunit to initialize * the entire buffer. */ libxfs_log_header(ptr, fs_uuid, version, BBTOB(len), fmt, lsn, tail_lsn, next, bp); if (bp) { bp->b_flags |= LIBXFS_B_DIRTY; libxfs_putbufr(bp); } blk += len; if (dptr) dptr += BBTOB(len); len = min(end_blk - blk, len); } return 0; } int libxfs_log_header( char *caddr, uuid_t *fs_uuid, int version, int sunit, int fmt, xfs_lsn_t lsn, xfs_lsn_t tail_lsn, libxfs_get_block_t *nextfunc, void *private) { xlog_rec_header_t *head = (xlog_rec_header_t *)caddr; char *p = caddr; __be32 cycle_lsn; int i, len; int hdrs = 1; if (lsn == NULLCOMMITLSN) lsn = xlog_assign_lsn(XLOG_INIT_CYCLE, 0); if (tail_lsn == NULLCOMMITLSN) tail_lsn = lsn; len = ((version == 2) && sunit) ? BTOBB(sunit) : 1; memset(p, 0, BBSIZE); head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); head->h_cycle = cpu_to_be32(CYCLE_LSN(lsn)); head->h_version = cpu_to_be32(version); head->h_crc = cpu_to_le32(0); head->h_prev_block = cpu_to_be32(-1); head->h_num_logops = cpu_to_be32(1); head->h_fmt = cpu_to_be32(fmt); head->h_size = cpu_to_be32(max(sunit, XLOG_BIG_RECORD_BSIZE)); head->h_lsn = cpu_to_be64(lsn); head->h_tail_lsn = cpu_to_be64(tail_lsn); memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t)); /* * The kernel expects to see either a log record header magic value or * the LSN cycle at the top of every log block. The first word of each * non-header block is copied to the record headers and replaced with * the cycle value (see xlog_[un]pack_data() and xlog_get_cycle() for * details). * * Even though we only ever write an unmount record (one block), we * support writing log records up to the max log buffer size of 256k to * improve log format performance. This means a record can require up * to 8 headers (1 rec. header + 7 ext. headers) for the packed cycle * data (each header supports 32k of data). */ cycle_lsn = CYCLE_LSN_DISK(head->h_lsn); if (version == 2 && sunit > XLOG_HEADER_CYCLE_SIZE) { hdrs = sunit / XLOG_HEADER_CYCLE_SIZE; if (sunit % XLOG_HEADER_CYCLE_SIZE) hdrs++; } /* * A fixed number of extended headers is expected based on h_size. If * required, format those now so the unmount record is located * correctly. * * Since we only write an unmount record, we only need one h_cycle_data * entry for the unmount record block. The subsequent record data * blocks are zeroed, which means we can stamp them directly with the * cycle and zero the rest of the cycle data in the extended headers. */ if (hdrs > 1) { for (i = 1; i < hdrs; i++) { p = nextfunc(p, BBSIZE, private); memset(p, 0, BBSIZE); /* xlog_rec_ext_header.xh_cycle */ *(__be32 *)p = cycle_lsn; } } /* * The total length is the max of the stripe unit or 2 basic block * minimum (1 hdr blk + 1 data blk). The record length is the total * minus however many header blocks are required. */ head->h_len = cpu_to_be32(max(BBTOB(2), sunit) - hdrs * BBSIZE); /* * Write out the unmount record, pack the first word into the record * header and stamp the block with the cycle. */ p = nextfunc(p, BBSIZE, private); unmount_record(p); head->h_cycle_data[0] = *(__be32 *)p; *(__be32 *)p = cycle_lsn; /* * Finally, zero all remaining blocks in the record and stamp each with * the cycle. We don't need to pack any of these blocks because the * cycle data in the headers has already been zeroed. */ len = max(len, hdrs + 1); for (i = hdrs + 1; i < len; i++) { p = nextfunc(p, BBSIZE, private); memset(p, 0, BBSIZE); *(__be32 *)p = cycle_lsn; } return BBTOB(len); } /* * Simple I/O (buffer cache) interface */ #ifdef XFS_BUF_TRACING #undef libxfs_readbuf #undef libxfs_readbuf_map #undef libxfs_writebuf #undef libxfs_getbuf #undef libxfs_getbuf_map #undef libxfs_getbuf_flags #undef libxfs_putbuf xfs_buf_t *libxfs_readbuf(struct xfs_buftarg *, xfs_daddr_t, int, int, const struct xfs_buf_ops *); xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int, const struct xfs_buf_ops *); int libxfs_writebuf(xfs_buf_t *, int); xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int); xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int); xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int, unsigned int); void libxfs_putbuf (xfs_buf_t *); #define __add_trace(bp, func, file, line) \ do { \ if (bp) { \ (bp)->b_func = (func); \ (bp)->b_file = (file); \ (bp)->b_line = (line); \ } \ } while (0) xfs_buf_t * libxfs_trace_readbuf(const char *func, const char *file, int line, struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags, const struct xfs_buf_ops *ops) { xfs_buf_t *bp = libxfs_readbuf(btp, blkno, len, flags, ops); __add_trace(bp, func, file, line); return bp; } xfs_buf_t * libxfs_trace_readbuf_map(const char *func, const char *file, int line, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags, const struct xfs_buf_ops *ops) { xfs_buf_t *bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops); __add_trace(bp, func, file, line); return bp; } int libxfs_trace_writebuf(const char *func, const char *file, int line, xfs_buf_t *bp, int flags) { __add_trace(bp, func, file, line); return libxfs_writebuf(bp, flags); } xfs_buf_t * libxfs_trace_getbuf(const char *func, const char *file, int line, struct xfs_buftarg *btp, xfs_daddr_t blkno, int len) { xfs_buf_t *bp = libxfs_getbuf(btp, blkno, len); __add_trace(bp, func, file, line); return bp; } xfs_buf_t * libxfs_trace_getbuf_map(const char *func, const char *file, int line, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags) { xfs_buf_t *bp = libxfs_getbuf_map(btp, map, nmaps, flags); __add_trace(bp, func, file, line); return bp; } xfs_buf_t * libxfs_trace_getbuf_flags(const char *func, const char *file, int line, struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, unsigned int flags) { xfs_buf_t *bp = libxfs_getbuf_flags(btp, blkno, len, flags); __add_trace(bp, func, file, line); return bp; } void libxfs_trace_putbuf(const char *func, const char *file, int line, xfs_buf_t *bp) { __add_trace(bp, func, file, line); libxfs_putbuf(bp); } #endif xfs_buf_t * libxfs_getsb(xfs_mount_t *mp) { return libxfs_readbuf(mp->m_ddev_targp, XFS_SB_DADDR, XFS_FSS_TO_BB(mp, 1), 0, &xfs_sb_buf_ops); } kmem_zone_t *xfs_buf_zone; static struct cache_mru xfs_buf_freelist = {{&xfs_buf_freelist.cm_list, &xfs_buf_freelist.cm_list}, 0, PTHREAD_MUTEX_INITIALIZER }; /* * The bufkey is used to pass the new buffer information to the cache object * allocation routine. Because discontiguous buffers need to pass different * information, we need fields to pass that information. However, because the * blkno and bblen is needed for the initial cache entry lookup (i.e. for * bcompare) the fact that the map/nmaps is non-null to switch to discontiguous * buffer initialisation instead of a contiguous buffer. */ struct xfs_bufkey { struct xfs_buftarg *buftarg; xfs_daddr_t blkno; unsigned int bblen; struct xfs_buf_map *map; int nmaps; }; /* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ #define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL #define CACHE_LINE_SIZE 64 static unsigned int libxfs_bhash(cache_key_t key, unsigned int hashsize, unsigned int hashshift) { uint64_t hashval = ((struct xfs_bufkey *)key)->blkno; uint64_t tmp; tmp = hashval ^ (GOLDEN_RATIO_PRIME + hashval) / CACHE_LINE_SIZE; tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> hashshift); return tmp % hashsize; } static int libxfs_bcompare(struct cache_node *node, cache_key_t key) { struct xfs_buf *bp = (struct xfs_buf *)node; struct xfs_bufkey *bkey = (struct xfs_bufkey *)key; if (bp->b_target->dev == bkey->buftarg->dev && bp->b_bn == bkey->blkno) { if (bp->b_bcount == BBTOB(bkey->bblen)) return CACHE_HIT; #ifdef IO_BCOMPARE_CHECK if (!(libxfs_bcache->c_flags & CACHE_MISCOMPARE_PURGE)) { fprintf(stderr, "%lx: Badness in key lookup (length)\n" "bp=(bno 0x%llx, len %u bytes) key=(bno 0x%llx, len %u bytes)\n", pthread_self(), (unsigned long long)bp->b_bn, (int)bp->b_bcount, (unsigned long long)bkey->blkno, BBTOB(bkey->bblen)); } #endif return CACHE_PURGE; } return CACHE_MISS; } static void __initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno, unsigned int bytes) { bp->b_flags = 0; bp->b_bn = bno; bp->b_bcount = bytes; bp->b_length = BTOBB(bytes); bp->b_target = btp; bp->b_mount = btp->bt_mount; bp->b_error = 0; if (!bp->b_addr) bp->b_addr = memalign(libxfs_device_alignment(), bytes); if (!bp->b_addr) { fprintf(stderr, _("%s: %s can't memalign %u bytes: %s\n"), progname, __FUNCTION__, bytes, strerror(errno)); exit(1); } memset(bp->b_addr, 0, bytes); #ifdef XFS_BUF_TRACING list_head_init(&bp->b_lock_list); #endif pthread_mutex_init(&bp->b_lock, NULL); bp->b_holder = 0; bp->b_recur = 0; bp->b_ops = NULL; if (!bp->b_maps) { bp->b_nmaps = 1; bp->b_maps = &bp->__b_map; bp->b_maps[0].bm_bn = bp->b_bn; bp->b_maps[0].bm_len = bp->b_length; } } static void libxfs_initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno, unsigned int bytes) { __initbuf(bp, btp, bno, bytes); } static void libxfs_initbuf_map(xfs_buf_t *bp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps) { unsigned int bytes = 0; int i; bytes = sizeof(struct xfs_buf_map) * nmaps; bp->b_maps = malloc(bytes); if (!bp->b_maps) { fprintf(stderr, _("%s: %s can't malloc %u bytes: %s\n"), progname, __FUNCTION__, bytes, strerror(errno)); exit(1); } bp->b_nmaps = nmaps; bytes = 0; for ( i = 0; i < nmaps; i++) { bp->b_maps[i].bm_bn = map[i].bm_bn; bp->b_maps[i].bm_len = map[i].bm_len; bytes += BBTOB(map[i].bm_len); } __initbuf(bp, btp, map[0].bm_bn, bytes); bp->b_flags |= LIBXFS_B_DISCONTIG; } static xfs_buf_t * __libxfs_getbufr(int blen) { xfs_buf_t *bp; /* * first look for a buffer that can be used as-is, * if one cannot be found, see if there is a buffer, * and if so, free its buffer and set b_addr to NULL * before calling libxfs_initbuf. */ pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); if (!list_empty(&xfs_buf_freelist.cm_list)) { list_for_each_entry(bp, &xfs_buf_freelist.cm_list, b_node.cn_mru) { if (bp->b_bcount == blen) { list_del_init(&bp->b_node.cn_mru); break; } } if (&bp->b_node.cn_mru == &xfs_buf_freelist.cm_list) { bp = list_entry(xfs_buf_freelist.cm_list.next, xfs_buf_t, b_node.cn_mru); list_del_init(&bp->b_node.cn_mru); free(bp->b_addr); bp->b_addr = NULL; if (bp->b_maps != &bp->__b_map) free(bp->b_maps); bp->b_maps = NULL; } } else bp = kmem_zone_zalloc(xfs_buf_zone, 0); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); bp->b_ops = NULL; if (bp->b_flags & LIBXFS_B_DIRTY) fprintf(stderr, "found dirty buffer (bulk) on free list!"); return bp; } xfs_buf_t * libxfs_getbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, int bblen) { xfs_buf_t *bp; int blen = BBTOB(bblen); bp =__libxfs_getbufr(blen); if (bp) libxfs_initbuf(bp, btp, blkno, blen); #ifdef IO_DEBUG printf("%lx: %s: allocated %u bytes buffer, key=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, blen, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return bp; } static xfs_buf_t * libxfs_getbufr_map(struct xfs_buftarg *btp, xfs_daddr_t blkno, int bblen, struct xfs_buf_map *map, int nmaps) { xfs_buf_t *bp; int blen = BBTOB(bblen); if (!map || !nmaps) { fprintf(stderr, _("%s: %s invalid map %p or nmaps %d\n"), progname, __FUNCTION__, map, nmaps); exit(1); } if (blkno != map[0].bm_bn) { fprintf(stderr, _("%s: %s map blkno 0x%llx doesn't match key 0x%llx\n"), progname, __FUNCTION__, (long long)map[0].bm_bn, (long long)blkno); exit(1); } bp =__libxfs_getbufr(blen); if (bp) libxfs_initbuf_map(bp, btp, map, nmaps); #ifdef IO_DEBUG printf("%lx: %s: allocated %u bytes buffer, key=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, blen, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return bp; } #ifdef XFS_BUF_TRACING struct list_head lock_buf_list = {&lock_buf_list, &lock_buf_list}; int lock_buf_count = 0; #endif static struct xfs_buf * __cache_lookup(struct xfs_bufkey *key, unsigned int flags) { struct xfs_buf *bp; cache_node_get(libxfs_bcache, key, (struct cache_node **)&bp); if (!bp) return NULL; if (use_xfs_buf_lock) { int ret; ret = pthread_mutex_trylock(&bp->b_lock); if (ret) { ASSERT(ret == EAGAIN); if (flags & LIBXFS_GETBUF_TRYLOCK) goto out_put; if (pthread_equal(bp->b_holder, pthread_self())) { fprintf(stderr, _("Warning: recursive buffer locking at block %" PRIu64 " detected\n"), key->blkno); bp->b_recur++; return bp; } else { pthread_mutex_lock(&bp->b_lock); } } bp->b_holder = pthread_self(); } cache_node_set_priority(libxfs_bcache, (struct cache_node *)bp, cache_node_get_priority((struct cache_node *)bp) - CACHE_PREFETCH_PRIORITY); #ifdef XFS_BUF_TRACING pthread_mutex_lock(&libxfs_bcache->c_mutex); lock_buf_count++; list_add(&bp->b_lock_list, &lock_buf_list); pthread_mutex_unlock(&libxfs_bcache->c_mutex); #endif #ifdef IO_DEBUG printf("%lx %s: hit buffer %p for bno = 0x%llx/0x%llx\n", pthread_self(), __FUNCTION__, bp, bp->b_bn, (long long)LIBXFS_BBTOOFF64(key->blkno)); #endif return bp; out_put: cache_node_put(libxfs_bcache, (struct cache_node *)bp); return NULL; } struct xfs_buf * libxfs_getbuf_flags(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, unsigned int flags) { struct xfs_bufkey key = {NULL}; key.buftarg = btp; key.blkno = blkno; key.bblen = len; return __cache_lookup(&key, flags); } /* * Clean the buffer flags for libxfs_getbuf*(), which wants to return * an unused buffer with clean state. This prevents CRC errors on a * re-read of a corrupt block that was prefetched and freed. This * can happen with a massively corrupt directory that is discarded, * but whose blocks are then recycled into expanding lost+found. * * Note however that if the buffer's dirty (prefetch calls getbuf) * we'll leave the state alone because we don't want to discard blocks * that have been fixed. */ static void reset_buf_state( struct xfs_buf *bp) { if (bp && !(bp->b_flags & LIBXFS_B_DIRTY)) bp->b_flags &= ~(LIBXFS_B_UNCHECKED | LIBXFS_B_STALE | LIBXFS_B_UPTODATE); } struct xfs_buf * libxfs_getbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len) { struct xfs_buf *bp; bp = libxfs_getbuf_flags(btp, blkno, len, 0); reset_buf_state(bp); return bp; } static struct xfs_buf * __libxfs_getbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags) { struct xfs_bufkey key = {NULL}; int i; if (nmaps == 1) return libxfs_getbuf_flags(btp, map[0].bm_bn, map[0].bm_len, flags); key.buftarg = btp; key.blkno = map[0].bm_bn; for (i = 0; i < nmaps; i++) { key.bblen += map[i].bm_len; } key.map = map; key.nmaps = nmaps; return __cache_lookup(&key, flags); } struct xfs_buf * libxfs_getbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags) { struct xfs_buf *bp; bp = __libxfs_getbuf_map(btp, map, nmaps, flags); reset_buf_state(bp); return bp; } void libxfs_putbuf(xfs_buf_t *bp) { /* * ensure that any errors on this use of the buffer don't carry * over to the next user. */ bp->b_error = 0; #ifdef XFS_BUF_TRACING pthread_mutex_lock(&libxfs_bcache->c_mutex); lock_buf_count--; ASSERT(lock_buf_count >= 0); list_del_init(&bp->b_lock_list); pthread_mutex_unlock(&libxfs_bcache->c_mutex); #endif if (use_xfs_buf_lock) { if (bp->b_recur) { bp->b_recur--; } else { bp->b_holder = 0; pthread_mutex_unlock(&bp->b_lock); } } if (!list_empty(&bp->b_node.cn_hash)) cache_node_put(libxfs_bcache, (struct cache_node *)bp); else if (--bp->b_node.cn_count == 0) libxfs_putbufr(bp); } void libxfs_purgebuf(xfs_buf_t *bp) { struct xfs_bufkey key = {NULL}; key.buftarg = bp->b_target; key.blkno = bp->b_bn; key.bblen = bp->b_length; cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp); } static struct cache_node * libxfs_balloc(cache_key_t key) { struct xfs_bufkey *bufkey = (struct xfs_bufkey *)key; if (bufkey->map) return (struct cache_node *) libxfs_getbufr_map(bufkey->buftarg, bufkey->blkno, bufkey->bblen, bufkey->map, bufkey->nmaps); return (struct cache_node *)libxfs_getbufr(bufkey->buftarg, bufkey->blkno, bufkey->bblen); } static int __read_buf(int fd, void *buf, int len, off64_t offset, int flags) { int sts; sts = pread(fd, buf, len, offset); if (sts < 0) { int error = errno; fprintf(stderr, _("%s: read failed: %s\n"), progname, strerror(error)); if (flags & LIBXFS_EXIT_ON_FAILURE) exit(1); return -error; } else if (sts != len) { fprintf(stderr, _("%s: error - read only %d of %d bytes\n"), progname, sts, len); if (flags & LIBXFS_EXIT_ON_FAILURE) exit(1); return -EIO; } return 0; } int libxfs_readbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, xfs_buf_t *bp, int len, int flags) { int fd = libxfs_device_to_fd(btp->dev); int bytes = BBTOB(len); int error; ASSERT(BBTOB(len) <= bp->b_bcount); error = __read_buf(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno), flags); if (!error && bp->b_target->dev == btp->dev && bp->b_bn == blkno && bp->b_bcount == bytes) bp->b_flags |= LIBXFS_B_UPTODATE; #ifdef IO_DEBUG printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, bytes, error, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return error; } void libxfs_readbuf_verify(struct xfs_buf *bp, const struct xfs_buf_ops *ops) { if (!ops) return; bp->b_ops = ops; bp->b_ops->verify_read(bp); bp->b_flags &= ~LIBXFS_B_UNCHECKED; } xfs_buf_t * libxfs_readbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags, const struct xfs_buf_ops *ops) { xfs_buf_t *bp; int error; bp = libxfs_getbuf_flags(btp, blkno, len, 0); if (!bp) return NULL; /* * if the buffer was prefetched, it is likely that it was not validated. * Hence if we are supplied an ops function and the buffer is marked as * unchecked, we need to validate it now. * * We do this verification even if the buffer is dirty - the * verification is almost certainly going to fail the CRC check in this * case as a dirty buffer has not had the CRC recalculated. However, we * should not be dirtying unchecked buffers and therefore failing it * here because it's dirty and unchecked indicates we've screwed up * somewhere else. */ bp->b_error = 0; if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) { if (bp->b_flags & LIBXFS_B_UNCHECKED) libxfs_readbuf_verify(bp, ops); return bp; } /* * Set the ops on a cache miss (i.e. first physical read) as the * verifier may change the ops to match the type of buffer it contains. * A cache hit might reset the verifier to the original type if we set * it again, but it won't get called again and set to match the buffer * contents. *cough* xfs_da_node_buf_ops *cough*. */ error = libxfs_readbufr(btp, blkno, bp, len, flags); if (error) bp->b_error = error; else libxfs_readbuf_verify(bp, ops); return bp; } int libxfs_readbufr_map(struct xfs_buftarg *btp, struct xfs_buf *bp, int flags) { int fd; int error = 0; void *buf; int i; fd = libxfs_device_to_fd(btp->dev); buf = bp->b_addr; for (i = 0; i < bp->b_nmaps; i++) { off64_t offset = LIBXFS_BBTOOFF64(bp->b_maps[i].bm_bn); int len = BBTOB(bp->b_maps[i].bm_len); error = __read_buf(fd, buf, len, offset, flags); if (error) { bp->b_error = error; break; } buf += len; } if (!error) bp->b_flags |= LIBXFS_B_UPTODATE; #ifdef IO_DEBUG printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n", pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp); #endif return error; } struct xfs_buf * libxfs_readbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; int error = 0; if (nmaps == 1) return libxfs_readbuf(btp, map[0].bm_bn, map[0].bm_len, flags, ops); bp = __libxfs_getbuf_map(btp, map, nmaps, 0); if (!bp) return NULL; bp->b_error = 0; if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) { if (bp->b_flags & LIBXFS_B_UNCHECKED) libxfs_readbuf_verify(bp, ops); return bp; } error = libxfs_readbufr_map(btp, bp, flags); if (!error) libxfs_readbuf_verify(bp, ops); #ifdef IO_DEBUGX printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n", pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp); #endif return bp; } static int __write_buf(int fd, void *buf, int len, off64_t offset, int flags) { int sts; sts = pwrite(fd, buf, len, offset); if (sts < 0) { int error = errno; fprintf(stderr, _("%s: pwrite failed: %s\n"), progname, strerror(error)); if (flags & LIBXFS_B_EXIT) exit(1); return -error; } else if (sts != len) { fprintf(stderr, _("%s: error - pwrite only %d of %d bytes\n"), progname, sts, len); if (flags & LIBXFS_B_EXIT) exit(1); return -EIO; } return 0; } int libxfs_writebufr(xfs_buf_t *bp) { int fd = libxfs_device_to_fd(bp->b_target->dev); /* * we never write buffers that are marked stale. This indicates they * contain data that has been invalidated, and even if the buffer is * dirty it must *never* be written. Verifiers are wonderful for finding * bugs like this. Make sure the error is obvious as to the cause. */ if (bp->b_flags & LIBXFS_B_STALE) { bp->b_error = -ESTALE; return bp->b_error; } /* * clear any pre-existing error status on the buffer. This can occur if * the buffer is corrupt on disk and the repair process doesn't clear * the error before fixing and writing it back. */ bp->b_error = 0; if (bp->b_ops) { bp->b_ops->verify_write(bp); if (bp->b_error) { fprintf(stderr, _("%s: write verifier failed on %s bno 0x%llx/0x%x\n"), __func__, bp->b_ops->name, (long long)bp->b_bn, bp->b_bcount); return bp->b_error; } } if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) { bp->b_error = __write_buf(fd, bp->b_addr, bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_bn), bp->b_flags); } else { int i; void *buf = bp->b_addr; for (i = 0; i < bp->b_nmaps; i++) { off64_t offset = LIBXFS_BBTOOFF64(bp->b_maps[i].bm_bn); int len = BBTOB(bp->b_maps[i].bm_len); bp->b_error = __write_buf(fd, buf, len, offset, bp->b_flags); if (bp->b_error) break; buf += len; } } #ifdef IO_DEBUG printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p, error %d\n", pthread_self(), __FUNCTION__, bp->b_bcount, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp, bp->b_error); #endif if (!bp->b_error) { bp->b_flags |= LIBXFS_B_UPTODATE; bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT | LIBXFS_B_UNCHECKED); } return bp->b_error; } int libxfs_writebuf_int(xfs_buf_t *bp, int flags) { /* * Clear any error hanging over from reading the buffer. This prevents * subsequent reads after this write from seeing stale errors. */ bp->b_error = 0; bp->b_flags &= ~LIBXFS_B_STALE; bp->b_flags |= (LIBXFS_B_DIRTY | flags); return 0; } int libxfs_writebuf(xfs_buf_t *bp, int flags) { #ifdef IO_DEBUG printf("%lx: %s: dirty blkno=%llu(%llu)\n", pthread_self(), __FUNCTION__, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn); #endif /* * Clear any error hanging over from reading the buffer. This prevents * subsequent reads after this write from seeing stale errors. */ bp->b_error = 0; bp->b_flags &= ~LIBXFS_B_STALE; bp->b_flags |= (LIBXFS_B_DIRTY | flags); libxfs_putbuf(bp); return 0; } void libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags) { #ifdef IO_DEBUG if (boff + len > bp->b_bcount) { printf("Badness, iomove out of range!\n" "bp=(bno 0x%llx, bytes %u) range=(boff %u, bytes %u)\n", (long long)bp->b_bn, bp->b_bcount, boff, len); abort(); } #endif switch (flags) { case LIBXFS_BZERO: memset(bp->b_addr + boff, 0, len); break; case LIBXFS_BREAD: memcpy(data, bp->b_addr + boff, len); break; case LIBXFS_BWRITE: memcpy(bp->b_addr + boff, data, len); break; } } static void libxfs_brelse( struct cache_node *node) { struct xfs_buf *bp = (struct xfs_buf *)node; if (!bp) return; if (bp->b_flags & LIBXFS_B_DIRTY) fprintf(stderr, "releasing dirty buffer to free list!"); pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); } static unsigned int libxfs_bulkrelse( struct cache *cache, struct list_head *list) { xfs_buf_t *bp; int count = 0; if (list_empty(list)) return 0 ; list_for_each_entry(bp, list, b_node.cn_mru) { if (bp->b_flags & LIBXFS_B_DIRTY) fprintf(stderr, "releasing dirty buffer (bulk) to free list!"); count++; } pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); list_splice(list, &xfs_buf_freelist.cm_list); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); return count; } /* * Free everything from the xfs_buf_freelist MRU, used at final teardown */ void libxfs_bcache_free(void) { struct list_head *cm_list; xfs_buf_t *bp, *next; cm_list = &xfs_buf_freelist.cm_list; list_for_each_entry_safe(bp, next, cm_list, b_node.cn_mru) { free(bp->b_addr); if (bp->b_maps != &bp->__b_map) free(bp->b_maps); kmem_zone_free(xfs_buf_zone, bp); } } /* * When a buffer is marked dirty, the error is cleared. Hence if we are trying * to flush a buffer prior to cache reclaim that has an error on it it means * we've already tried to flush it and it failed. Prevent repeated corruption * errors from being reported by skipping such buffers - when the corruption is * fixed the buffer will be marked dirty again and we can write it again. */ static int libxfs_bflush( struct cache_node *node) { struct xfs_buf *bp = (struct xfs_buf *)node; if (!bp->b_error && bp->b_flags & LIBXFS_B_DIRTY) return libxfs_writebufr(bp); return bp->b_error; } void libxfs_putbufr(xfs_buf_t *bp) { if (bp->b_flags & LIBXFS_B_DIRTY) libxfs_writebufr(bp); libxfs_brelse((struct cache_node *)bp); } void libxfs_bcache_purge(void) { cache_purge(libxfs_bcache); } void libxfs_bcache_flush(void) { cache_flush(libxfs_bcache); } int libxfs_bcache_overflowed(void) { return cache_overflowed(libxfs_bcache); } struct cache_operations libxfs_bcache_operations = { .hash = libxfs_bhash, .alloc = libxfs_balloc, .flush = libxfs_bflush, .relse = libxfs_brelse, .compare = libxfs_bcompare, .bulkrelse = libxfs_bulkrelse }; /* * Verify an on-disk magic value against the magic value specified in the * verifier structure. The verifier magic is in disk byte order so the caller is * expected to pass the value directly from disk. */ bool xfs_verify_magic( struct xfs_buf *bp, __be32 dmagic) { struct xfs_mount *mp = bp->b_mount; int idx; idx = xfs_sb_version_hascrc(&mp->m_sb); if (unlikely(WARN_ON(!bp->b_ops || !bp->b_ops->magic[idx]))) return false; return dmagic == bp->b_ops->magic[idx]; } /* * Verify an on-disk magic value against the magic value specified in the * verifier structure. The verifier magic is in disk byte order so the caller is * expected to pass the value directly from disk. */ bool xfs_verify_magic16( struct xfs_buf *bp, __be16 dmagic) { struct xfs_mount *mp = bp->b_mount; int idx; idx = xfs_sb_version_hascrc(&mp->m_sb); if (unlikely(WARN_ON(!bp->b_ops || !bp->b_ops->magic16[idx]))) return false; return dmagic == bp->b_ops->magic16[idx]; } /* * Inode cache stubs. */ kmem_zone_t *xfs_inode_zone; extern kmem_zone_t *xfs_ili_zone; /* * If there are inline format data / attr forks attached to this inode, * make sure they're not corrupt. */ bool libxfs_inode_verify_forks( struct xfs_inode *ip) { struct xfs_ifork *ifp; xfs_failaddr_t fa; if (!ip->i_fork_ops) return true; fa = xfs_ifork_verify_data(ip, ip->i_fork_ops); if (fa) { ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "data fork", ifp->if_u1.if_data, ifp->if_bytes, fa); return false; } fa = xfs_ifork_verify_attr(ip, ip->i_fork_ops); if (fa) { ifp = XFS_IFORK_PTR(ip, XFS_ATTR_FORK); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "attr fork", ifp ? ifp->if_u1.if_data : NULL, ifp ? ifp->if_bytes : 0, fa); return false; } return true; } int libxfs_iget( struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino, uint lock_flags, struct xfs_inode **ipp, struct xfs_ifork_ops *ifork_ops) { struct xfs_inode *ip; int error = 0; ip = kmem_zone_zalloc(xfs_inode_zone, 0); if (!ip) return -ENOMEM; ip->i_ino = ino; ip->i_mount = mp; error = xfs_iread(mp, tp, ip, 0); if (error) { kmem_zone_free(xfs_inode_zone, ip); *ipp = NULL; return error; } ip->i_fork_ops = ifork_ops; if (!libxfs_inode_verify_forks(ip)) { libxfs_irele(ip); return -EFSCORRUPTED; } /* * set up the inode ops structure that the libxfs code relies on */ if (XFS_ISDIR(ip)) ip->d_ops = mp->m_dir_inode_ops; else ip->d_ops = mp->m_nondir_inode_ops; *ipp = ip; return 0; } static void libxfs_idestroy(xfs_inode_t *ip) { switch (VFS_I(ip)->i_mode & S_IFMT) { case S_IFREG: case S_IFDIR: case S_IFLNK: libxfs_idestroy_fork(ip, XFS_DATA_FORK); break; } if (ip->i_afp) libxfs_idestroy_fork(ip, XFS_ATTR_FORK); if (ip->i_cowfp) xfs_idestroy_fork(ip, XFS_COW_FORK); } void libxfs_irele( struct xfs_inode *ip) { ASSERT(ip->i_itemp == NULL); libxfs_idestroy(ip); kmem_zone_free(xfs_inode_zone, ip); } /* * Write out a buffer list synchronously. * * This will take the @buffer_list, write all buffers out and wait for I/O * completion on all of the buffers. @buffer_list is consumed by the function, * so callers must have some other way of tracking buffers if they require such * functionality. */ int xfs_buf_delwri_submit( struct list_head *buffer_list) { struct xfs_buf *bp, *n; int error = 0, error2; list_for_each_entry_safe(bp, n, buffer_list, b_list) { list_del_init(&bp->b_list); error2 = libxfs_writebuf(bp, 0); if (!error) error = error2; } return error; } xfsprogs-5.3.0/libxfs/trans.c0000644000175000017500000005603313570057155016045 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005-2006 Silicon Graphics, Inc. * Copyright (C) 2010 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_sb.h" #include "xfs_defer.h" #include "xfs_trace.h" static void xfs_trans_free_items(struct xfs_trans *tp); STATIC struct xfs_trans *xfs_trans_dup(struct xfs_trans *tp); static int xfs_trans_reserve(struct xfs_trans *tp, struct xfs_trans_res *resp, uint blocks, uint rtextents); static int __xfs_trans_commit(struct xfs_trans *tp, bool regrant); /* * Simple transaction interface */ kmem_zone_t *xfs_trans_zone; /* * Initialize the precomputed transaction reservation values * in the mount structure. */ void libxfs_trans_init( struct xfs_mount *mp) { xfs_trans_resv_calc(mp, &mp->m_resv); } /* * Add the given log item to the transaction's list of log items. */ void libxfs_trans_add_item( struct xfs_trans *tp, struct xfs_log_item *lip) { ASSERT(lip->li_mountp == tp->t_mountp); ASSERT(lip->li_ailp == tp->t_mountp->m_ail); ASSERT(list_empty(&lip->li_trans)); ASSERT(!test_bit(XFS_LI_DIRTY, &lip->li_flags)); list_add_tail(&lip->li_trans, &tp->t_items); } /* * Unlink and free the given descriptor. */ void libxfs_trans_del_item( struct xfs_log_item *lip) { clear_bit(XFS_LI_DIRTY, &lip->li_flags); list_del_init(&lip->li_trans); } /* * Roll from one trans in the sequence of PERMANENT transactions to * the next: permanent transactions are only flushed out when * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon * as possible to let chunks of it go to the log. So we commit the * chunk we've been working on and get a new transaction to continue. */ int libxfs_trans_roll( struct xfs_trans **tpp) { struct xfs_trans *trans = *tpp; struct xfs_trans_res tres; int error; /* * Copy the critical parameters from one trans to the next. */ tres.tr_logres = trans->t_log_res; tres.tr_logcount = trans->t_log_count; *tpp = xfs_trans_dup(trans); /* * Commit the current transaction. * If this commit failed, then it'd just unlock those items that * are marked to be released. That also means that a filesystem shutdown * is in progress. The caller takes the responsibility to cancel * the duplicate transaction that gets returned. */ error = __xfs_trans_commit(trans, true); if (error) return error; /* * Reserve space in the log for the next transaction. * This also pushes items in the "AIL", the list of logged items, * out to disk if they are taking up space at the tail of the log * that we want to use. This requires that either nothing be locked * across this call, or that anything that is locked be logged in * the prior and the next transactions. */ tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; return xfs_trans_reserve(*tpp, &tres, 0, 0); } /* * Free the transaction structure. If there is more clean up * to do when the structure is freed, add it here. */ static void xfs_trans_free( struct xfs_trans *tp) { kmem_zone_free(xfs_trans_zone, tp); } /* * This is called to create a new transaction which will share the * permanent log reservation of the given transaction. The remaining * unused block and rt extent reservations are also inherited. This * implies that the original transaction is no longer allowed to allocate * blocks. Locks and log items, however, are no inherited. They must * be added to the new transaction explicitly. */ STATIC struct xfs_trans * xfs_trans_dup( struct xfs_trans *tp) { struct xfs_trans *ntp; ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); /* * Initialize the new transaction structure. */ ntp->t_mountp = tp->t_mountp; INIT_LIST_HEAD(&ntp->t_items); INIT_LIST_HEAD(&ntp->t_dfops); ntp->t_firstblock = NULLFSBLOCK; ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE) | (tp->t_flags & XFS_TRANS_NO_WRITECOUNT); /* We gave our writer reference to the new transaction */ tp->t_flags |= XFS_TRANS_NO_WRITECOUNT; ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; tp->t_blk_res = tp->t_blk_res_used; /* move deferred ops over to the new tp */ xfs_defer_move(ntp, tp); return ntp; } /* * This is called to reserve free disk blocks and log space for the * given transaction. This must be done before allocating any resources * within the transaction. * * This will return ENOSPC if there are not enough blocks available. * It will sleep waiting for available log space. * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which * is used by long running transactions. If any one of the reservations * fails then they will all be backed out. * * This does not do quota reservations. That typically is done by the * caller afterwards. */ static int xfs_trans_reserve( struct xfs_trans *tp, struct xfs_trans_res *resp, uint blocks, uint rtextents) { int error = 0; /* * Attempt to reserve the needed disk blocks by decrementing * the number needed from the number available. This will * fail if the count would go below zero. */ if (blocks > 0) { if (tp->t_mountp->m_sb.sb_fdblocks < blocks) return -ENOSPC; tp->t_blk_res += blocks; } /* * Reserve the log space needed for this transaction. */ if (resp->tr_logres > 0) { ASSERT(tp->t_log_res == 0 || tp->t_log_res == resp->tr_logres); ASSERT(tp->t_log_count == 0 || tp->t_log_count == resp->tr_logcount); if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) tp->t_flags |= XFS_TRANS_PERM_LOG_RES; else ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); tp->t_log_res = resp->tr_logres; tp->t_log_count = resp->tr_logcount; } /* * Attempt to reserve the needed realtime extents by decrementing * the number needed from the number available. This will * fail if the count would go below zero. */ if (rtextents > 0) { if (tp->t_mountp->m_sb.sb_rextents < rtextents) { error = -ENOSPC; goto undo_blocks; } } return 0; /* * Error cases jump to one of these labels to undo any * reservations which have already been performed. */ undo_blocks: if (blocks > 0) tp->t_blk_res = 0; return error; } int libxfs_trans_alloc( struct xfs_mount *mp, struct xfs_trans_res *resp, unsigned int blocks, unsigned int rtextents, unsigned int flags, struct xfs_trans **tpp) { struct xfs_trans *tp; int error; tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); tp->t_mountp = mp; INIT_LIST_HEAD(&tp->t_items); INIT_LIST_HEAD(&tp->t_dfops); tp->t_firstblock = NULLFSBLOCK; error = xfs_trans_reserve(tp, resp, blocks, rtextents); if (error) { xfs_trans_cancel(tp); return error; } trace_xfs_trans_alloc(tp, _RET_IP_); *tpp = tp; return 0; } /* * Create an empty transaction with no reservation. This is a defensive * mechanism for routines that query metadata without actually modifying * them -- if the metadata being queried is somehow cross-linked (think a * btree block pointer that points higher in the tree), we risk deadlock. * However, blocks grabbed as part of a transaction can be re-grabbed. * The verifiers will notice the corrupt block and the operation will fail * back to userspace without deadlocking. * * Note the zero-length reservation; this transaction MUST be cancelled * without any dirty data. */ int libxfs_trans_alloc_empty( struct xfs_mount *mp, struct xfs_trans **tpp) { struct xfs_trans_res resv = {0}; return xfs_trans_alloc(mp, &resv, 0, 0, XFS_TRANS_NO_WRITECOUNT, tpp); } /* * Allocate a transaction that can be rolled. Since userspace doesn't have * a need for log reservations, we really only tr_itruncate to get the * permanent log reservation flag to avoid blowing asserts. */ int libxfs_trans_alloc_rollable( struct xfs_mount *mp, unsigned int blocks, struct xfs_trans **tpp) { return libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, blocks, 0, 0, tpp); } void libxfs_trans_cancel( struct xfs_trans *tp) { trace_xfs_trans_cancel(tp, _RET_IP_); if (tp == NULL) return; if (tp->t_flags & XFS_TRANS_PERM_LOG_RES) xfs_defer_cancel(tp); xfs_trans_free_items(tp); xfs_trans_free(tp); } static void xfs_buf_item_put( struct xfs_buf_log_item *bip) { struct xfs_buf *bp = bip->bli_buf; bp->b_log_item = NULL; kmem_zone_free(xfs_buf_item_zone, bip); } /* from xfs_trans_buf.c */ /* * Add the locked buffer to the transaction. * * The buffer must be locked, and it cannot be associated with any * transaction. * * If the buffer does not yet have a buf log item associated with it, * then allocate one for it. Then add the buf item to the transaction. */ STATIC void _libxfs_trans_bjoin( struct xfs_trans *tp, struct xfs_buf *bp, int reset_recur) { struct xfs_buf_log_item *bip; ASSERT(bp->b_transp == NULL); /* * The xfs_buf_log_item pointer is stored in b_log_item. If * it doesn't have one yet, then allocate one and initialize it. * The checks to see if one is there are in xfs_buf_item_init(). */ xfs_buf_item_init(bp, tp->t_mountp); bip = bp->b_log_item; if (reset_recur) bip->bli_recur = 0; /* * Attach the item to the transaction so we can find it in * xfs_trans_get_buf() and friends. */ xfs_trans_add_item(tp, &bip->bli_item); bp->b_transp = tp; } void libxfs_trans_bjoin( struct xfs_trans *tp, struct xfs_buf *bp) { _libxfs_trans_bjoin(tp, bp, 0); trace_xfs_trans_bjoin(bp->b_log_item); } /* * Cancel the previous buffer hold request made on this buffer * for this transaction. */ void libxfs_trans_bhold_release( xfs_trans_t *tp, xfs_buf_t *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(bp->b_transp == tp); ASSERT(bip != NULL); bip->bli_flags &= ~XFS_BLI_HOLD; trace_xfs_trans_bhold_release(bip); } /* * Get and lock the buffer for the caller if it is not already * locked within the given transaction. If it is already locked * within the transaction, just increment its lock recursion count * and return a pointer to it. * * If the transaction pointer is NULL, make this just a normal * get_buf() call. */ struct xfs_buf * libxfs_trans_get_buf_map( struct xfs_trans *tp, struct xfs_buftarg *target, struct xfs_buf_map *map, int nmaps, xfs_buf_flags_t flags) { xfs_buf_t *bp; struct xfs_buf_log_item *bip; if (!tp) return libxfs_getbuf_map(target, map, nmaps, 0); /* * If we find the buffer in the cache with this transaction * pointer in its b_fsprivate2 field, then we know we already * have it locked. In this case we just increment the lock * recursion count and return the buffer to the caller. */ bp = xfs_trans_buf_item_match(tp, target, map, nmaps); if (bp != NULL) { ASSERT(bp->b_transp == tp); bip = bp->b_log_item; ASSERT(bip != NULL); bip->bli_recur++; trace_xfs_trans_get_buf_recur(bip); return bp; } bp = libxfs_getbuf_map(target, map, nmaps, 0); if (bp == NULL) { return NULL; } ASSERT(!bp->b_error); _libxfs_trans_bjoin(tp, bp, 1); trace_xfs_trans_get_buf(bp->b_log_item); return bp; } xfs_buf_t * libxfs_trans_getsb( xfs_trans_t *tp, struct xfs_mount *mp) { xfs_buf_t *bp; struct xfs_buf_log_item *bip; int len = XFS_FSS_TO_BB(mp, 1); DEFINE_SINGLE_BUF_MAP(map, XFS_SB_DADDR, len); if (tp == NULL) return libxfs_getsb(mp); bp = xfs_trans_buf_item_match(tp, mp->m_dev, &map, 1); if (bp != NULL) { ASSERT(bp->b_transp == tp); bip = bp->b_log_item; ASSERT(bip != NULL); bip->bli_recur++; trace_xfs_trans_getsb_recur(bip); return bp; } bp = libxfs_getsb(mp); if (bp == NULL) return NULL; _libxfs_trans_bjoin(tp, bp, 1); trace_xfs_trans_getsb(bp->b_log_item); return bp; } int libxfs_trans_read_buf_map( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buftarg *target, struct xfs_buf_map *map, int nmaps, xfs_buf_flags_t flags, struct xfs_buf **bpp, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; struct xfs_buf_log_item *bip; int error; *bpp = NULL; if (tp == NULL) { bp = libxfs_readbuf_map(target, map, nmaps, flags, ops); if (!bp) { return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM; } if (bp->b_error) goto out_relse; goto done; } bp = xfs_trans_buf_item_match(tp, target, map, nmaps); if (bp) { ASSERT(bp->b_transp == tp); ASSERT(bp->b_log_item != NULL); bip = bp->b_log_item; bip->bli_recur++; trace_xfs_trans_read_buf_recur(bip); goto done; } bp = libxfs_readbuf_map(target, map, nmaps, flags, ops); if (!bp) { return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM; } if (bp->b_error) goto out_relse; _libxfs_trans_bjoin(tp, bp, 1); done: trace_xfs_trans_read_buf(bp->b_log_item); *bpp = bp; return 0; out_relse: error = bp->b_error; xfs_buf_relse(bp); return error; } /* * Release a buffer previously joined to the transaction. If the buffer is * modified within this transaction, decrement the recursion count but do not * release the buffer even if the count goes to 0. If the buffer is not modified * within the transaction, decrement the recursion count and release the buffer * if the recursion count goes to 0. * * If the buffer is to be released and it was not already dirty before this * transaction began, then also free the buf_log_item associated with it. * * If the transaction pointer is NULL, this is a normal xfs_buf_relse() call. */ void libxfs_trans_brelse( struct xfs_trans *tp, struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(bp->b_transp == tp); if (!tp) { libxfs_putbuf(bp); return; } trace_xfs_trans_brelse(bip); ASSERT(bip->bli_item.li_type == XFS_LI_BUF); /* * If the release is for a recursive lookup, then decrement the count * and return. */ if (bip->bli_recur > 0) { bip->bli_recur--; return; } /* * If the buffer is invalidated or dirty in this transaction, we can't * release it until we commit. */ if (test_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags)) return; if (bip->bli_flags & XFS_BLI_STALE) return; /* * Unlink the log item from the transaction and clear the hold flag, if * set. We wouldn't want the next user of the buffer to get confused. */ xfs_trans_del_item(&bip->bli_item); bip->bli_flags &= ~XFS_BLI_HOLD; /* drop the reference to the bli */ xfs_buf_item_put(bip); bp->b_transp = NULL; libxfs_putbuf(bp); } /* * Mark the buffer as not needing to be unlocked when the buf item's * iop_unlock() routine is called. The buffer must already be locked * and associated with the given transaction. */ /* ARGSUSED */ void libxfs_trans_bhold( xfs_trans_t *tp, xfs_buf_t *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(bp->b_transp == tp); ASSERT(bip != NULL); bip->bli_flags |= XFS_BLI_HOLD; trace_xfs_trans_bhold(bip); } /* * Mark a buffer dirty in the transaction. */ void libxfs_trans_dirty_buf( struct xfs_trans *tp, struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(bp->b_transp == tp); ASSERT(bip != NULL); tp->t_flags |= XFS_TRANS_DIRTY; set_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags); } /* * This is called to mark bytes first through last inclusive of the given * buffer as needing to be logged when the transaction is committed. * The buffer must already be associated with the given transaction. * * First and last are numbers relative to the beginning of this buffer, * so the first byte in the buffer is numbered 0 regardless of the * value of b_blkno. */ void libxfs_trans_log_buf( struct xfs_trans *tp, struct xfs_buf *bp, uint first, uint last) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(first <= last && last < BBTOB(bp->b_length)); xfs_trans_dirty_buf(tp, bp); trace_xfs_trans_log_buf(bip); xfs_buf_item_log(bip, first, last); } void libxfs_trans_binval( xfs_trans_t *tp, xfs_buf_t *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(bp->b_transp == tp); ASSERT(bip != NULL); trace_xfs_trans_binval(bip); if (bip->bli_flags & XFS_BLI_STALE) return; XFS_BUF_UNDELAYWRITE(bp); xfs_buf_stale(bp); bip->bli_flags |= XFS_BLI_STALE; bip->bli_flags &= ~XFS_BLI_DIRTY; bip->__bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; bip->__bli_format.blf_flags |= XFS_BLF_CANCEL; set_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags); tp->t_flags |= XFS_TRANS_DIRTY; } /* * Mark the buffer as being one which contains newly allocated * inodes. We need to make sure that even if this buffer is * relogged as an 'inode buf' we still recover all of the inode * images in the face of a crash. This works in coordination with * xfs_buf_item_committed() to ensure that the buffer remains in the * AIL at its original location even after it has been relogged. */ /* ARGSUSED */ void libxfs_trans_inode_alloc_buf( xfs_trans_t *tp, xfs_buf_t *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; ASSERT(bp->b_transp == tp); ASSERT(bip != NULL); bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); } /* * For userspace, ordered buffers just need to be marked dirty so * the transaction commit will write them and mark them up-to-date. * In essence, they are just like any other logged buffer in userspace. * * If the buffer is already dirty, trigger the "already logged" return condition. */ bool libxfs_trans_ordered_buf( struct xfs_trans *tp, struct xfs_buf *bp) { struct xfs_buf_log_item *bip = bp->b_log_item; bool ret; ret = test_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags); libxfs_trans_log_buf(tp, bp, 0, bp->b_bcount); return ret; } /* end of xfs_trans_buf.c */ /* * Record the indicated change to the given field for application * to the file system's superblock when the transaction commits. * For now, just store the change in the transaction structure. * Mark the transaction structure to indicate that the superblock * needs to be updated before committing. * * Originally derived from xfs_trans_mod_sb(). */ void libxfs_trans_mod_sb( xfs_trans_t *tp, uint field, long delta) { switch (field) { case XFS_TRANS_SB_RES_FDBLOCKS: return; case XFS_TRANS_SB_FDBLOCKS: if (delta < 0) { tp->t_blk_res_used += (uint)-delta; if (tp->t_blk_res_used > tp->t_blk_res) { fprintf(stderr, _("Transaction block reservation exceeded! %u > %u\n"), tp->t_blk_res_used, tp->t_blk_res); ASSERT(0); } } tp->t_fdblocks_delta += delta; break; case XFS_TRANS_SB_ICOUNT: ASSERT(delta > 0); tp->t_icount_delta += delta; break; case XFS_TRANS_SB_IFREE: tp->t_ifree_delta += delta; break; case XFS_TRANS_SB_FREXTENTS: tp->t_frextents_delta += delta; break; default: ASSERT(0); return; } tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); } static void xfs_inode_item_put( struct xfs_inode_log_item *iip) { struct xfs_inode *ip = iip->ili_inode; ip->i_itemp = NULL; kmem_zone_free(xfs_ili_zone, iip); } /* * Transaction commital code follows (i.e. write to disk in libxfs) * * XXX (dgc): should failure to flush the inode (e.g. due to uncorrected * corruption) result in transaction commit failure w/ EFSCORRUPTED? */ static void inode_item_done( xfs_inode_log_item_t *iip) { xfs_dinode_t *dip; xfs_inode_t *ip; xfs_mount_t *mp; xfs_buf_t *bp; int error; ip = iip->ili_inode; mp = iip->ili_item.li_mountp; ASSERT(ip != NULL); if (!(iip->ili_fields & XFS_ILOG_ALL)) goto free; /* * Get the buffer containing the on-disk inode. */ error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, 0, 0); if (error) { fprintf(stderr, _("%s: warning - imap_to_bp failed (%d)\n"), progname, error); goto free; } /* * Flush the inode and disassociate it from the transaction regardless * of whether the flush succeed or not. If we fail the flush, make sure * we still release the buffer reference we currently hold. */ error = libxfs_iflush_int(ip, bp); bp->b_transp = NULL; /* remove xact ptr */ if (error) { fprintf(stderr, _("%s: warning - iflush_int failed (%d)\n"), progname, error); libxfs_putbuf(bp); goto free; } libxfs_writebuf(bp, 0); free: xfs_inode_item_put(iip); } static void buf_item_done( xfs_buf_log_item_t *bip) { xfs_buf_t *bp; int hold; extern kmem_zone_t *xfs_buf_item_zone; bp = bip->bli_buf; ASSERT(bp != NULL); bp->b_transp = NULL; /* remove xact ptr */ hold = (bip->bli_flags & XFS_BLI_HOLD); if (bip->bli_flags & XFS_BLI_DIRTY) libxfs_writebuf_int(bp, 0); bip->bli_flags &= ~XFS_BLI_HOLD; xfs_buf_item_put(bip); if (hold) return; libxfs_putbuf(bp); } static void trans_committed( xfs_trans_t *tp) { struct xfs_log_item *lip, *next; list_for_each_entry_safe(lip, next, &tp->t_items, li_trans) { xfs_trans_del_item(lip); if (lip->li_type == XFS_LI_BUF) buf_item_done((xfs_buf_log_item_t *)lip); else if (lip->li_type == XFS_LI_INODE) inode_item_done((xfs_inode_log_item_t *)lip); else { fprintf(stderr, _("%s: unrecognised log item type\n"), progname); ASSERT(0); } } } static void buf_item_unlock( xfs_buf_log_item_t *bip) { xfs_buf_t *bp = bip->bli_buf; uint hold; /* Clear the buffer's association with this transaction. */ bip->bli_buf->b_transp = NULL; hold = bip->bli_flags & XFS_BLI_HOLD; bip->bli_flags &= ~XFS_BLI_HOLD; xfs_buf_item_put(bip); if (!hold) libxfs_putbuf(bp); } static void inode_item_unlock( xfs_inode_log_item_t *iip) { xfs_inode_item_put(iip); } /* Detach and unlock all of the items in a transaction */ static void xfs_trans_free_items( struct xfs_trans *tp) { struct xfs_log_item *lip, *next; list_for_each_entry_safe(lip, next, &tp->t_items, li_trans) { xfs_trans_del_item(lip); if (lip->li_type == XFS_LI_BUF) buf_item_unlock((xfs_buf_log_item_t *)lip); else if (lip->li_type == XFS_LI_INODE) inode_item_unlock((xfs_inode_log_item_t *)lip); else { fprintf(stderr, _("%s: unrecognised log item type\n"), progname); ASSERT(0); } } } /* * Commit the changes represented by this transaction */ static int __xfs_trans_commit( struct xfs_trans *tp, bool regrant) { struct xfs_sb *sbp; int error = 0; trace_xfs_trans_commit(tp, _RET_IP_); if (tp == NULL) return 0; /* * Finish deferred items on final commit. Only permanent transactions * should ever have deferred ops. */ WARN_ON_ONCE(!list_empty(&tp->t_dfops) && !(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); if (!regrant && (tp->t_flags & XFS_TRANS_PERM_LOG_RES)) { error = xfs_defer_finish_noroll(&tp); if (error) goto out_unreserve; } if (!(tp->t_flags & XFS_TRANS_DIRTY)) goto out_unreserve; if (tp->t_flags & XFS_TRANS_SB_DIRTY) { sbp = &(tp->t_mountp->m_sb); if (tp->t_icount_delta) sbp->sb_icount += tp->t_icount_delta; if (tp->t_ifree_delta) sbp->sb_ifree += tp->t_ifree_delta; if (tp->t_fdblocks_delta) sbp->sb_fdblocks += tp->t_fdblocks_delta; if (tp->t_frextents_delta) sbp->sb_frextents += tp->t_frextents_delta; xfs_log_sb(tp); } trans_committed(tp); /* That's it for the transaction structure. Free it. */ xfs_trans_free(tp); return 0; out_unreserve: xfs_trans_free_items(tp); xfs_trans_free(tp); return error; } int libxfs_trans_commit( struct xfs_trans *tp) { return __xfs_trans_commit(tp, false); } xfsprogs-5.3.0/libxfs/util.c0000644000175000017500000004625313570057155015676 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "libxfs.h" #include "libxfs_io.h" #include "init.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_trans_space.h" #include "xfs_ialloc.h" #include "xfs_alloc.h" #include "xfs_bit.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2_priv.h" /* * Calculate the worst case log unit reservation for a given superblock * configuration. Copied and munged from the kernel code, and assumes a * worse case header usage (maximum log buffer sizes) */ int xfs_log_calc_unit_res( struct xfs_mount *mp, int unit_bytes) { int iclog_space; int iclog_header_size; int iclog_size; uint num_headers; if (xfs_sb_version_haslogv2(&mp->m_sb)) { iclog_size = XLOG_MAX_RECORD_BSIZE; iclog_header_size = BBTOB(iclog_size / XLOG_HEADER_CYCLE_SIZE); } else { iclog_size = XLOG_BIG_RECORD_BSIZE; iclog_header_size = BBSIZE; } /* * Permanent reservations have up to 'cnt'-1 active log operations * in the log. A unit in this case is the amount of space for one * of these log operations. Normal reservations have a cnt of 1 * and their unit amount is the total amount of space required. * * The following lines of code account for non-transaction data * which occupy space in the on-disk log. * * Normal form of a transaction is: * ... * and then there are LR hdrs, split-recs and roundoff at end of syncs. * * We need to account for all the leadup data and trailer data * around the transaction data. * And then we need to account for the worst case in terms of using * more space. * The worst case will happen if: * - the placement of the transaction happens to be such that the * roundoff is at its maximum * - the transaction data is synced before the commit record is synced * i.e. | * Therefore the commit record is in its own Log Record. * This can happen as the commit record is called with its * own region to xlog_write(). * This then means that in the worst case, roundoff can happen for * the commit-rec as well. * The commit-rec is smaller than padding in this scenario and so it is * not added separately. */ /* for trans header */ unit_bytes += sizeof(xlog_op_header_t); unit_bytes += sizeof(xfs_trans_header_t); /* for start-rec */ unit_bytes += sizeof(xlog_op_header_t); /* * for LR headers - the space for data in an iclog is the size minus * the space used for the headers. If we use the iclog size, then we * undercalculate the number of headers required. * * Furthermore - the addition of op headers for split-recs might * increase the space required enough to require more log and op * headers, so take that into account too. * * IMPORTANT: This reservation makes the assumption that if this * transaction is the first in an iclog and hence has the LR headers * accounted to it, then the remaining space in the iclog is * exclusively for this transaction. i.e. if the transaction is larger * than the iclog, it will be the only thing in that iclog. * Fundamentally, this means we must pass the entire log vector to * xlog_write to guarantee this. */ iclog_space = iclog_size - iclog_header_size; num_headers = howmany(unit_bytes, iclog_space); /* for split-recs - ophdrs added when data split over LRs */ unit_bytes += sizeof(xlog_op_header_t) * num_headers; /* add extra header reservations if we overrun */ while (!num_headers || howmany(unit_bytes, iclog_space) > num_headers) { unit_bytes += sizeof(xlog_op_header_t); num_headers++; } unit_bytes += iclog_header_size * num_headers; /* for commit-rec LR header - note: padding will subsume the ophdr */ unit_bytes += iclog_header_size; /* for roundoff padding for transaction data and one for commit record */ if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) { /* log su roundoff */ unit_bytes += 2 * mp->m_sb.sb_logsunit; } else { /* BB roundoff */ unit_bytes += 2 * BBSIZE; } return unit_bytes; } struct timespec64 current_time(struct inode *inode) { struct timespec64 tv; struct timeval stv; gettimeofday(&stv, (struct timezone *)0); tv.tv_sec = stv.tv_sec; tv.tv_nsec = stv.tv_usec * 1000; return tv; } STATIC uint16_t xfs_flags2diflags( struct xfs_inode *ip, unsigned int xflags) { /* can't set PREALLOC this way, just preserve it */ uint16_t di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); if (xflags & FS_XFLAG_IMMUTABLE) di_flags |= XFS_DIFLAG_IMMUTABLE; if (xflags & FS_XFLAG_APPEND) di_flags |= XFS_DIFLAG_APPEND; if (xflags & FS_XFLAG_SYNC) di_flags |= XFS_DIFLAG_SYNC; if (xflags & FS_XFLAG_NOATIME) di_flags |= XFS_DIFLAG_NOATIME; if (xflags & FS_XFLAG_NODUMP) di_flags |= XFS_DIFLAG_NODUMP; if (xflags & FS_XFLAG_NODEFRAG) di_flags |= XFS_DIFLAG_NODEFRAG; if (xflags & FS_XFLAG_FILESTREAM) di_flags |= XFS_DIFLAG_FILESTREAM; if (S_ISDIR(VFS_I(ip)->i_mode)) { if (xflags & FS_XFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (xflags & FS_XFLAG_NOSYMLINKS) di_flags |= XFS_DIFLAG_NOSYMLINKS; if (xflags & FS_XFLAG_EXTSZINHERIT) di_flags |= XFS_DIFLAG_EXTSZINHERIT; if (xflags & FS_XFLAG_PROJINHERIT) di_flags |= XFS_DIFLAG_PROJINHERIT; } else if (S_ISREG(VFS_I(ip)->i_mode)) { if (xflags & FS_XFLAG_REALTIME) di_flags |= XFS_DIFLAG_REALTIME; if (xflags & FS_XFLAG_EXTSIZE) di_flags |= XFS_DIFLAG_EXTSIZE; } return di_flags; } STATIC uint64_t xfs_flags2diflags2( struct xfs_inode *ip, unsigned int xflags) { uint64_t di_flags2 = (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK); if (xflags & FS_XFLAG_DAX) di_flags2 |= XFS_DIFLAG2_DAX; if (xflags & FS_XFLAG_COWEXTSIZE) di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; return di_flags2; } /* * Allocate an inode on disk and return a copy of its in-core version. * Set mode, nlink, and rdev appropriately within the inode. * The uid and gid for the inode are set according to the contents of * the given cred structure. * * This was once shared with the kernel, but has diverged to the point * where it's no longer worth the hassle of maintaining common code. */ static int libxfs_ialloc( xfs_trans_t *tp, xfs_inode_t *pip, mode_t mode, nlink_t nlink, xfs_dev_t rdev, struct cred *cr, struct fsxattr *fsx, xfs_buf_t **ialloc_context, xfs_inode_t **ipp) { xfs_ino_t ino; xfs_inode_t *ip; uint flags; int error; /* * Call the space management code to pick * the on-disk inode to be allocated. */ error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, ialloc_context, &ino); if (error != 0) return error; if (*ialloc_context || ino == NULLFSINO) { *ipp = NULL; return 0; } ASSERT(*ialloc_context == NULL); error = libxfs_iget(tp->t_mountp, tp, ino, 0, &ip, &xfs_default_ifork_ops); if (error != 0) return error; ASSERT(ip != NULL); VFS_I(ip)->i_mode = mode; set_nlink(VFS_I(ip), nlink); ip->i_d.di_uid = cr->cr_uid; ip->i_d.di_gid = cr->cr_gid; xfs_set_projid(&ip->i_d, pip ? 0 : fsx->fsx_projid); xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD); /* * We only support filesystems that understand v2 format inodes. So if * this is currently an old format inode, then change the inode version * number now. This way we only do the conversion here rather than here * and in the flush/logging code. */ if (ip->i_d.di_version == 1) { ip->i_d.di_version = 2; /* * old link count, projid_lo/hi field, pad field * already zeroed */ } if (pip && (VFS_I(pip)->i_mode & S_ISGID)) { ip->i_d.di_gid = pip->i_d.di_gid; if ((VFS_I(pip)->i_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) VFS_I(ip)->i_mode |= S_ISGID; } ip->i_d.di_size = 0; ip->i_d.di_nextents = 0; ASSERT(ip->i_d.di_nblocks == 0); ip->i_d.di_extsize = pip ? 0 : fsx->fsx_extsize; ip->i_d.di_dmevmask = 0; ip->i_d.di_dmstate = 0; ip->i_d.di_flags = pip ? 0 : xfs_flags2diflags(ip, fsx->fsx_xflags); if (ip->i_d.di_version == 3) { ASSERT(ip->i_d.di_ino == ino); ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid)); VFS_I(ip)->i_version = 1; ip->i_d.di_flags2 = pip ? 0 : xfs_flags2diflags2(ip, fsx->fsx_xflags); ip->i_d.di_crtime.t_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec; ip->i_d.di_crtime.t_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec; ip->i_d.di_cowextsize = pip ? 0 : fsx->fsx_cowextsize; } flags = XFS_ILOG_CORE; switch (mode & S_IFMT) { case S_IFIFO: case S_IFSOCK: /* doesn't make sense to set an rdev for these */ rdev = 0; /* FALLTHROUGH */ case S_IFCHR: case S_IFBLK: ip->i_d.di_format = XFS_DINODE_FMT_DEV; flags |= XFS_ILOG_DEV; VFS_I(ip)->i_rdev = rdev; break; case S_IFREG: case S_IFDIR: if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { uint di_flags = 0; if ((mode & S_IFMT) == S_IFDIR) { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSZINHERIT; ip->i_d.di_extsize = pip->i_d.di_extsize; } } else { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { di_flags |= XFS_DIFLAG_REALTIME; } if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSIZE; ip->i_d.di_extsize = pip->i_d.di_extsize; } } if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) di_flags |= XFS_DIFLAG_PROJINHERIT; ip->i_d.di_flags |= di_flags; } /* FALLTHROUGH */ case S_IFLNK: ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_bytes = 0; ip->i_df.if_u1.if_root = NULL; break; default: ASSERT(0); } /* Attribute fork settings for new inode. */ ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_anextents = 0; /* * set up the inode ops structure that the libxfs code relies on */ if (XFS_ISDIR(ip)) ip->d_ops = ip->i_mount->m_dir_inode_ops; else ip->d_ops = ip->i_mount->m_nondir_inode_ops; /* * Log the new values stuffed into the inode. */ xfs_trans_ijoin(tp, ip, 0); xfs_trans_log_inode(tp, ip, flags); *ipp = ip; return 0; } /* * Writes a modified inode's changes out to the inode's on disk home. * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel. */ int libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) { xfs_inode_log_item_t *iip; xfs_dinode_t *dip; xfs_mount_t *mp; ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || ip->i_d.di_nextents > ip->i_df.if_ext_max); ASSERT(ip->i_d.di_version > 1); iip = ip->i_itemp; mp = ip->i_mount; /* set *dip = inode's place in the buffer */ dip = xfs_buf_offset(bp, ip->i_imap.im_boffset); ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC); if (XFS_ISREG(ip)) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ); } else if (XFS_ISDIR(ip)) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) || (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) ); } ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks); ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize); /* bump the change count on v3 inodes */ if (ip->i_d.di_version == 3) VFS_I(ip)->i_version++; /* Check the inline fork data before we write out. */ if (!libxfs_inode_verify_forks(ip)) return -EFSCORRUPTED; /* * Copy the dirty parts of the inode into the on-disk * inode. We always copy out the core of the inode, * because if the inode is dirty at all the core must * be. */ xfs_inode_to_disk(ip, dip, iip->ili_item.li_lsn); xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK); if (XFS_IFORK_Q(ip)) xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK); /* generate the checksum. */ xfs_dinode_calc_crc(mp, dip); return 0; } int libxfs_mod_incore_sb( struct xfs_mount *mp, int field, int64_t delta, int rsvd) { long long lcounter; /* long counter for 64 bit fields */ switch (field) { case XFS_TRANS_SB_FDBLOCKS: lcounter = (long long)mp->m_sb.sb_fdblocks; lcounter += delta; if (lcounter < 0) return -ENOSPC; mp->m_sb.sb_fdblocks = lcounter; return 0; default: ASSERT(0); return -EINVAL; } } /* * This routine allocates disk space for the given file. * Originally derived from xfs_alloc_file_space(). */ int libxfs_alloc_file_space( xfs_inode_t *ip, xfs_off_t offset, xfs_off_t len, int alloc_type, int attr_flags) { xfs_mount_t *mp; xfs_off_t count; xfs_filblks_t datablocks; xfs_filblks_t allocated_fsb; xfs_filblks_t allocatesize_fsb; xfs_bmbt_irec_t *imapp; xfs_bmbt_irec_t imaps[1]; int reccount; uint resblks; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; int xfs_bmapi_flags; int error; if (len <= 0) return -EINVAL; count = len; error = 0; imapp = &imaps[0]; reccount = 1; xfs_bmapi_flags = alloc_type ? XFS_BMAPI_PREALLOC : 0; mp = ip->i_mount; startoffset_fsb = XFS_B_TO_FSBT(mp, offset); allocatesize_fsb = XFS_B_TO_FSB(mp, count); /* allocate file space until done or until there is an error */ while (allocatesize_fsb && !error) { datablocks = allocatesize_fsb; resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks); error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); /* * Check for running out of space */ if (error) { ASSERT(error == -ENOSPC); break; } xfs_trans_ijoin(tp, ip, 0); error = xfs_bmapi_write(tp, ip, startoffset_fsb, allocatesize_fsb, xfs_bmapi_flags, 0, imapp, &reccount); if (error) goto error0; /* * Complete the transaction */ error = xfs_trans_commit(tp); if (error) break; allocated_fsb = imapp->br_blockcount; if (reccount == 0) return -ENOSPC; startoffset_fsb += allocated_fsb; allocatesize_fsb -= allocated_fsb; } return error; error0: /* Cancel bmap, cancel trans */ xfs_trans_cancel(tp); return error; } /* * Wrapper around call to libxfs_ialloc. Takes care of committing and * allocating a new transaction as needed. * * Originally there were two copies of this code - one in mkfs, the * other in repair - now there is just the one. */ int libxfs_inode_alloc( xfs_trans_t **tp, xfs_inode_t *pip, mode_t mode, nlink_t nlink, xfs_dev_t rdev, struct cred *cr, struct fsxattr *fsx, xfs_inode_t **ipp) { xfs_buf_t *ialloc_context; xfs_inode_t *ip; int error; ialloc_context = (xfs_buf_t *)0; error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx, &ialloc_context, &ip); if (error) { *ipp = NULL; return error; } if (!ialloc_context && !ip) { *ipp = NULL; return -ENOSPC; } if (ialloc_context) { xfs_trans_bhold(*tp, ialloc_context); error = xfs_trans_roll(tp); if (error) { fprintf(stderr, _("%s: cannot duplicate transaction: %s\n"), progname, strerror(error)); exit(1); } xfs_trans_bjoin(*tp, ialloc_context); error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx, &ialloc_context, &ip); if (!ip) error = -ENOSPC; if (error) return error; } *ipp = ip; return error; } void cmn_err(int level, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); } /* * Warnings specifically for verifier errors. Differentiate CRC vs. invalid * values, and omit the stack trace unless the error level is tuned high. */ void xfs_verifier_error( struct xfs_buf *bp, int error, xfs_failaddr_t failaddr) { xfs_buf_ioerror(bp, error); xfs_alert(NULL, "Metadata %s detected at %p, %s block 0x%llx/0x%x", bp->b_error == -EFSBADCRC ? "CRC error" : "corruption", failaddr ? failaddr : __return_address, bp->b_ops->name, bp->b_bn, BBTOB(bp->b_length)); } /* * Warnings for inode corruption problems. Don't bother with the stack * trace unless the error level is turned up high. */ void xfs_inode_verifier_error( struct xfs_inode *ip, int error, const char *name, void *buf, size_t bufsz, xfs_failaddr_t failaddr) { xfs_alert(NULL, "Metadata %s detected at %p, inode 0x%llx %s", error == -EFSBADCRC ? "CRC error" : "corruption", failaddr ? failaddr : __return_address, ip->i_ino, name); } /* * This is called from I/O verifiers on v5 superblock filesystems. In the * kernel, it validates the metadata LSN parameter against the current LSN of * the active log. We don't have an active log in userspace so this kind of * validation is not required. Therefore, this function always returns true in * userspace. * * xfs_repair piggybacks off this mechanism to help track the largest metadata * LSN in use on a filesystem. Keep a record of the largest LSN seen such that * repair can validate it against the state of the log. */ xfs_lsn_t libxfs_max_lsn = 0; static pthread_mutex_t libxfs_max_lsn_lock = PTHREAD_MUTEX_INITIALIZER; bool xfs_log_check_lsn( struct xfs_mount *mp, xfs_lsn_t lsn) { int cycle = CYCLE_LSN(lsn); int block = BLOCK_LSN(lsn); int max_cycle; int max_block; if (lsn == NULLCOMMITLSN) return true; pthread_mutex_lock(&libxfs_max_lsn_lock); max_cycle = CYCLE_LSN(libxfs_max_lsn); max_block = BLOCK_LSN(libxfs_max_lsn); if ((cycle > max_cycle) || (cycle == max_cycle && block > max_block)) libxfs_max_lsn = lsn; pthread_mutex_unlock(&libxfs_max_lsn_lock); return true; } void xfs_log_item_init( struct xfs_mount *mp, struct xfs_log_item *item, int type) { item->li_mountp = mp; item->li_type = type; INIT_LIST_HEAD(&item->li_trans); } static struct xfs_buftarg * xfs_find_bdev_for_inode( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; if (XFS_IS_REALTIME_INODE(ip)) return mp->m_rtdev_targp; return mp->m_ddev_targp; } static xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) { if (XFS_IS_REALTIME_INODE(ip)) return XFS_FSB_TO_BB(ip->i_mount, fsb); return XFS_FSB_TO_DADDR(ip->i_mount, (fsb)); } int libxfs_zero_extent( struct xfs_inode *ip, xfs_fsblock_t start_fsb, xfs_off_t count_fsb) { xfs_daddr_t sector = xfs_fsb_to_db(ip, start_fsb); ssize_t size = XFS_FSB_TO_BB(ip->i_mount, count_fsb); return libxfs_device_zero(xfs_find_bdev_for_inode(ip), sector, size); } unsigned int hweight8(unsigned int w) { unsigned int res = w - ((w >> 1) & 0x55); res = (res & 0x33) + ((res >> 2) & 0x33); return (res + (res >> 4)) & 0x0F; } unsigned int hweight32(unsigned int w) { unsigned int res = w - ((w >> 1) & 0x55555555); res = (res & 0x33333333) + ((res >> 2) & 0x33333333); res = (res + (res >> 4)) & 0x0F0F0F0F; res = res + (res >> 8); return (res + (res >> 16)) & 0x000000FF; } unsigned int hweight64(__u64 w) { return hweight32((unsigned int)w) + hweight32((unsigned int)(w >> 32)); } /* xfs_health.c */ /* Mark a per-fs metadata healed. */ void xfs_fs_mark_healthy( struct xfs_mount *mp, unsigned int mask) { ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY)); trace_xfs_fs_mark_healthy(mp, mask); spin_lock(&mp->m_sb_lock); mp->m_fs_sick &= ~mask; mp->m_fs_checked |= mask; spin_unlock(&mp->m_sb_lock); } void xfs_ag_geom_health(struct xfs_perag *pag, struct xfs_ag_geometry *ageo) { } xfsprogs-5.3.0/libxfs/xfs_ag.c0000644000175000017500000003671413570057155016171 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2018 Red Hat, Inc. * All rights reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_btree.h" #include "xfs_alloc_btree.h" #include "xfs_rmap_btree.h" #include "xfs_alloc.h" #include "xfs_ialloc.h" #include "xfs_rmap.h" #include "xfs_ag.h" #include "xfs_ag_resv.h" #include "xfs_health.h" static struct xfs_buf * xfs_get_aghdr_buf( struct xfs_mount *mp, xfs_daddr_t blkno, size_t numblks, int flags, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags); if (!bp) return NULL; xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); bp->b_bn = blkno; bp->b_maps[0].bm_bn = blkno; bp->b_ops = ops; return bp; } static inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id) { return mp->m_sb.sb_logstart > 0 && id->agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart); } /* * Generic btree root block init function */ static void xfs_btroot_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno); } /* Finish initializing a free space btree. */ static void xfs_freesp_init_recs( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_alloc_rec *arec; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); if (is_log_ag(mp, id)) { struct xfs_alloc_rec *nrec; xfs_agblock_t start = XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart); ASSERT(start >= mp->m_ag_prealloc_blocks); if (start != mp->m_ag_prealloc_blocks) { /* * Modify first record to pad stripe align of log */ arec->ar_blockcount = cpu_to_be32(start - mp->m_ag_prealloc_blocks); nrec = arec + 1; /* * Insert second record at start of internal log * which then gets trimmed. */ nrec->ar_startblock = cpu_to_be32( be32_to_cpu(arec->ar_startblock) + be32_to_cpu(arec->ar_blockcount)); arec = nrec; be16_add_cpu(&block->bb_numrecs, 1); } /* * Change record start to after the internal log */ be32_add_cpu(&arec->ar_startblock, mp->m_sb.sb_logblocks); } /* * Calculate the record block count and check for the case where * the log might have consumed all available space in the AG. If * so, reset the record count to 0 to avoid exposure of an invalid * record start block. */ arec->ar_blockcount = cpu_to_be32(id->agsize - be32_to_cpu(arec->ar_startblock)); if (!arec->ar_blockcount) block->bb_numrecs = 0; } /* * Alloc btree root block init functions */ static void xfs_bnoroot_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno); xfs_freesp_init_recs(mp, bp, id); } static void xfs_cntroot_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno); xfs_freesp_init_recs(mp, bp, id); } /* * Reverse map root block init */ static void xfs_rmaproot_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_rmap_rec *rrec; xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno); /* * mark the AG header regions as static metadata The BNO * btree block is the first block after the headers, so * it's location defines the size of region the static * metadata consumes. * * Note: unlike mkfs, we never have to account for log * space when growing the data regions */ rrec = XFS_RMAP_REC_ADDR(block, 1); rrec->rm_startblock = 0; rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp)); rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS); rrec->rm_offset = 0; /* account freespace btree root blocks */ rrec = XFS_RMAP_REC_ADDR(block, 2); rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp)); rrec->rm_blockcount = cpu_to_be32(2); rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); rrec->rm_offset = 0; /* account inode btree root blocks */ rrec = XFS_RMAP_REC_ADDR(block, 3); rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp)); rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) - XFS_IBT_BLOCK(mp)); rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT); rrec->rm_offset = 0; /* account for rmap btree root */ rrec = XFS_RMAP_REC_ADDR(block, 4); rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp)); rrec->rm_blockcount = cpu_to_be32(1); rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); rrec->rm_offset = 0; /* account for refc btree root */ if (xfs_sb_version_hasreflink(&mp->m_sb)) { rrec = XFS_RMAP_REC_ADDR(block, 5); rrec->rm_startblock = cpu_to_be32(xfs_refc_block(mp)); rrec->rm_blockcount = cpu_to_be32(1); rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC); rrec->rm_offset = 0; be16_add_cpu(&block->bb_numrecs, 1); } /* account for the log space */ if (is_log_ag(mp, id)) { rrec = XFS_RMAP_REC_ADDR(block, be16_to_cpu(block->bb_numrecs) + 1); rrec->rm_startblock = cpu_to_be32( XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart)); rrec->rm_blockcount = cpu_to_be32(mp->m_sb.sb_logblocks); rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG); rrec->rm_offset = 0; be16_add_cpu(&block->bb_numrecs, 1); } } /* * Initialise new secondary superblocks with the pre-grow geometry, but mark * them as "in progress" so we know they haven't yet been activated. This will * get cleared when the update with the new geometry information is done after * changes to the primary are committed. This isn't strictly necessary, but we * get it for free with the delayed buffer write lists and it means we can tell * if a grow operation didn't complete properly after the fact. */ static void xfs_sbblock_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); xfs_sb_to_disk(dsb, &mp->m_sb); dsb->sb_inprogress = 1; } static void xfs_agfblock_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); xfs_extlen_t tmpsize; agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); agf->agf_seqno = cpu_to_be32(id->agno); agf->agf_length = cpu_to_be32(id->agsize); agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp)); agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp)); agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1); agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1); if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { agf->agf_roots[XFS_BTNUM_RMAPi] = cpu_to_be32(XFS_RMAP_BLOCK(mp)); agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1); agf->agf_rmap_blocks = cpu_to_be32(1); } agf->agf_flfirst = cpu_to_be32(1); agf->agf_fllast = 0; agf->agf_flcount = 0; tmpsize = id->agsize - mp->m_ag_prealloc_blocks; agf->agf_freeblks = cpu_to_be32(tmpsize); agf->agf_longest = cpu_to_be32(tmpsize); if (xfs_sb_version_hascrc(&mp->m_sb)) uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); if (xfs_sb_version_hasreflink(&mp->m_sb)) { agf->agf_refcount_root = cpu_to_be32( xfs_refc_block(mp)); agf->agf_refcount_level = cpu_to_be32(1); agf->agf_refcount_blocks = cpu_to_be32(1); } if (is_log_ag(mp, id)) { int64_t logblocks = mp->m_sb.sb_logblocks; be32_add_cpu(&agf->agf_freeblks, -logblocks); agf->agf_longest = cpu_to_be32(id->agsize - XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart) - logblocks); } } static void xfs_agflblock_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp); __be32 *agfl_bno; int bucket; if (xfs_sb_version_hascrc(&mp->m_sb)) { agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); agfl->agfl_seqno = cpu_to_be32(id->agno); uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); } agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp); for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++) agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); } static void xfs_agiblock_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); int bucket; agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); agi->agi_seqno = cpu_to_be32(id->agno); agi->agi_length = cpu_to_be32(id->agsize); agi->agi_count = 0; agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp)); agi->agi_level = cpu_to_be32(1); agi->agi_freecount = 0; agi->agi_newino = cpu_to_be32(NULLAGINO); agi->agi_dirino = cpu_to_be32(NULLAGINO); if (xfs_sb_version_hascrc(&mp->m_sb)) uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); if (xfs_sb_version_hasfinobt(&mp->m_sb)) { agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); agi->agi_free_level = cpu_to_be32(1); } for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); } typedef void (*aghdr_init_work_f)(struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id); static int xfs_ag_init_hdr( struct xfs_mount *mp, struct aghdr_init_data *id, aghdr_init_work_f work, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; bp = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, 0, ops); if (!bp) return -ENOMEM; (*work)(mp, bp, id); xfs_buf_delwri_queue(bp, &id->buffer_list); xfs_buf_relse(bp); return 0; } struct xfs_aghdr_grow_data { xfs_daddr_t daddr; size_t numblks; const struct xfs_buf_ops *ops; aghdr_init_work_f work; xfs_btnum_t type; bool need_init; }; /* * Prepare new AG headers to be written to disk. We use uncached buffers here, * as it is assumed these new AG headers are currently beyond the currently * valid filesystem address space. Using cached buffers would trip over EOFS * corruption detection alogrithms in the buffer cache lookup routines. * * This is a non-transactional function, but the prepared buffers are added to a * delayed write buffer list supplied by the caller so they can submit them to * disk and wait on them as required. */ int xfs_ag_init_headers( struct xfs_mount *mp, struct aghdr_init_data *id) { struct xfs_aghdr_grow_data aghdr_data[] = { { /* SB */ .daddr = XFS_AG_DADDR(mp, id->agno, XFS_SB_DADDR), .numblks = XFS_FSS_TO_BB(mp, 1), .ops = &xfs_sb_buf_ops, .work = &xfs_sbblock_init, .need_init = true }, { /* AGF */ .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGF_DADDR(mp)), .numblks = XFS_FSS_TO_BB(mp, 1), .ops = &xfs_agf_buf_ops, .work = &xfs_agfblock_init, .need_init = true }, { /* AGFL */ .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGFL_DADDR(mp)), .numblks = XFS_FSS_TO_BB(mp, 1), .ops = &xfs_agfl_buf_ops, .work = &xfs_agflblock_init, .need_init = true }, { /* AGI */ .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGI_DADDR(mp)), .numblks = XFS_FSS_TO_BB(mp, 1), .ops = &xfs_agi_buf_ops, .work = &xfs_agiblock_init, .need_init = true }, { /* BNO root block */ .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_BNO_BLOCK(mp)), .numblks = BTOBB(mp->m_sb.sb_blocksize), .ops = &xfs_bnobt_buf_ops, .work = &xfs_bnoroot_init, .need_init = true }, { /* CNT root block */ .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_CNT_BLOCK(mp)), .numblks = BTOBB(mp->m_sb.sb_blocksize), .ops = &xfs_cntbt_buf_ops, .work = &xfs_cntroot_init, .need_init = true }, { /* INO root block */ .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_IBT_BLOCK(mp)), .numblks = BTOBB(mp->m_sb.sb_blocksize), .ops = &xfs_inobt_buf_ops, .work = &xfs_btroot_init, .type = XFS_BTNUM_INO, .need_init = true }, { /* FINO root block */ .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_FIBT_BLOCK(mp)), .numblks = BTOBB(mp->m_sb.sb_blocksize), .ops = &xfs_finobt_buf_ops, .work = &xfs_btroot_init, .type = XFS_BTNUM_FINO, .need_init = xfs_sb_version_hasfinobt(&mp->m_sb) }, { /* RMAP root block */ .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_RMAP_BLOCK(mp)), .numblks = BTOBB(mp->m_sb.sb_blocksize), .ops = &xfs_rmapbt_buf_ops, .work = &xfs_rmaproot_init, .need_init = xfs_sb_version_hasrmapbt(&mp->m_sb) }, { /* REFC root block */ .daddr = XFS_AGB_TO_DADDR(mp, id->agno, xfs_refc_block(mp)), .numblks = BTOBB(mp->m_sb.sb_blocksize), .ops = &xfs_refcountbt_buf_ops, .work = &xfs_btroot_init, .type = XFS_BTNUM_REFC, .need_init = xfs_sb_version_hasreflink(&mp->m_sb) }, { /* NULL terminating block */ .daddr = XFS_BUF_DADDR_NULL, } }; struct xfs_aghdr_grow_data *dp; int error = 0; /* Account for AG free space in new AG */ id->nfree += id->agsize - mp->m_ag_prealloc_blocks; for (dp = &aghdr_data[0]; dp->daddr != XFS_BUF_DADDR_NULL; dp++) { if (!dp->need_init) continue; id->daddr = dp->daddr; id->numblks = dp->numblks; id->type = dp->type; error = xfs_ag_init_hdr(mp, id, dp->work, dp->ops); if (error) break; } return error; } /* * Extent the AG indicated by the @id by the length passed in */ int xfs_ag_extend_space( struct xfs_mount *mp, struct xfs_trans *tp, struct aghdr_init_data *id, xfs_extlen_t len) { struct xfs_buf *bp; struct xfs_agi *agi; struct xfs_agf *agf; int error; /* * Change the agi length. */ error = xfs_ialloc_read_agi(mp, tp, id->agno, &bp); if (error) return error; agi = XFS_BUF_TO_AGI(bp); be32_add_cpu(&agi->agi_length, len); ASSERT(id->agno == mp->m_sb.sb_agcount - 1 || be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks); xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); /* * Change agf length. */ error = xfs_alloc_read_agf(mp, tp, id->agno, 0, &bp); if (error) return error; agf = XFS_BUF_TO_AGF(bp); be32_add_cpu(&agf->agf_length, len); ASSERT(agf->agf_length == agi->agi_length); xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH); /* * Free the new space. * * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that * this doesn't actually exist in the rmap btree. */ error = xfs_rmap_free(tp, bp, id->agno, be32_to_cpu(agf->agf_length) - len, len, &XFS_RMAP_OINFO_SKIP_UPDATE); if (error) return error; return xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, id->agno, be32_to_cpu(agf->agf_length) - len), len, &XFS_RMAP_OINFO_SKIP_UPDATE, XFS_AG_RESV_NONE); } /* Retrieve AG geometry. */ int xfs_ag_get_geometry( struct xfs_mount *mp, xfs_agnumber_t agno, struct xfs_ag_geometry *ageo) { struct xfs_buf *agi_bp; struct xfs_buf *agf_bp; struct xfs_agi *agi; struct xfs_agf *agf; struct xfs_perag *pag; unsigned int freeblks; int error; if (agno >= mp->m_sb.sb_agcount) return -EINVAL; /* Lock the AG headers. */ error = xfs_ialloc_read_agi(mp, NULL, agno, &agi_bp); if (error) return error; error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agf_bp); if (error) goto out_agi; pag = xfs_perag_get(mp, agno); /* Fill out form. */ memset(ageo, 0, sizeof(*ageo)); ageo->ag_number = agno; agi = XFS_BUF_TO_AGI(agi_bp); ageo->ag_icount = be32_to_cpu(agi->agi_count); ageo->ag_ifree = be32_to_cpu(agi->agi_freecount); agf = XFS_BUF_TO_AGF(agf_bp); ageo->ag_length = be32_to_cpu(agf->agf_length); freeblks = pag->pagf_freeblks + pag->pagf_flcount + pag->pagf_btreeblks - xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE); ageo->ag_freeblks = freeblks; xfs_ag_geom_health(pag, ageo); /* Release resources. */ xfs_perag_put(pag); xfs_buf_relse(agf_bp); out_agi: xfs_buf_relse(agi_bp); return error; } xfsprogs-5.3.0/libxfs/xfs_ag.h0000644000175000017500000000162713570057155016171 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2018 Red Hat, Inc. * All rights reserved. */ #ifndef __LIBXFS_AG_H #define __LIBXFS_AG_H 1 struct xfs_mount; struct xfs_trans; struct aghdr_init_data { /* per ag data */ xfs_agblock_t agno; /* ag to init */ xfs_extlen_t agsize; /* new AG size */ struct list_head buffer_list; /* buffer writeback list */ xfs_rfsblock_t nfree; /* cumulative new free space */ /* per header data */ xfs_daddr_t daddr; /* header location */ size_t numblks; /* size of header */ xfs_btnum_t type; /* type of btree root block */ }; int xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id); int xfs_ag_extend_space(struct xfs_mount *mp, struct xfs_trans *tp, struct aghdr_init_data *id, xfs_extlen_t len); int xfs_ag_get_geometry(struct xfs_mount *mp, xfs_agnumber_t agno, struct xfs_ag_geometry *ageo); #endif /* __LIBXFS_AG_H */ xfsprogs-5.3.0/libxfs/xfs_ag_resv.c0000644000175000017500000002551513570057155017225 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_rmap_btree.h" #include "xfs_btree.h" #include "xfs_refcount_btree.h" #include "xfs_ialloc_btree.h" /* * Per-AG Block Reservations * * For some kinds of allocation group metadata structures, it is advantageous * to reserve a small number of blocks in each AG so that future expansions of * that data structure do not encounter ENOSPC because errors during a btree * split cause the filesystem to go offline. * * Prior to the introduction of reflink, this wasn't an issue because the free * space btrees maintain a reserve of space (the AGFL) to handle any expansion * that may be necessary; and allocations of other metadata (inodes, BMBT, * dir/attr) aren't restricted to a single AG. However, with reflink it is * possible to allocate all the space in an AG, have subsequent reflink/CoW * activity expand the refcount btree, and discover that there's no space left * to handle that expansion. Since we can calculate the maximum size of the * refcount btree, we can reserve space for it and avoid ENOSPC. * * Handling per-AG reservations consists of three changes to the allocator's * behavior: First, because these reservations are always needed, we decrease * the ag_max_usable counter to reflect the size of the AG after the reserved * blocks are taken. Second, the reservations must be reflected in the * fdblocks count to maintain proper accounting. Third, each AG must maintain * its own reserved block counter so that we can calculate the amount of space * that must remain free to maintain the reservations. Fourth, the "remaining * reserved blocks" count must be used when calculating the length of the * longest free extent in an AG and to clamp maxlen in the per-AG allocation * functions. In other words, we maintain a virtual allocation via in-core * accounting tricks so that we don't have to clean up after a crash. :) * * Reserved blocks can be managed by passing one of the enum xfs_ag_resv_type * values via struct xfs_alloc_arg or directly to the xfs_free_extent * function. It might seem a little funny to maintain a reservoir of blocks * to feed another reservoir, but the AGFL only holds enough blocks to get * through the next transaction. The per-AG reservation is to ensure (we * hope) that each AG never runs out of blocks. Each data structure wanting * to use the reservation system should update ask/used in xfs_ag_resv_init. */ /* * Are we critically low on blocks? For now we'll define that as the number * of blocks we can get our hands on being less than 10% of what we reserved * or less than some arbitrary number (maximum btree height). */ bool xfs_ag_resv_critical( struct xfs_perag *pag, enum xfs_ag_resv_type type) { xfs_extlen_t avail; xfs_extlen_t orig; switch (type) { case XFS_AG_RESV_METADATA: avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved; orig = pag->pag_meta_resv.ar_asked; break; case XFS_AG_RESV_RMAPBT: avail = pag->pagf_freeblks + pag->pagf_flcount - pag->pag_meta_resv.ar_reserved; orig = pag->pag_rmapbt_resv.ar_asked; break; default: ASSERT(0); return false; } trace_xfs_ag_resv_critical(pag, type, avail); /* Critically low if less than 10% or max btree height remains. */ return XFS_TEST_ERROR(avail < orig / 10 || avail < XFS_BTREE_MAXLEVELS, pag->pag_mount, XFS_ERRTAG_AG_RESV_CRITICAL); } /* * How many blocks are reserved but not used, and therefore must not be * allocated away? */ xfs_extlen_t xfs_ag_resv_needed( struct xfs_perag *pag, enum xfs_ag_resv_type type) { xfs_extlen_t len; len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved; switch (type) { case XFS_AG_RESV_METADATA: case XFS_AG_RESV_RMAPBT: len -= xfs_perag_resv(pag, type)->ar_reserved; break; case XFS_AG_RESV_NONE: /* empty */ break; default: ASSERT(0); } trace_xfs_ag_resv_needed(pag, type, len); return len; } /* Clean out a reservation */ static int __xfs_ag_resv_free( struct xfs_perag *pag, enum xfs_ag_resv_type type) { struct xfs_ag_resv *resv; xfs_extlen_t oldresv; int error; trace_xfs_ag_resv_free(pag, type, 0); resv = xfs_perag_resv(pag, type); if (pag->pag_agno == 0) pag->pag_mount->m_ag_max_usable += resv->ar_asked; /* * RMAPBT blocks come from the AGFL and AGFL blocks are always * considered "free", so whatever was reserved at mount time must be * given back at umount. */ if (type == XFS_AG_RESV_RMAPBT) oldresv = resv->ar_orig_reserved; else oldresv = resv->ar_reserved; error = xfs_mod_fdblocks(pag->pag_mount, oldresv, true); resv->ar_reserved = 0; resv->ar_asked = 0; resv->ar_orig_reserved = 0; if (error) trace_xfs_ag_resv_free_error(pag->pag_mount, pag->pag_agno, error, _RET_IP_); return error; } /* Free a per-AG reservation. */ int xfs_ag_resv_free( struct xfs_perag *pag) { int error; int err2; error = __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT); err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA); if (err2 && !error) error = err2; return error; } static int __xfs_ag_resv_init( struct xfs_perag *pag, enum xfs_ag_resv_type type, xfs_extlen_t ask, xfs_extlen_t used) { struct xfs_mount *mp = pag->pag_mount; struct xfs_ag_resv *resv; int error; xfs_extlen_t hidden_space; if (used > ask) ask = used; switch (type) { case XFS_AG_RESV_RMAPBT: /* * Space taken by the rmapbt is not subtracted from fdblocks * because the rmapbt lives in the free space. Here we must * subtract the entire reservation from fdblocks so that we * always have blocks available for rmapbt expansion. */ hidden_space = ask; break; case XFS_AG_RESV_METADATA: /* * Space taken by all other metadata btrees are accounted * on-disk as used space. We therefore only hide the space * that is reserved but not used by the trees. */ hidden_space = ask - used; break; default: ASSERT(0); return -EINVAL; } error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true); if (error) { trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno, error, _RET_IP_); xfs_warn(mp, "Per-AG reservation for AG %u failed. Filesystem may run out of space.", pag->pag_agno); return error; } /* * Reduce the maximum per-AG allocation length by however much we're * trying to reserve for an AG. Since this is a filesystem-wide * counter, we only make the adjustment for AG 0. This assumes that * there aren't any AGs hungrier for per-AG reservation than AG 0. */ if (pag->pag_agno == 0) mp->m_ag_max_usable -= ask; resv = xfs_perag_resv(pag, type); resv->ar_asked = ask; resv->ar_orig_reserved = hidden_space; resv->ar_reserved = ask - used; trace_xfs_ag_resv_init(pag, type, ask); return 0; } /* Create a per-AG block reservation. */ int xfs_ag_resv_init( struct xfs_perag *pag, struct xfs_trans *tp) { struct xfs_mount *mp = pag->pag_mount; xfs_agnumber_t agno = pag->pag_agno; xfs_extlen_t ask; xfs_extlen_t used; int error = 0; /* Create the metadata reservation. */ if (pag->pag_meta_resv.ar_asked == 0) { ask = used = 0; error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used); if (error) goto out; error = xfs_finobt_calc_reserves(mp, tp, agno, &ask, &used); if (error) goto out; error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, ask, used); if (error) { /* * Because we didn't have per-AG reservations when the * finobt feature was added we might not be able to * reserve all needed blocks. Warn and fall back to the * old and potentially buggy code in that case, but * ensure we do have the reservation for the refcountbt. */ ask = used = 0; mp->m_finobt_nores = true; error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used); if (error) goto out; error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, ask, used); if (error) goto out; } } /* Create the RMAPBT metadata reservation */ if (pag->pag_rmapbt_resv.ar_asked == 0) { ask = used = 0; error = xfs_rmapbt_calc_reserves(mp, tp, agno, &ask, &used); if (error) goto out; error = __xfs_ag_resv_init(pag, XFS_AG_RESV_RMAPBT, ask, used); if (error) goto out; } #ifdef DEBUG /* need to read in the AGF for the ASSERT below to work */ error = xfs_alloc_pagf_init(pag->pag_mount, tp, pag->pag_agno, 0); if (error) return error; ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved + xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <= pag->pagf_freeblks + pag->pagf_flcount); #endif out: return error; } /* Allocate a block from the reservation. */ void xfs_ag_resv_alloc_extent( struct xfs_perag *pag, enum xfs_ag_resv_type type, struct xfs_alloc_arg *args) { struct xfs_ag_resv *resv; xfs_extlen_t len; uint field; trace_xfs_ag_resv_alloc_extent(pag, type, args->len); switch (type) { case XFS_AG_RESV_AGFL: return; case XFS_AG_RESV_METADATA: case XFS_AG_RESV_RMAPBT: resv = xfs_perag_resv(pag, type); break; default: ASSERT(0); /* fall through */ case XFS_AG_RESV_NONE: field = args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : XFS_TRANS_SB_FDBLOCKS; xfs_trans_mod_sb(args->tp, field, -(int64_t)args->len); return; } len = min_t(xfs_extlen_t, args->len, resv->ar_reserved); resv->ar_reserved -= len; if (type == XFS_AG_RESV_RMAPBT) return; /* Allocations of reserved blocks only need on-disk sb updates... */ xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len); /* ...but non-reserved blocks need in-core and on-disk updates. */ if (args->len > len) xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_FDBLOCKS, -((int64_t)args->len - len)); } /* Free a block to the reservation. */ void xfs_ag_resv_free_extent( struct xfs_perag *pag, enum xfs_ag_resv_type type, struct xfs_trans *tp, xfs_extlen_t len) { xfs_extlen_t leftover; struct xfs_ag_resv *resv; trace_xfs_ag_resv_free_extent(pag, type, len); switch (type) { case XFS_AG_RESV_AGFL: return; case XFS_AG_RESV_METADATA: case XFS_AG_RESV_RMAPBT: resv = xfs_perag_resv(pag, type); break; default: ASSERT(0); /* fall through */ case XFS_AG_RESV_NONE: xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len); return; } leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved); resv->ar_reserved += leftover; if (type == XFS_AG_RESV_RMAPBT) return; /* Freeing into the reserved pool only requires on-disk update... */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len); /* ...but freeing beyond that requires in-core and on-disk update. */ if (len > leftover) xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len - leftover); } xfsprogs-5.3.0/libxfs/xfs_ag_resv.h0000644000175000017500000000266413435336036017230 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_AG_RESV_H__ #define __XFS_AG_RESV_H__ int xfs_ag_resv_free(struct xfs_perag *pag); int xfs_ag_resv_init(struct xfs_perag *pag, struct xfs_trans *tp); bool xfs_ag_resv_critical(struct xfs_perag *pag, enum xfs_ag_resv_type type); xfs_extlen_t xfs_ag_resv_needed(struct xfs_perag *pag, enum xfs_ag_resv_type type); void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type, struct xfs_alloc_arg *args); void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type, struct xfs_trans *tp, xfs_extlen_t len); /* * RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from * the AGFL, they are allocated one at a time and the reservation updates don't * require a transaction. */ static inline void xfs_ag_resv_rmapbt_alloc( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_alloc_arg args = { NULL }; struct xfs_perag *pag; args.len = 1; pag = xfs_perag_get(mp, agno); xfs_ag_resv_alloc_extent(pag, XFS_AG_RESV_RMAPBT, &args); xfs_perag_put(pag); } static inline void xfs_ag_resv_rmapbt_free( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_perag *pag; pag = xfs_perag_get(mp, agno); xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1); xfs_perag_put(pag); } #endif /* __XFS_AG_RESV_H__ */ xfsprogs-5.3.0/libxfs/xfs_alloc.c0000644000175000017500000025572013570057155016674 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_shared.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_btree.h" #include "xfs_rmap.h" #include "xfs_alloc_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_ag_resv.h" #include "xfs_bmap.h" extern kmem_zone_t *xfs_bmap_free_item_zone; struct workqueue_struct *xfs_alloc_wq; #define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) #define XFSA_FIXUP_BNO_OK 1 #define XFSA_FIXUP_CNT_OK 2 STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *); STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *); STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *); /* * Size of the AGFL. For CRC-enabled filesystes we steal a couple of slots in * the beginning of the block for a proper header with the location information * and CRC. */ unsigned int xfs_agfl_size( struct xfs_mount *mp) { unsigned int size = mp->m_sb.sb_sectsize; if (xfs_sb_version_hascrc(&mp->m_sb)) size -= sizeof(struct xfs_agfl); return size / sizeof(xfs_agblock_t); } unsigned int xfs_refc_block( struct xfs_mount *mp) { if (xfs_sb_version_hasrmapbt(&mp->m_sb)) return XFS_RMAP_BLOCK(mp) + 1; if (xfs_sb_version_hasfinobt(&mp->m_sb)) return XFS_FIBT_BLOCK(mp) + 1; return XFS_IBT_BLOCK(mp) + 1; } xfs_extlen_t xfs_prealloc_blocks( struct xfs_mount *mp) { if (xfs_sb_version_hasreflink(&mp->m_sb)) return xfs_refc_block(mp) + 1; if (xfs_sb_version_hasrmapbt(&mp->m_sb)) return XFS_RMAP_BLOCK(mp) + 1; if (xfs_sb_version_hasfinobt(&mp->m_sb)) return XFS_FIBT_BLOCK(mp) + 1; return XFS_IBT_BLOCK(mp) + 1; } /* * In order to avoid ENOSPC-related deadlock caused by out-of-order locking of * AGF buffer (PV 947395), we place constraints on the relationship among * actual allocations for data blocks, freelist blocks, and potential file data * bmap btree blocks. However, these restrictions may result in no actual space * allocated for a delayed extent, for example, a data block in a certain AG is * allocated but there is no additional block for the additional bmap btree * block due to a split of the bmap btree of the file. The result of this may * lead to an infinite loop when the file gets flushed to disk and all delayed * extents need to be actually allocated. To get around this, we explicitly set * aside a few blocks which will not be reserved in delayed allocation. * * We need to reserve 4 fsbs _per AG_ for the freelist and 4 more to handle a * potential split of the file's bmap btree. */ unsigned int xfs_alloc_set_aside( struct xfs_mount *mp) { return mp->m_sb.sb_agcount * (XFS_ALLOC_AGFL_RESERVE + 4); } /* * When deciding how much space to allocate out of an AG, we limit the * allocation maximum size to the size the AG. However, we cannot use all the * blocks in the AG - some are permanently used by metadata. These * blocks are generally: * - the AG superblock, AGF, AGI and AGFL * - the AGF (bno and cnt) and AGI btree root blocks, and optionally * the AGI free inode and rmap btree root blocks. * - blocks on the AGFL according to xfs_alloc_set_aside() limits * - the rmapbt root block * * The AG headers are sector sized, so the amount of space they take up is * dependent on filesystem geometry. The others are all single blocks. */ unsigned int xfs_alloc_ag_max_usable( struct xfs_mount *mp) { unsigned int blocks; blocks = XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)); /* ag headers */ blocks += XFS_ALLOC_AGFL_RESERVE; blocks += 3; /* AGF, AGI btree root blocks */ if (xfs_sb_version_hasfinobt(&mp->m_sb)) blocks++; /* finobt root block */ if (xfs_sb_version_hasrmapbt(&mp->m_sb)) blocks++; /* rmap root block */ if (xfs_sb_version_hasreflink(&mp->m_sb)) blocks++; /* refcount root block */ return mp->m_sb.sb_agblocks - blocks; } /* * Lookup the record equal to [bno, len] in the btree given by cur. */ STATIC int /* error */ xfs_alloc_lookup_eq( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */ { cur->bc_rec.a.ar_startblock = bno; cur->bc_rec.a.ar_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); } /* * Lookup the first record greater than or equal to [bno, len] * in the btree given by cur. */ int /* error */ xfs_alloc_lookup_ge( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */ { cur->bc_rec.a.ar_startblock = bno; cur->bc_rec.a.ar_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); } /* * Lookup the first record less than or equal to [bno, len] * in the btree given by cur. */ int /* error */ xfs_alloc_lookup_le( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */ { cur->bc_rec.a.ar_startblock = bno; cur->bc_rec.a.ar_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); } /* * Update the record referred to by cur to the value given * by [bno, len]. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int /* error */ xfs_alloc_update( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len) /* length of extent */ { union xfs_btree_rec rec; rec.alloc.ar_startblock = cpu_to_be32(bno); rec.alloc.ar_blockcount = cpu_to_be32(len); return xfs_btree_update(cur, &rec); } /* * Get the data from the pointed-to record. */ int /* error */ xfs_alloc_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t *bno, /* output: starting block of extent */ xfs_extlen_t *len, /* output: length of extent */ int *stat) /* output: success/failure */ { struct xfs_mount *mp = cur->bc_mp; xfs_agnumber_t agno = cur->bc_private.a.agno; union xfs_btree_rec *rec; int error; error = xfs_btree_get_rec(cur, &rec, stat); if (error || !(*stat)) return error; *bno = be32_to_cpu(rec->alloc.ar_startblock); *len = be32_to_cpu(rec->alloc.ar_blockcount); if (*len == 0) goto out_bad_rec; /* check for valid extent range, including overflow */ if (!xfs_verify_agbno(mp, agno, *bno)) goto out_bad_rec; if (*bno > *bno + *len) goto out_bad_rec; if (!xfs_verify_agbno(mp, agno, *bno + *len - 1)) goto out_bad_rec; return 0; out_bad_rec: xfs_warn(mp, "%s Freespace BTree record corruption in AG %d detected!", cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size", agno); xfs_warn(mp, "start block 0x%x block count 0x%x", *bno, *len); return -EFSCORRUPTED; } /* * Compute aligned version of the found extent. * Takes alignment and min length into account. */ STATIC bool xfs_alloc_compute_aligned( xfs_alloc_arg_t *args, /* allocation argument structure */ xfs_agblock_t foundbno, /* starting block in found extent */ xfs_extlen_t foundlen, /* length in found extent */ xfs_agblock_t *resbno, /* result block number */ xfs_extlen_t *reslen, /* result length */ unsigned *busy_gen) { xfs_agblock_t bno = foundbno; xfs_extlen_t len = foundlen; xfs_extlen_t diff; bool busy; /* Trim busy sections out of found extent */ busy = xfs_extent_busy_trim(args, &bno, &len, busy_gen); /* * If we have a largish extent that happens to start before min_agbno, * see if we can shift it into range... */ if (bno < args->min_agbno && bno + len > args->min_agbno) { diff = args->min_agbno - bno; if (len > diff) { bno += diff; len -= diff; } } if (args->alignment > 1 && len >= args->minlen) { xfs_agblock_t aligned_bno = roundup(bno, args->alignment); diff = aligned_bno - bno; *resbno = aligned_bno; *reslen = diff >= len ? 0 : len - diff; } else { *resbno = bno; *reslen = len; } return busy; } /* * Compute best start block and diff for "near" allocations. * freelen >= wantlen already checked by caller. */ STATIC xfs_extlen_t /* difference value (absolute) */ xfs_alloc_compute_diff( xfs_agblock_t wantbno, /* target starting block */ xfs_extlen_t wantlen, /* target length */ xfs_extlen_t alignment, /* target alignment */ int datatype, /* are we allocating data? */ xfs_agblock_t freebno, /* freespace's starting block */ xfs_extlen_t freelen, /* freespace's length */ xfs_agblock_t *newbnop) /* result: best start block from free */ { xfs_agblock_t freeend; /* end of freespace extent */ xfs_agblock_t newbno1; /* return block number */ xfs_agblock_t newbno2; /* other new block number */ xfs_extlen_t newlen1=0; /* length with newbno1 */ xfs_extlen_t newlen2=0; /* length with newbno2 */ xfs_agblock_t wantend; /* end of target extent */ bool userdata = xfs_alloc_is_userdata(datatype); ASSERT(freelen >= wantlen); freeend = freebno + freelen; wantend = wantbno + wantlen; /* * We want to allocate from the start of a free extent if it is past * the desired block or if we are allocating user data and the free * extent is before desired block. The second case is there to allow * for contiguous allocation from the remaining free space if the file * grows in the short term. */ if (freebno >= wantbno || (userdata && freeend < wantend)) { if ((newbno1 = roundup(freebno, alignment)) >= freeend) newbno1 = NULLAGBLOCK; } else if (freeend >= wantend && alignment > 1) { newbno1 = roundup(wantbno, alignment); newbno2 = newbno1 - alignment; if (newbno1 >= freeend) newbno1 = NULLAGBLOCK; else newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); if (newbno2 < freebno) newbno2 = NULLAGBLOCK; else newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { if (newlen1 < newlen2 || (newlen1 == newlen2 && XFS_ABSDIFF(newbno1, wantbno) > XFS_ABSDIFF(newbno2, wantbno))) newbno1 = newbno2; } else if (newbno2 != NULLAGBLOCK) newbno1 = newbno2; } else if (freeend >= wantend) { newbno1 = wantbno; } else if (alignment > 1) { newbno1 = roundup(freeend - wantlen, alignment); if (newbno1 > freeend - wantlen && newbno1 - alignment >= freebno) newbno1 -= alignment; else if (newbno1 >= freeend) newbno1 = NULLAGBLOCK; } else newbno1 = freeend - wantlen; *newbnop = newbno1; return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno); } /* * Fix up the length, based on mod and prod. * len should be k * prod + mod for some k. * If len is too small it is returned unchanged. * If len hits maxlen it is left alone. */ STATIC void xfs_alloc_fix_len( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_extlen_t k; xfs_extlen_t rlen; ASSERT(args->mod < args->prod); rlen = args->len; ASSERT(rlen >= args->minlen); ASSERT(rlen <= args->maxlen); if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen || (args->mod == 0 && rlen < args->prod)) return; k = rlen % args->prod; if (k == args->mod) return; if (k > args->mod) rlen = rlen - (k - args->mod); else rlen = rlen - args->prod + (args->mod - k); /* casts to (int) catch length underflows */ if ((int)rlen < (int)args->minlen) return; ASSERT(rlen >= args->minlen && rlen <= args->maxlen); ASSERT(rlen % args->prod == args->mod); ASSERT(args->pag->pagf_freeblks + args->pag->pagf_flcount >= rlen + args->minleft); args->len = rlen; } /* * Update the two btrees, logically removing from freespace the extent * starting at rbno, rlen blocks. The extent is contained within the * actual (current) free extent fbno for flen blocks. * Flags are passed in indicating whether the cursors are set to the * relevant records. */ STATIC int /* error code */ xfs_alloc_fixup_trees( xfs_btree_cur_t *cnt_cur, /* cursor for by-size btree */ xfs_btree_cur_t *bno_cur, /* cursor for by-block btree */ xfs_agblock_t fbno, /* starting block of free extent */ xfs_extlen_t flen, /* length of free extent */ xfs_agblock_t rbno, /* starting block of returned extent */ xfs_extlen_t rlen, /* length of returned extent */ int flags) /* flags, XFSA_FIXUP_... */ { int error; /* error code */ int i; /* operation results */ xfs_agblock_t nfbno1; /* first new free startblock */ xfs_agblock_t nfbno2; /* second new free startblock */ xfs_extlen_t nflen1=0; /* first new free length */ xfs_extlen_t nflen2=0; /* second new free length */ struct xfs_mount *mp; mp = cnt_cur->bc_mp; /* * Look up the record in the by-size tree if necessary. */ if (flags & XFSA_FIXUP_CNT_OK) { #ifdef DEBUG if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1 && nfbno1 == fbno && nflen1 == flen); #endif } else { if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } /* * Look up the record in the by-block tree if necessary. */ if (flags & XFSA_FIXUP_BNO_OK) { #ifdef DEBUG if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1 && nfbno1 == fbno && nflen1 == flen); #endif } else { if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } #ifdef DEBUG if (bno_cur->bc_nlevels == 1 && cnt_cur->bc_nlevels == 1) { struct xfs_btree_block *bnoblock; struct xfs_btree_block *cntblock; bnoblock = XFS_BUF_TO_BLOCK(bno_cur->bc_bufs[0]); cntblock = XFS_BUF_TO_BLOCK(cnt_cur->bc_bufs[0]); XFS_WANT_CORRUPTED_RETURN(mp, bnoblock->bb_numrecs == cntblock->bb_numrecs); } #endif /* * Deal with all four cases: the allocated record is contained * within the freespace record, so we can have new freespace * at either (or both) end, or no freespace remaining. */ if (rbno == fbno && rlen == flen) nfbno1 = nfbno2 = NULLAGBLOCK; else if (rbno == fbno) { nfbno1 = rbno + rlen; nflen1 = flen - rlen; nfbno2 = NULLAGBLOCK; } else if (rbno + rlen == fbno + flen) { nfbno1 = fbno; nflen1 = flen - rlen; nfbno2 = NULLAGBLOCK; } else { nfbno1 = fbno; nflen1 = rbno - fbno; nfbno2 = rbno + rlen; nflen2 = (fbno + flen) - nfbno2; } /* * Delete the entry from the by-size btree. */ if ((error = xfs_btree_delete(cnt_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); /* * Add new by-size btree entry(s). */ if (nfbno1 != NULLAGBLOCK) { if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 0); if ((error = xfs_btree_insert(cnt_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } if (nfbno2 != NULLAGBLOCK) { if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 0); if ((error = xfs_btree_insert(cnt_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } /* * Fix up the by-block btree entry(s). */ if (nfbno1 == NULLAGBLOCK) { /* * No remaining freespace, just delete the by-block tree entry. */ if ((error = xfs_btree_delete(bno_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } else { /* * Update the by-block entry to start later|be shorter. */ if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) return error; } if (nfbno2 != NULLAGBLOCK) { /* * 2 resulting free entries, need to add one. */ if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 0); if ((error = xfs_btree_insert(bno_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } return 0; } static xfs_failaddr_t xfs_agfl_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp); int i; /* * There is no verification of non-crc AGFLs because mkfs does not * initialise the AGFL to zero or NULL. Hence the only valid part of the * AGFL is what the AGF says is active. We can't get to the AGF, so we * can't verify just those entries are valid. */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return NULL; if (!xfs_verify_magic(bp, agfl->agfl_magicnum)) return __this_address; if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem. */ if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno) return __this_address; for (i = 0; i < xfs_agfl_size(mp); i++) { if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK && be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) return __this_address; } if (!xfs_log_check_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn))) return __this_address; return NULL; } static void xfs_agfl_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; /* * There is no verification of non-crc AGFLs because mkfs does not * initialise the AGFL to zero or NULL. Hence the only valid part of the * AGFL is what the AGF says is active. We can't get to the AGF, so we * can't verify just those entries are valid. */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (!xfs_buf_verify_cksum(bp, XFS_AGFL_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_agfl_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_agfl_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; xfs_failaddr_t fa; /* no verification of non-crc AGFLs */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; fa = xfs_agfl_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (bip) XFS_BUF_TO_AGFL(bp)->agfl_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_AGFL_CRC_OFF); } const struct xfs_buf_ops xfs_agfl_buf_ops = { .name = "xfs_agfl", .magic = { cpu_to_be32(XFS_AGFL_MAGIC), cpu_to_be32(XFS_AGFL_MAGIC) }, .verify_read = xfs_agfl_read_verify, .verify_write = xfs_agfl_write_verify, .verify_struct = xfs_agfl_verify, }; /* * Read in the allocation group free block array. */ int /* error */ xfs_alloc_read_agfl( xfs_mount_t *mp, /* mount point structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_buf_t **bpp) /* buffer for the ag free block array */ { xfs_buf_t *bp; /* return value */ int error; ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf( mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops); if (error) return error; xfs_buf_set_ref(bp, XFS_AGFL_REF); *bpp = bp; return 0; } STATIC int xfs_alloc_update_counters( struct xfs_trans *tp, struct xfs_perag *pag, struct xfs_buf *agbp, long len) { struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); pag->pagf_freeblks += len; be32_add_cpu(&agf->agf_freeblks, len); xfs_trans_agblocks_delta(tp, len); if (unlikely(be32_to_cpu(agf->agf_freeblks) > be32_to_cpu(agf->agf_length))) return -EFSCORRUPTED; xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); return 0; } /* * Allocation group level functions. */ /* * Deal with the case where only small freespaces remain. Either return the * contents of the last freespace record, or allocate space from the freelist if * there is nothing in the tree. */ STATIC int /* error */ xfs_alloc_ag_vextent_small( struct xfs_alloc_arg *args, /* allocation argument structure */ struct xfs_btree_cur *ccur, /* optional by-size cursor */ xfs_agblock_t *fbnop, /* result block number */ xfs_extlen_t *flenp, /* result length */ int *stat) /* status: 0-freelist, 1-normal/none */ { int error = 0; xfs_agblock_t fbno = NULLAGBLOCK; xfs_extlen_t flen = 0; int i = 0; /* * If a cntbt cursor is provided, try to allocate the largest record in * the tree. Try the AGFL if the cntbt is empty, otherwise fail the * allocation. Make sure to respect minleft even when pulling from the * freelist. */ if (ccur) error = xfs_btree_decrement(ccur, 0, &i); if (error) goto error; if (i) { error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error); goto out; } if (args->minlen != 1 || args->alignment != 1 || args->resv == XFS_AG_RESV_AGFL || (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount) <= args->minleft)) goto out; error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0); if (error) goto error; if (fbno == NULLAGBLOCK) goto out; xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1, xfs_alloc_allow_busy_reuse(args->datatype)); if (xfs_alloc_is_userdata(args->datatype)) { struct xfs_buf *bp; bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno); if (!bp) { error = -EFSCORRUPTED; goto error; } xfs_trans_binval(args->tp, bp); } *fbnop = args->agbno = fbno; *flenp = args->len = 1; XFS_WANT_CORRUPTED_GOTO(args->mp, fbno < be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length), error); args->wasfromfl = 1; trace_xfs_alloc_small_freelist(args); /* * If we're feeding an AGFL block to something that doesn't live in the * free space, we need to clear out the OWN_AG rmap. */ error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1, &XFS_RMAP_OINFO_AG); if (error) goto error; *stat = 0; return 0; out: /* * Can't do the allocation, give up. */ if (flen < args->minlen) { args->agbno = NULLAGBLOCK; trace_xfs_alloc_small_notenough(args); flen = 0; } *fbnop = fbno; *flenp = flen; *stat = 1; trace_xfs_alloc_small_done(args); return 0; error: trace_xfs_alloc_small_error(args); return error; } /* * Allocate a variable extent in the allocation group agno. * Type and bno are used to determine where in the allocation group the * extent will start. * Extent's length (returned in *len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent( xfs_alloc_arg_t *args) /* argument structure for allocation */ { int error=0; ASSERT(args->minlen > 0); ASSERT(args->maxlen > 0); ASSERT(args->minlen <= args->maxlen); ASSERT(args->mod < args->prod); ASSERT(args->alignment > 0); /* * Branch to correct routine based on the type. */ args->wasfromfl = 0; switch (args->type) { case XFS_ALLOCTYPE_THIS_AG: error = xfs_alloc_ag_vextent_size(args); break; case XFS_ALLOCTYPE_NEAR_BNO: error = xfs_alloc_ag_vextent_near(args); break; case XFS_ALLOCTYPE_THIS_BNO: error = xfs_alloc_ag_vextent_exact(args); break; default: ASSERT(0); /* NOTREACHED */ } if (error || args->agbno == NULLAGBLOCK) return error; ASSERT(args->len >= args->minlen); ASSERT(args->len <= args->maxlen); ASSERT(!args->wasfromfl || args->resv != XFS_AG_RESV_AGFL); ASSERT(args->agbno % args->alignment == 0); /* if not file data, insert new block into the reverse map btree */ if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) { error = xfs_rmap_alloc(args->tp, args->agbp, args->agno, args->agbno, args->len, &args->oinfo); if (error) return error; } if (!args->wasfromfl) { error = xfs_alloc_update_counters(args->tp, args->pag, args->agbp, -((long)(args->len))); if (error) return error; ASSERT(!xfs_extent_busy_search(args->mp, args->agno, args->agbno, args->len)); } xfs_ag_resv_alloc_extent(args->pag, args->resv, args); XFS_STATS_INC(args->mp, xs_allocx); XFS_STATS_ADD(args->mp, xs_allocb, args->len); return error; } /* * Allocate a variable extent at exactly agno/bno. * Extent's length (returned in *len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent_exact( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */ xfs_btree_cur_t *cnt_cur;/* by count btree cursor */ int error; xfs_agblock_t fbno; /* start block of found extent */ xfs_extlen_t flen; /* length of found extent */ xfs_agblock_t tbno; /* start block of busy extent */ xfs_extlen_t tlen; /* length of busy extent */ xfs_agblock_t tend; /* end block of busy extent */ int i; /* success/failure of operation */ unsigned busy_gen; ASSERT(args->alignment == 1); /* * Allocate/initialize a cursor for the by-number freespace btree. */ bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); /* * Lookup bno and minlen in the btree (minlen is irrelevant, really). * Look for the closest free block <= bno, it must contain bno * if any free block does. */ error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i); if (error) goto error0; if (!i) goto not_found; /* * Grab the freespace record. */ error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); ASSERT(fbno <= args->agbno); /* * Check for overlapping busy extents. */ tbno = fbno; tlen = flen; xfs_extent_busy_trim(args, &tbno, &tlen, &busy_gen); /* * Give up if the start of the extent is busy, or the freespace isn't * long enough for the minimum request. */ if (tbno > args->agbno) goto not_found; if (tlen < args->minlen) goto not_found; tend = tbno + tlen; if (tend < args->agbno + args->minlen) goto not_found; /* * End of extent will be smaller of the freespace end and the * maximal requested end. * * Fix the length according to mod and prod if given. */ args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen) - args->agbno; xfs_alloc_fix_len(args); ASSERT(args->agbno + args->len <= tend); /* * We are allocating agbno for args->len * Allocate/initialize a cursor for the by-size btree. */ cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_CNT); ASSERT(args->agbno + args->len <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno, args->len, XFSA_FIXUP_BNO_OK); if (error) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); goto error0; } xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); args->wasfromfl = 0; trace_xfs_alloc_exact_done(args); return 0; not_found: /* Didn't find it, return null. */ xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); args->agbno = NULLAGBLOCK; trace_xfs_alloc_exact_notfound(args); return 0; error0: xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); trace_xfs_alloc_exact_error(args); return error; } /* * Search the btree in a given direction via the search cursor and compare * the records found against the good extent we've already found. */ STATIC int xfs_alloc_find_best_extent( struct xfs_alloc_arg *args, /* allocation argument structure */ struct xfs_btree_cur **gcur, /* good cursor */ struct xfs_btree_cur **scur, /* searching cursor */ xfs_agblock_t gdiff, /* difference for search comparison */ xfs_agblock_t *sbno, /* extent found by search */ xfs_extlen_t *slen, /* extent length */ xfs_agblock_t *sbnoa, /* aligned extent found by search */ xfs_extlen_t *slena, /* aligned extent length */ int dir) /* 0 = search right, 1 = search left */ { xfs_agblock_t new; xfs_agblock_t sdiff; int error; int i; unsigned busy_gen; /* The good extent is perfect, no need to search. */ if (!gdiff) goto out_use_good; /* * Look until we find a better one, run out of space or run off the end. */ do { error = xfs_alloc_get_rec(*scur, sbno, slen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); xfs_alloc_compute_aligned(args, *sbno, *slen, sbnoa, slena, &busy_gen); /* * The good extent is closer than this one. */ if (!dir) { if (*sbnoa > args->max_agbno) goto out_use_good; if (*sbnoa >= args->agbno + gdiff) goto out_use_good; } else { if (*sbnoa < args->min_agbno) goto out_use_good; if (*sbnoa <= args->agbno - gdiff) goto out_use_good; } /* * Same distance, compare length and pick the best. */ if (*slena >= args->minlen) { args->len = XFS_EXTLEN_MIN(*slena, args->maxlen); xfs_alloc_fix_len(args); sdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->datatype, *sbnoa, *slena, &new); /* * Choose closer size and invalidate other cursor. */ if (sdiff < gdiff) goto out_use_search; goto out_use_good; } if (!dir) error = xfs_btree_increment(*scur, 0, &i); else error = xfs_btree_decrement(*scur, 0, &i); if (error) goto error0; } while (i); out_use_good: xfs_btree_del_cursor(*scur, XFS_BTREE_NOERROR); *scur = NULL; return 0; out_use_search: xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR); *gcur = NULL; return 0; error0: /* caller invalidates cursors */ return error; } /* * Allocate a variable extent near bno in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent_near( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ xfs_agblock_t gtbno; /* start bno of right side entry */ xfs_agblock_t gtbnoa; /* aligned ... */ xfs_extlen_t gtdiff; /* difference to right side entry */ xfs_extlen_t gtlen; /* length of right side entry */ xfs_extlen_t gtlena; /* aligned ... */ xfs_agblock_t gtnew; /* useful start bno of right side */ int error; /* error code */ int i; /* result code, temporary */ int j; /* result code, temporary */ xfs_agblock_t ltbno; /* start bno of left side entry */ xfs_agblock_t ltbnoa; /* aligned ... */ xfs_extlen_t ltdiff; /* difference to left side entry */ xfs_extlen_t ltlen; /* length of left side entry */ xfs_extlen_t ltlena; /* aligned ... */ xfs_agblock_t ltnew; /* useful start bno of left side */ xfs_extlen_t rlen; /* length of returned extent */ bool busy; unsigned busy_gen; #ifdef DEBUG /* * Randomly don't execute the first algorithm. */ int dofirst; /* set to do first algorithm */ dofirst = prandom_u32() & 1; #endif /* handle unitialized agbno range so caller doesn't have to */ if (!args->min_agbno && !args->max_agbno) args->max_agbno = args->mp->m_sb.sb_agblocks - 1; ASSERT(args->min_agbno <= args->max_agbno); /* clamp agbno to the range if it's outside */ if (args->agbno < args->min_agbno) args->agbno = args->min_agbno; if (args->agbno > args->max_agbno) args->agbno = args->max_agbno; restart: bno_cur_lt = NULL; bno_cur_gt = NULL; ltlen = 0; gtlena = 0; ltlena = 0; busy = false; /* * Get a cursor for the by-size btree. */ cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_CNT); /* * See if there are any free extents as big as maxlen. */ if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) goto error0; /* * If none, then pick up the last entry in the tree unless the * tree is empty. */ if (!i) { if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, <len, &i))) goto error0; if (i == 0 || ltlen == 0) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_near_noentry(args); return 0; } ASSERT(i == 1); } args->wasfromfl = 0; /* * First algorithm. * If the requested extent is large wrt the freespaces available * in this a.g., then the cursor will be pointing to a btree entry * near the right edge of the tree. If it's in the last btree leaf * block, then we just examine all the entries in that block * that are big enough, and pick the best one. * This is written as a while loop so we can break out of it, * but we never loop back to the top. */ while (xfs_btree_islastblock(cnt_cur, 0)) { xfs_extlen_t bdiff; int besti=0; xfs_extlen_t blen=0; xfs_agblock_t bnew=0; #ifdef DEBUG if (dofirst) break; #endif /* * Start from the entry that lookup found, sequence through * all larger free blocks. If we're actually pointing at a * record smaller than maxlen, go to the start of this block, * and skip all those smaller than minlen. */ if (ltlen || args->alignment > 1) { cnt_cur->bc_ptrs[0] = 1; do { if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); if (ltlen >= args->minlen) break; if ((error = xfs_btree_increment(cnt_cur, 0, &i))) goto error0; } while (i); ASSERT(ltlen >= args->minlen); if (!i) break; } i = cnt_cur->bc_ptrs[0]; for (j = 1, blen = 0, bdiff = 0; !error && j && (blen < args->maxlen || bdiff > 0); error = xfs_btree_increment(cnt_cur, 0, &j)) { /* * For each entry, decide if it's better than * the previous best entry. */ if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); busy = xfs_alloc_compute_aligned(args, ltbno, ltlen, <bnoa, <lena, &busy_gen); if (ltlena < args->minlen) continue; if (ltbnoa < args->min_agbno || ltbnoa > args->max_agbno) continue; args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); xfs_alloc_fix_len(args); ASSERT(args->len >= args->minlen); if (args->len < blen) continue; ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->datatype, ltbnoa, ltlena, <new); if (ltnew != NULLAGBLOCK && (args->len > blen || ltdiff < bdiff)) { bdiff = ltdiff; bnew = ltnew; blen = args->len; besti = cnt_cur->bc_ptrs[0]; } } /* * It didn't work. We COULD be in a case where * there's a good record somewhere, so try again. */ if (blen == 0) break; /* * Point at the best entry, and retrieve it again. */ cnt_cur->bc_ptrs[0] = besti; if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); args->len = blen; /* * We are allocating starting at bnew for blen blocks. */ args->agbno = bnew; ASSERT(bnew >= ltbno); ASSERT(bnew + blen <= ltbno + ltlen); /* * Set up a cursor for the by-bno tree. */ bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); /* * Fix up the btree entries. */ if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) goto error0; xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); trace_xfs_alloc_near_first(args); return 0; } /* * Second algorithm. * Search in the by-bno tree to the left and to the right * simultaneously, until in each case we find a space big enough, * or run into the edge of the tree. When we run into the edge, * we deallocate that cursor. * If both searches succeed, we compare the two spaces and pick * the better one. * With alignment, it's possible for both to fail; the upper * level algorithm that picks allocation groups for allocations * is not supposed to do this. */ /* * Allocate and initialize the cursor for the leftward search. */ bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); /* * Lookup <= bno to find the leftward search's starting point. */ if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) goto error0; if (!i) { /* * Didn't find anything; use this cursor for the rightward * search. */ bno_cur_gt = bno_cur_lt; bno_cur_lt = NULL; } /* * Found something. Duplicate the cursor for the rightward search. */ else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) goto error0; /* * Increment the cursor, so we will point at the entry just right * of the leftward entry if any, or to the leftmost entry. */ if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) goto error0; if (!i) { /* * It failed, there are no rightward entries. */ xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); bno_cur_gt = NULL; } /* * Loop going left with the leftward cursor, right with the * rightward cursor, until either both directions give up or * we find an entry at least as big as minlen. */ do { if (bno_cur_lt) { if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); busy |= xfs_alloc_compute_aligned(args, ltbno, ltlen, <bnoa, <lena, &busy_gen); if (ltlena >= args->minlen && ltbnoa >= args->min_agbno) break; if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i))) goto error0; if (!i || ltbnoa < args->min_agbno) { xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); bno_cur_lt = NULL; } } if (bno_cur_gt) { if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); busy |= xfs_alloc_compute_aligned(args, gtbno, gtlen, >bnoa, >lena, &busy_gen); if (gtlena >= args->minlen && gtbnoa <= args->max_agbno) break; if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) goto error0; if (!i || gtbnoa > args->max_agbno) { xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); bno_cur_gt = NULL; } } } while (bno_cur_lt || bno_cur_gt); /* * Got both cursors still active, need to find better entry. */ if (bno_cur_lt && bno_cur_gt) { if (ltlena >= args->minlen) { /* * Left side is good, look for a right side entry. */ args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); xfs_alloc_fix_len(args); ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->datatype, ltbnoa, ltlena, <new); error = xfs_alloc_find_best_extent(args, &bno_cur_lt, &bno_cur_gt, ltdiff, >bno, >len, >bnoa, >lena, 0 /* search right */); } else { ASSERT(gtlena >= args->minlen); /* * Right side is good, look for a left side entry. */ args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); xfs_alloc_fix_len(args); gtdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->datatype, gtbnoa, gtlena, >new); error = xfs_alloc_find_best_extent(args, &bno_cur_gt, &bno_cur_lt, gtdiff, <bno, <len, <bnoa, <lena, 1 /* search left */); } if (error) goto error0; } /* * If we couldn't get anything, give up. */ if (bno_cur_lt == NULL && bno_cur_gt == NULL) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); if (busy) { trace_xfs_alloc_near_busy(args); xfs_extent_busy_flush(args->mp, args->pag, busy_gen); goto restart; } trace_xfs_alloc_size_neither(args); args->agbno = NULLAGBLOCK; return 0; } /* * At this point we have selected a freespace entry, either to the * left or to the right. If it's on the right, copy all the * useful variables to the "left" set so we only have one * copy of this code. */ if (bno_cur_gt) { bno_cur_lt = bno_cur_gt; bno_cur_gt = NULL; ltbno = gtbno; ltbnoa = gtbnoa; ltlen = gtlen; ltlena = gtlena; j = 1; } else j = 0; /* * Fix up the length and compute the useful address. */ args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); xfs_alloc_fix_len(args); rlen = args->len; (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, args->datatype, ltbnoa, ltlena, <new); ASSERT(ltnew >= ltbno); ASSERT(ltnew + rlen <= ltbnoa + ltlena); ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); ASSERT(ltnew >= args->min_agbno && ltnew <= args->max_agbno); args->agbno = ltnew; if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, ltnew, rlen, XFSA_FIXUP_BNO_OK))) goto error0; if (j) trace_xfs_alloc_near_greater(args); else trace_xfs_alloc_near_lesser(args); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); return 0; error0: trace_xfs_alloc_near_error(args); if (cnt_cur != NULL) xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); if (bno_cur_lt != NULL) xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); if (bno_cur_gt != NULL) xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); return error; } /* * Allocate a variable extent anywhere in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent_size( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_btree_cur_t *bno_cur; /* cursor for bno btree */ xfs_btree_cur_t *cnt_cur; /* cursor for cnt btree */ int error; /* error result */ xfs_agblock_t fbno; /* start of found freespace */ xfs_extlen_t flen; /* length of found freespace */ int i; /* temp status variable */ xfs_agblock_t rbno; /* returned block number */ xfs_extlen_t rlen; /* length of returned extent */ bool busy; unsigned busy_gen; restart: /* * Allocate and initialize a cursor for the by-size btree. */ cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_CNT); bno_cur = NULL; busy = false; /* * Look for an entry >= maxlen+alignment-1 blocks. */ if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen + args->alignment - 1, &i))) goto error0; /* * If none then we have to settle for a smaller extent. In the case that * there are no large extents, this will return the last entry in the * tree unless the tree is empty. In the case that there are only busy * large extents, this will return the largest small extent unless there * are no smaller extents available. */ if (!i) { error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno, &flen, &i); if (error) goto error0; if (i == 0 || flen == 0) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_noentry(args); return 0; } ASSERT(i == 1); busy = xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen, &busy_gen); } else { /* * Search for a non-busy extent that is large enough. */ for (;;) { error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); busy = xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen, &busy_gen); if (rlen >= args->maxlen) break; error = xfs_btree_increment(cnt_cur, 0, &i); if (error) goto error0; if (i == 0) { /* * Our only valid extents must have been busy. * Make it unbusy by forcing the log out and * retrying. */ xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_busy(args); xfs_extent_busy_flush(args->mp, args->pag, busy_gen); goto restart; } } } /* * In the first case above, we got the last entry in the * by-size btree. Now we check to see if the space hits maxlen * once aligned; if not, we search left for something better. * This can't happen in the second case above. */ rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 || (rlen <= flen && rbno + rlen <= fbno + flen), error0); if (rlen < args->maxlen) { xfs_agblock_t bestfbno; xfs_extlen_t bestflen; xfs_agblock_t bestrbno; xfs_extlen_t bestrlen; bestrlen = rlen; bestrbno = rbno; bestflen = flen; bestfbno = fbno; for (;;) { if ((error = xfs_btree_decrement(cnt_cur, 0, &i))) goto error0; if (i == 0) break; if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); if (flen < bestrlen) break; busy = xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen, &busy_gen); rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 || (rlen <= flen && rbno + rlen <= fbno + flen), error0); if (rlen > bestrlen) { bestrlen = rlen; bestrbno = rbno; bestflen = flen; bestfbno = fbno; if (rlen == args->maxlen) break; } } if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); rlen = bestrlen; rbno = bestrbno; flen = bestflen; fbno = bestfbno; } args->wasfromfl = 0; /* * Fix up the length. */ args->len = rlen; if (rlen < args->minlen) { if (busy) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_busy(args); xfs_extent_busy_flush(args->mp, args->pag, busy_gen); goto restart; } goto out_nominleft; } xfs_alloc_fix_len(args); rlen = args->len; XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0); /* * Allocate and initialize a cursor for the by-block tree. */ bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, rbno, rlen, XFSA_FIXUP_CNT_OK))) goto error0; xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); cnt_cur = bno_cur = NULL; args->len = rlen; args->agbno = rbno; XFS_WANT_CORRUPTED_GOTO(args->mp, args->agbno + args->len <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length), error0); trace_xfs_alloc_size_done(args); return 0; error0: trace_xfs_alloc_size_error(args); if (cnt_cur) xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); if (bno_cur) xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); return error; out_nominleft: xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_nominleft(args); args->agbno = NULLAGBLOCK; return 0; } /* * Free the extent starting at agno/bno for length. */ STATIC int xfs_free_ag_extent( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type) { struct xfs_mount *mp; struct xfs_perag *pag; struct xfs_btree_cur *bno_cur; struct xfs_btree_cur *cnt_cur; xfs_agblock_t gtbno; /* start of right neighbor */ xfs_extlen_t gtlen; /* length of right neighbor */ xfs_agblock_t ltbno; /* start of left neighbor */ xfs_extlen_t ltlen; /* length of left neighbor */ xfs_agblock_t nbno; /* new starting block of freesp */ xfs_extlen_t nlen; /* new length of freespace */ int haveleft; /* have a left neighbor */ int haveright; /* have a right neighbor */ int i; int error; bno_cur = cnt_cur = NULL; mp = tp->t_mountp; if (!xfs_rmap_should_skip_owner_update(oinfo)) { error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo); if (error) goto error0; } /* * Allocate and initialize a cursor for the by-block btree. */ bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO); /* * Look for a neighboring block on the left (lower block numbers) * that is contiguous with this space. */ if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) goto error0; if (haveleft) { /* * There is a block to our left. */ if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * It's not contiguous, though. */ if (ltbno + ltlen < bno) haveleft = 0; else { /* * If this failure happens the request to free this * space was invalid, it's (partly) already free. * Very bad. */ XFS_WANT_CORRUPTED_GOTO(mp, ltbno + ltlen <= bno, error0); } } /* * Look for a neighboring block on the right (higher block numbers) * that is contiguous with this space. */ if ((error = xfs_btree_increment(bno_cur, 0, &haveright))) goto error0; if (haveright) { /* * There is a block to our right. */ if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * It's not contiguous, though. */ if (bno + len < gtbno) haveright = 0; else { /* * If this failure happens the request to free this * space was invalid, it's (partly) already free. * Very bad. */ XFS_WANT_CORRUPTED_GOTO(mp, gtbno >= bno + len, error0); } } /* * Now allocate and initialize a cursor for the by-size tree. */ cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT); /* * Have both left and right contiguous neighbors. * Merge all three into a single free block. */ if (haveleft && haveright) { /* * Delete the old by-size entry on the left. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Delete the old by-size entry on the right. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Delete the old by-block entry for the right block. */ if ((error = xfs_btree_delete(bno_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Move the by-block cursor back to the left neighbor. */ if ((error = xfs_btree_decrement(bno_cur, 0, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); #ifdef DEBUG /* * Check that this is the right record: delete didn't * mangle the cursor. */ { xfs_agblock_t xxbno; xfs_extlen_t xxlen; if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1 && xxbno == ltbno && xxlen == ltlen, error0); } #endif /* * Update remaining by-block entry to the new, joined block. */ nbno = ltbno; nlen = len + ltlen + gtlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0; } /* * Have only a left contiguous neighbor. * Merge it together with the new freespace. */ else if (haveleft) { /* * Delete the old by-size entry on the left. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Back up the by-block cursor to the left neighbor, and * update its length. */ if ((error = xfs_btree_decrement(bno_cur, 0, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); nbno = ltbno; nlen = len + ltlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0; } /* * Have only a right contiguous neighbor. * Merge it together with the new freespace. */ else if (haveright) { /* * Delete the old by-size entry on the right. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Update the starting block and length of the right * neighbor in the by-block tree. */ nbno = bno; nlen = len + gtlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0; } /* * No contiguous neighbors. * Insert the new freespace into the by-block tree. */ else { nbno = bno; nlen = len; if ((error = xfs_btree_insert(bno_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); } xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); bno_cur = NULL; /* * In all cases we need to insert the new freespace in the by-size tree. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, error0); if ((error = xfs_btree_insert(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); cnt_cur = NULL; /* * Update the freespace totals in the ag and superblock. */ pag = xfs_perag_get(mp, agno); error = xfs_alloc_update_counters(tp, pag, agbp, len); xfs_ag_resv_free_extent(pag, type, tp, len); xfs_perag_put(pag); if (error) goto error0; XFS_STATS_INC(mp, xs_freex); XFS_STATS_ADD(mp, xs_freeb, len); trace_xfs_free_extent(mp, agno, bno, len, type, haveleft, haveright); return 0; error0: trace_xfs_free_extent(mp, agno, bno, len, type, -1, -1); if (bno_cur) xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); if (cnt_cur) xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); return error; } /* * Visible (exported) allocation/free functions. * Some of these are used just by xfs_alloc_btree.c and this file. */ /* * Compute and fill in value of m_ag_maxlevels. */ void xfs_alloc_compute_maxlevels( xfs_mount_t *mp) /* file system mount structure */ { mp->m_ag_maxlevels = xfs_btree_compute_maxlevels(mp->m_alloc_mnr, (mp->m_sb.sb_agblocks + 1) / 2); } /* * Find the length of the longest extent in an AG. The 'need' parameter * specifies how much space we're going to need for the AGFL and the * 'reserved' parameter tells us how many blocks in this AG are reserved for * other callers. */ xfs_extlen_t xfs_alloc_longest_free_extent( struct xfs_perag *pag, xfs_extlen_t need, xfs_extlen_t reserved) { xfs_extlen_t delta = 0; /* * If the AGFL needs a recharge, we'll have to subtract that from the * longest extent. */ if (need > pag->pagf_flcount) delta = need - pag->pagf_flcount; /* * If we cannot maintain others' reservations with space from the * not-longest freesp extents, we'll have to subtract /that/ from * the longest extent too. */ if (pag->pagf_freeblks - pag->pagf_longest < reserved) delta += reserved - (pag->pagf_freeblks - pag->pagf_longest); /* * If the longest extent is long enough to satisfy all the * reservations and AGFL rules in place, we can return this extent. */ if (pag->pagf_longest > delta) return pag->pagf_longest - delta; /* Otherwise, let the caller try for 1 block if there's space. */ return pag->pagf_flcount > 0 || pag->pagf_longest > 0; } unsigned int xfs_alloc_min_freelist( struct xfs_mount *mp, struct xfs_perag *pag) { unsigned int min_free; /* space needed by-bno freespace btree */ min_free = min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_BNOi] + 1, mp->m_ag_maxlevels); /* space needed by-size freespace btree */ min_free += min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_CNTi] + 1, mp->m_ag_maxlevels); /* space needed reverse mapping used space btree */ if (xfs_sb_version_hasrmapbt(&mp->m_sb)) min_free += min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_RMAPi] + 1, mp->m_rmap_maxlevels); return min_free; } /* * Check if the operation we are fixing up the freelist for should go ahead or * not. If we are freeing blocks, we always allow it, otherwise the allocation * is dependent on whether the size and shape of free space available will * permit the requested allocation to take place. */ static bool xfs_alloc_space_available( struct xfs_alloc_arg *args, xfs_extlen_t min_free, int flags) { struct xfs_perag *pag = args->pag; xfs_extlen_t alloc_len, longest; xfs_extlen_t reservation; /* blocks that are still reserved */ int available; xfs_extlen_t agflcount; if (flags & XFS_ALLOC_FLAG_FREEING) return true; reservation = xfs_ag_resv_needed(pag, args->resv); /* do we have enough contiguous free space for the allocation? */ alloc_len = args->minlen + (args->alignment - 1) + args->minalignslop; longest = xfs_alloc_longest_free_extent(pag, min_free, reservation); if (longest < alloc_len) return false; /* * Do we have enough free space remaining for the allocation? Don't * account extra agfl blocks because we are about to defer free them, * making them unavailable until the current transaction commits. */ agflcount = min_t(xfs_extlen_t, pag->pagf_flcount, min_free); available = (int)(pag->pagf_freeblks + agflcount - reservation - min_free - args->minleft); if (available < (int)max(args->total, alloc_len)) return false; /* * Clamp maxlen to the amount of free space available for the actual * extent allocation. */ if (available < (int)args->maxlen && !(flags & XFS_ALLOC_FLAG_CHECK)) { args->maxlen = available; ASSERT(args->maxlen > 0); ASSERT(args->maxlen >= args->minlen); } return true; } int xfs_free_agfl_block( struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t agbno, struct xfs_buf *agbp, struct xfs_owner_info *oinfo) { int error; struct xfs_buf *bp; error = xfs_free_ag_extent(tp, agbp, agno, agbno, 1, oinfo, XFS_AG_RESV_AGFL); if (error) return error; bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno); if (!bp) return -EFSCORRUPTED; xfs_trans_binval(tp, bp); return 0; } /* * Check the agfl fields of the agf for inconsistency or corruption. The purpose * is to detect an agfl header padding mismatch between current and early v5 * kernels. This problem manifests as a 1-slot size difference between the * on-disk flcount and the active [first, last] range of a wrapped agfl. This * may also catch variants of agfl count corruption unrelated to padding. Either * way, we'll reset the agfl and warn the user. * * Return true if a reset is required before the agfl can be used, false * otherwise. */ static bool xfs_agfl_needs_reset( struct xfs_mount *mp, struct xfs_agf *agf) { uint32_t f = be32_to_cpu(agf->agf_flfirst); uint32_t l = be32_to_cpu(agf->agf_fllast); uint32_t c = be32_to_cpu(agf->agf_flcount); int agfl_size = xfs_agfl_size(mp); int active; /* no agfl header on v4 supers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; /* * The agf read verifier catches severe corruption of these fields. * Repeat some sanity checks to cover a packed -> unpacked mismatch if * the verifier allows it. */ if (f >= agfl_size || l >= agfl_size) return true; if (c > agfl_size) return true; /* * Check consistency between the on-disk count and the active range. An * agfl padding mismatch manifests as an inconsistent flcount. */ if (c && l >= f) active = l - f + 1; else if (c) active = agfl_size - f + l + 1; else active = 0; return active != c; } /* * Reset the agfl to an empty state. Ignore/drop any existing blocks since the * agfl content cannot be trusted. Warn the user that a repair is required to * recover leaked blocks. * * The purpose of this mechanism is to handle filesystems affected by the agfl * header padding mismatch problem. A reset keeps the filesystem online with a * relatively minor free space accounting inconsistency rather than suffer the * inevitable crash from use of an invalid agfl block. */ static void xfs_agfl_reset( struct xfs_trans *tp, struct xfs_buf *agbp, struct xfs_perag *pag) { struct xfs_mount *mp = tp->t_mountp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); ASSERT(pag->pagf_agflreset); trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); xfs_warn(mp, "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. " "Please unmount and run xfs_repair.", pag->pag_agno, pag->pagf_flcount); agf->agf_flfirst = 0; agf->agf_fllast = cpu_to_be32(xfs_agfl_size(mp) - 1); agf->agf_flcount = 0; xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); pag->pagf_flcount = 0; pag->pagf_agflreset = false; } /* * Defer an AGFL block free. This is effectively equivalent to * xfs_bmap_add_free() with some special handling particular to AGFL blocks. * * Deferring AGFL frees helps prevent log reservation overruns due to too many * allocation operations in a transaction. AGFL frees are prone to this problem * because for one they are always freed one at a time. Further, an immediate * AGFL block free can cause a btree join and require another block free before * the real allocation can proceed. Deferring the free disconnects freeing up * the AGFL slot from freeing the block. */ STATIC void xfs_defer_agfl_block( struct xfs_trans *tp, xfs_agnumber_t agno, xfs_fsblock_t agbno, struct xfs_owner_info *oinfo) { struct xfs_mount *mp = tp->t_mountp; struct xfs_extent_free_item *new; /* new element */ ASSERT(xfs_bmap_free_item_zone != NULL); ASSERT(oinfo != NULL); new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); new->xefi_startblock = XFS_AGB_TO_FSB(mp, agno, agbno); new->xefi_blockcount = 1; new->xefi_oinfo = *oinfo; trace_xfs_agfl_free_defer(mp, agno, 0, agbno, 1); xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_AGFL_FREE, &new->xefi_list); } /* * Decide whether to use this allocation group for this allocation. * If so, fix up the btree freelist's size. */ int /* error */ xfs_alloc_fix_freelist( struct xfs_alloc_arg *args, /* allocation argument structure */ int flags) /* XFS_ALLOC_FLAG_... */ { struct xfs_mount *mp = args->mp; struct xfs_perag *pag = args->pag; struct xfs_trans *tp = args->tp; struct xfs_buf *agbp = NULL; struct xfs_buf *agflbp = NULL; struct xfs_alloc_arg targs; /* local allocation arguments */ xfs_agblock_t bno; /* freelist block */ xfs_extlen_t need; /* total blocks needed in freelist */ int error = 0; /* deferred ops (AGFL block frees) require permanent transactions */ ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); if (!pag->pagf_init) { error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); if (error) goto out_no_agbp; if (!pag->pagf_init) { ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_agbp_relse; } } /* * If this is a metadata preferred pag and we are user data then try * somewhere else if we are not being asked to try harder at this * point */ if (pag->pagf_metadata && xfs_alloc_is_userdata(args->datatype) && (flags & XFS_ALLOC_FLAG_TRYLOCK)) { ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_agbp_relse; } need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags | XFS_ALLOC_FLAG_CHECK)) goto out_agbp_relse; /* * Get the a.g. freespace buffer. * Can fail if we're not blocking on locks, and it's held. */ if (!agbp) { error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); if (error) goto out_no_agbp; if (!agbp) { ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_no_agbp; } } /* reset a padding mismatched agfl before final free space check */ if (pag->pagf_agflreset) xfs_agfl_reset(tp, agbp, pag); /* If there isn't enough total space or single-extent, reject it. */ need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags)) goto out_agbp_relse; /* * Make the freelist shorter if it's too long. * * Note that from this point onwards, we will always release the agf and * agfl buffers on error. This handles the case where we error out and * the buffers are clean or may not have been joined to the transaction * and hence need to be released manually. If they have been joined to * the transaction, then xfs_trans_brelse() will handle them * appropriately based on the recursion count and dirty state of the * buffer. * * XXX (dgc): When we have lots of free space, does this buy us * anything other than extra overhead when we need to put more blocks * back on the free list? Maybe we should only do this when space is * getting low or the AGFL is more than half full? * * The NOSHRINK flag prevents the AGFL from being shrunk if it's too * big; the NORMAP flag prevents AGFL expand/shrink operations from * updating the rmapbt. Both flags are used in xfs_repair while we're * rebuilding the rmapbt, and neither are used by the kernel. They're * both required to ensure that rmaps are correctly recorded for the * regenerated AGFL, bnobt, and cntbt. See repair/phase5.c and * repair/rmap.c in xfsprogs for details. */ memset(&targs, 0, sizeof(targs)); /* struct copy below */ if (flags & XFS_ALLOC_FLAG_NORMAP) targs.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE; else targs.oinfo = XFS_RMAP_OINFO_AG; while (!(flags & XFS_ALLOC_FLAG_NOSHRINK) && pag->pagf_flcount > need) { error = xfs_alloc_get_freelist(tp, agbp, &bno, 0); if (error) goto out_agbp_relse; /* defer agfl frees */ xfs_defer_agfl_block(tp, args->agno, bno, &targs.oinfo); } targs.tp = tp; targs.mp = mp; targs.agbp = agbp; targs.agno = args->agno; targs.alignment = targs.minlen = targs.prod = 1; targs.type = XFS_ALLOCTYPE_THIS_AG; targs.pag = pag; error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp); if (error) goto out_agbp_relse; /* Make the freelist longer if it's too short. */ while (pag->pagf_flcount < need) { targs.agbno = 0; targs.maxlen = need - pag->pagf_flcount; targs.resv = XFS_AG_RESV_AGFL; /* Allocate as many blocks as possible at once. */ error = xfs_alloc_ag_vextent(&targs); if (error) goto out_agflbp_relse; /* * Stop if we run out. Won't happen if callers are obeying * the restrictions correctly. Can happen for free calls * on a completely full ag. */ if (targs.agbno == NULLAGBLOCK) { if (flags & XFS_ALLOC_FLAG_FREEING) break; goto out_agflbp_relse; } /* * Put each allocated block on the list. */ for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) { error = xfs_alloc_put_freelist(tp, agbp, agflbp, bno, 0); if (error) goto out_agflbp_relse; } } xfs_trans_brelse(tp, agflbp); args->agbp = agbp; return 0; out_agflbp_relse: xfs_trans_brelse(tp, agflbp); out_agbp_relse: if (agbp) xfs_trans_brelse(tp, agbp); out_no_agbp: args->agbp = NULL; return error; } /* * Get a block from the freelist. * Returns with the buffer for the block gotten. */ int /* error */ xfs_alloc_get_freelist( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *agbp, /* buffer containing the agf structure */ xfs_agblock_t *bnop, /* block address retrieved from freelist */ int btreeblk) /* destination is a AGF btree */ { xfs_agf_t *agf; /* a.g. freespace structure */ xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ xfs_agblock_t bno; /* block number returned */ __be32 *agfl_bno; int error; int logflags; xfs_mount_t *mp = tp->t_mountp; xfs_perag_t *pag; /* per allocation group data */ /* * Freelist is empty, give up. */ agf = XFS_BUF_TO_AGF(agbp); if (!agf->agf_flcount) { *bnop = NULLAGBLOCK; return 0; } /* * Read the array of free blocks. */ error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno), &agflbp); if (error) return error; /* * Get the block number and update the data structures. */ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]); be32_add_cpu(&agf->agf_flfirst, 1); xfs_trans_brelse(tp, agflbp); if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp)) agf->agf_flfirst = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT; if (btreeblk) { be32_add_cpu(&agf->agf_btreeblks, 1); pag->pagf_btreeblks++; logflags |= XFS_AGF_BTREEBLKS; } xfs_perag_put(pag); xfs_alloc_log_agf(tp, agbp, logflags); *bnop = bno; return 0; } /* * Log the given fields from the agf structure. */ void xfs_alloc_log_agf( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *bp, /* buffer for a.g. freelist header */ int fields) /* mask of fields to be logged (XFS_AGF_...) */ { int first; /* first byte offset */ int last; /* last byte offset */ static const short offsets[] = { offsetof(xfs_agf_t, agf_magicnum), offsetof(xfs_agf_t, agf_versionnum), offsetof(xfs_agf_t, agf_seqno), offsetof(xfs_agf_t, agf_length), offsetof(xfs_agf_t, agf_roots[0]), offsetof(xfs_agf_t, agf_levels[0]), offsetof(xfs_agf_t, agf_flfirst), offsetof(xfs_agf_t, agf_fllast), offsetof(xfs_agf_t, agf_flcount), offsetof(xfs_agf_t, agf_freeblks), offsetof(xfs_agf_t, agf_longest), offsetof(xfs_agf_t, agf_btreeblks), offsetof(xfs_agf_t, agf_uuid), offsetof(xfs_agf_t, agf_rmap_blocks), offsetof(xfs_agf_t, agf_refcount_blocks), offsetof(xfs_agf_t, agf_refcount_root), offsetof(xfs_agf_t, agf_refcount_level), /* needed so that we don't log the whole rest of the structure: */ offsetof(xfs_agf_t, agf_spare64), sizeof(xfs_agf_t) }; trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_); xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGF_BUF); xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); } /* * Interface for inode allocation to force the pag data to be initialized. */ int /* error */ xfs_alloc_pagf_init( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags) /* XFS_ALLOC_FLAGS_... */ { xfs_buf_t *bp; int error; if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) return error; if (bp) xfs_trans_brelse(tp, bp); return 0; } /* * Put the block on the freelist for the allocation group. */ int /* error */ xfs_alloc_put_freelist( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *agbp, /* buffer for a.g. freelist header */ xfs_buf_t *agflbp,/* buffer for a.g. free block array */ xfs_agblock_t bno, /* block being freed */ int btreeblk) /* block came from a AGF btree */ { xfs_agf_t *agf; /* a.g. freespace structure */ __be32 *blockp;/* pointer to array entry */ int error; int logflags; xfs_mount_t *mp; /* mount structure */ xfs_perag_t *pag; /* per allocation group data */ __be32 *agfl_bno; int startoff; agf = XFS_BUF_TO_AGF(agbp); mp = tp->t_mountp; if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno), &agflbp))) return error; be32_add_cpu(&agf->agf_fllast, 1); if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp)) agf->agf_fllast = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT; if (btreeblk) { be32_add_cpu(&agf->agf_btreeblks, -1); pag->pagf_btreeblks--; logflags |= XFS_AGF_BTREEBLKS; } xfs_perag_put(pag); xfs_alloc_log_agf(tp, agbp, logflags); ASSERT(be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp)); agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)]; *blockp = cpu_to_be32(bno); startoff = (char *)blockp - (char *)agflbp->b_addr; xfs_alloc_log_agf(tp, agbp, logflags); xfs_trans_buf_set_type(tp, agflbp, XFS_BLFT_AGFL_BUF); xfs_trans_log_buf(tp, agflbp, startoff, startoff + sizeof(xfs_agblock_t) - 1); return 0; } static xfs_failaddr_t xfs_agf_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn))) return __this_address; } if (!xfs_verify_magic(bp, agf->agf_magicnum)) return __this_address; if (!(XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) && be32_to_cpu(agf->agf_flfirst) < xfs_agfl_size(mp) && be32_to_cpu(agf->agf_fllast) < xfs_agfl_size(mp) && be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp))) return __this_address; if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 || be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) < 1 || be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS || be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS) return __this_address; if (xfs_sb_version_hasrmapbt(&mp->m_sb) && (be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) < 1 || be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS)) return __this_address; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem. */ if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno) return __this_address; if (xfs_sb_version_haslazysbcount(&mp->m_sb) && be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length)) return __this_address; if (xfs_sb_version_hasreflink(&mp->m_sb) && (be32_to_cpu(agf->agf_refcount_level) < 1 || be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS)) return __this_address; return NULL; } static void xfs_agf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_AGF_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_agf_verify(bp); if (XFS_TEST_ERROR(fa, mp, XFS_ERRTAG_ALLOC_READ_AGF)) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_agf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; xfs_failaddr_t fa; fa = xfs_agf_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) XFS_BUF_TO_AGF(bp)->agf_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_AGF_CRC_OFF); } const struct xfs_buf_ops xfs_agf_buf_ops = { .name = "xfs_agf", .magic = { cpu_to_be32(XFS_AGF_MAGIC), cpu_to_be32(XFS_AGF_MAGIC) }, .verify_read = xfs_agf_read_verify, .verify_write = xfs_agf_write_verify, .verify_struct = xfs_agf_verify, }; /* * Read in the allocation group header (free/alloc section). */ int /* error */ xfs_read_agf( struct xfs_mount *mp, /* mount point structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags, /* XFS_BUF_ */ struct xfs_buf **bpp) /* buffer for the ag freelist header */ { int error; trace_xfs_read_agf(mp, agno); ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf( mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops); if (error) return error; if (!*bpp) return 0; ASSERT(!(*bpp)->b_error); xfs_buf_set_ref(*bpp, XFS_AGF_REF); return 0; } /* * Read in the allocation group header (free/alloc section). */ int /* error */ xfs_alloc_read_agf( struct xfs_mount *mp, /* mount point structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags, /* XFS_ALLOC_FLAG_... */ struct xfs_buf **bpp) /* buffer for the ag freelist header */ { struct xfs_agf *agf; /* ag freelist header */ struct xfs_perag *pag; /* per allocation group data */ int error; trace_xfs_alloc_read_agf(mp, agno); ASSERT(agno != NULLAGNUMBER); error = xfs_read_agf(mp, tp, agno, (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0, bpp); if (error) return error; if (!*bpp) return 0; ASSERT(!(*bpp)->b_error); agf = XFS_BUF_TO_AGF(*bpp); pag = xfs_perag_get(mp, agno); if (!pag->pagf_init) { pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks); pag->pagf_flcount = be32_to_cpu(agf->agf_flcount); pag->pagf_longest = be32_to_cpu(agf->agf_longest); pag->pagf_levels[XFS_BTNUM_BNOi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]); pag->pagf_levels[XFS_BTNUM_CNTi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]); pag->pagf_levels[XFS_BTNUM_RMAPi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]); pag->pagf_refcount_level = be32_to_cpu(agf->agf_refcount_level); pag->pagf_init = 1; pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf); } #ifdef DEBUG else if (!XFS_FORCED_SHUTDOWN(mp)) { ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks)); ASSERT(pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks)); ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount)); ASSERT(pag->pagf_longest == be32_to_cpu(agf->agf_longest)); ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] == be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi])); ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] == be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); } #endif xfs_perag_put(pag); return 0; } /* * Allocate an extent (variable-size). * Depending on the allocation type, we either look in a single allocation * group or loop over the allocation groups to find the result. */ int /* error */ xfs_alloc_vextent( struct xfs_alloc_arg *args) /* allocation argument structure */ { xfs_agblock_t agsize; /* allocation group size */ int error; int flags; /* XFS_ALLOC_FLAG_... locking flags */ struct xfs_mount *mp; /* mount structure pointer */ xfs_agnumber_t sagno; /* starting allocation group number */ xfs_alloctype_t type; /* input allocation type */ int bump_rotor = 0; xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */ mp = args->mp; type = args->otype = args->type; args->agbno = NULLAGBLOCK; /* * Just fix this up, for the case where the last a.g. is shorter * (or there's only one a.g.) and the caller couldn't easily figure * that out (xfs_bmap_alloc). */ agsize = mp->m_sb.sb_agblocks; if (args->maxlen > agsize) args->maxlen = agsize; if (args->alignment == 0) args->alignment = 1; ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); ASSERT(args->minlen <= args->maxlen); ASSERT(args->minlen <= agsize); ASSERT(args->mod < args->prod); if (XFS_FSB_TO_AGNO(mp, args->fsbno) >= mp->m_sb.sb_agcount || XFS_FSB_TO_AGBNO(mp, args->fsbno) >= agsize || args->minlen > args->maxlen || args->minlen > agsize || args->mod >= args->prod) { args->fsbno = NULLFSBLOCK; trace_xfs_alloc_vextent_badargs(args); return 0; } switch (type) { case XFS_ALLOCTYPE_THIS_AG: case XFS_ALLOCTYPE_NEAR_BNO: case XFS_ALLOCTYPE_THIS_BNO: /* * These three force us into a single a.g. */ args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); args->pag = xfs_perag_get(mp, args->agno); error = xfs_alloc_fix_freelist(args, 0); if (error) { trace_xfs_alloc_vextent_nofix(args); goto error0; } if (!args->agbp) { trace_xfs_alloc_vextent_noagbp(args); break; } args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); if ((error = xfs_alloc_ag_vextent(args))) goto error0; break; case XFS_ALLOCTYPE_START_BNO: /* * Try near allocation first, then anywhere-in-ag after * the first a.g. fails. */ if ((args->datatype & XFS_ALLOC_INITIAL_USER_DATA) && (mp->m_flags & XFS_MOUNT_32BITINODES)) { args->fsbno = XFS_AGB_TO_FSB(mp, ((mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount), 0); bump_rotor = 1; } args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); args->type = XFS_ALLOCTYPE_NEAR_BNO; /* FALLTHROUGH */ case XFS_ALLOCTYPE_FIRST_AG: /* * Rotate through the allocation groups looking for a winner. */ if (type == XFS_ALLOCTYPE_FIRST_AG) { /* * Start with allocation group given by bno. */ args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); args->type = XFS_ALLOCTYPE_THIS_AG; sagno = 0; flags = 0; } else { /* * Start with the given allocation group. */ args->agno = sagno = XFS_FSB_TO_AGNO(mp, args->fsbno); flags = XFS_ALLOC_FLAG_TRYLOCK; } /* * Loop over allocation groups twice; first time with * trylock set, second time without. */ for (;;) { args->pag = xfs_perag_get(mp, args->agno); error = xfs_alloc_fix_freelist(args, flags); if (error) { trace_xfs_alloc_vextent_nofix(args); goto error0; } /* * If we get a buffer back then the allocation will fly. */ if (args->agbp) { if ((error = xfs_alloc_ag_vextent(args))) goto error0; break; } trace_xfs_alloc_vextent_loopfailed(args); /* * Didn't work, figure out the next iteration. */ if (args->agno == sagno && type == XFS_ALLOCTYPE_START_BNO) args->type = XFS_ALLOCTYPE_THIS_AG; /* * For the first allocation, we can try any AG to get * space. However, if we already have allocated a * block, we don't want to try AGs whose number is below * sagno. Otherwise, we may end up with out-of-order * locking of AGF, which might cause deadlock. */ if (++(args->agno) == mp->m_sb.sb_agcount) { if (args->tp->t_firstblock != NULLFSBLOCK) args->agno = sagno; else args->agno = 0; } /* * Reached the starting a.g., must either be done * or switch to non-trylock mode. */ if (args->agno == sagno) { if (flags == 0) { args->agbno = NULLAGBLOCK; trace_xfs_alloc_vextent_allfailed(args); break; } flags = 0; if (type == XFS_ALLOCTYPE_START_BNO) { args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); args->type = XFS_ALLOCTYPE_NEAR_BNO; } } xfs_perag_put(args->pag); } if (bump_rotor) { if (args->agno == sagno) mp->m_agfrotor = (mp->m_agfrotor + 1) % (mp->m_sb.sb_agcount * rotorstep); else mp->m_agfrotor = (args->agno * rotorstep + 1) % (mp->m_sb.sb_agcount * rotorstep); } break; default: ASSERT(0); /* NOTREACHED */ } if (args->agbno == NULLAGBLOCK) args->fsbno = NULLFSBLOCK; else { args->fsbno = XFS_AGB_TO_FSB(mp, args->agno, args->agbno); #ifdef DEBUG ASSERT(args->len >= args->minlen); ASSERT(args->len <= args->maxlen); ASSERT(args->agbno % args->alignment == 0); XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno), args->len); #endif /* Zero the extent if we were asked to do so */ if (args->datatype & XFS_ALLOC_USERDATA_ZERO) { error = xfs_zero_extent(args->ip, args->fsbno, args->len); if (error) goto error0; } } xfs_perag_put(args->pag); return 0; error0: xfs_perag_put(args->pag); return error; } /* Ensure that the freelist is at full capacity. */ int xfs_free_extent_fix_freelist( struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **agbp) { struct xfs_alloc_arg args; int error; memset(&args, 0, sizeof(struct xfs_alloc_arg)); args.tp = tp; args.mp = tp->t_mountp; args.agno = agno; /* * validate that the block number is legal - the enables us to detect * and handle a silent filesystem corruption rather than crashing. */ if (args.agno >= args.mp->m_sb.sb_agcount) return -EFSCORRUPTED; args.pag = xfs_perag_get(args.mp, args.agno); ASSERT(args.pag); error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); if (error) goto out; *agbp = args.agbp; out: xfs_perag_put(args.pag); return error; } /* * Free an extent. * Just break up the extent address and hand off to xfs_free_ag_extent * after fixing up the freelist. */ int __xfs_free_extent( struct xfs_trans *tp, xfs_fsblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type, bool skip_discard) { struct xfs_mount *mp = tp->t_mountp; struct xfs_buf *agbp; xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, bno); xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, bno); int error; unsigned int busy_flags = 0; ASSERT(len != 0); ASSERT(type != XFS_AG_RESV_AGFL); if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FREE_EXTENT)) return -EIO; error = xfs_free_extent_fix_freelist(tp, agno, &agbp); if (error) return error; XFS_WANT_CORRUPTED_GOTO(mp, agbno < mp->m_sb.sb_agblocks, err); /* validate the extent size is legal now we have the agf locked */ XFS_WANT_CORRUPTED_GOTO(mp, agbno + len <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length), err); error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type); if (error) goto err; if (skip_discard) busy_flags |= XFS_EXTENT_BUSY_SKIP_DISCARD; xfs_extent_busy_insert(tp, agno, agbno, len, busy_flags); return 0; err: xfs_trans_brelse(tp, agbp); return error; } struct xfs_alloc_query_range_info { xfs_alloc_query_range_fn fn; void *priv; }; /* Format btree record and pass to our callback. */ STATIC int xfs_alloc_query_range_helper( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, void *priv) { struct xfs_alloc_query_range_info *query = priv; struct xfs_alloc_rec_incore irec; irec.ar_startblock = be32_to_cpu(rec->alloc.ar_startblock); irec.ar_blockcount = be32_to_cpu(rec->alloc.ar_blockcount); return query->fn(cur, &irec, query->priv); } /* Find all free space within a given range of blocks. */ int xfs_alloc_query_range( struct xfs_btree_cur *cur, struct xfs_alloc_rec_incore *low_rec, struct xfs_alloc_rec_incore *high_rec, xfs_alloc_query_range_fn fn, void *priv) { union xfs_btree_irec low_brec; union xfs_btree_irec high_brec; struct xfs_alloc_query_range_info query; ASSERT(cur->bc_btnum == XFS_BTNUM_BNO); low_brec.a = *low_rec; high_brec.a = *high_rec; query.priv = priv; query.fn = fn; return xfs_btree_query_range(cur, &low_brec, &high_brec, xfs_alloc_query_range_helper, &query); } /* Find all free space records. */ int xfs_alloc_query_all( struct xfs_btree_cur *cur, xfs_alloc_query_range_fn fn, void *priv) { struct xfs_alloc_query_range_info query; ASSERT(cur->bc_btnum == XFS_BTNUM_BNO); query.priv = priv; query.fn = fn; return xfs_btree_query_all(cur, xfs_alloc_query_range_helper, &query); } /* Is there a record covering a given extent? */ int xfs_alloc_has_record( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists) { union xfs_btree_irec low; union xfs_btree_irec high; memset(&low, 0, sizeof(low)); low.a.ar_startblock = bno; memset(&high, 0xFF, sizeof(high)); high.a.ar_startblock = bno + len - 1; return xfs_btree_has_record(cur, &low, &high, exists); } /* * Walk all the blocks in the AGFL. The @walk_fn can return any negative * error code or XFS_ITER_*. */ int xfs_agfl_walk( struct xfs_mount *mp, struct xfs_agf *agf, struct xfs_buf *agflbp, xfs_agfl_walk_fn walk_fn, void *priv) { __be32 *agfl_bno; unsigned int i; int error; agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); i = be32_to_cpu(agf->agf_flfirst); /* Nothing to walk in an empty AGFL. */ if (agf->agf_flcount == cpu_to_be32(0)) return 0; /* Otherwise, walk from first to last, wrapping as needed. */ for (;;) { error = walk_fn(mp, be32_to_cpu(agfl_bno[i]), priv); if (error) return error; if (i == be32_to_cpu(agf->agf_fllast)) break; if (++i == xfs_agfl_size(mp)) i = 0; } return 0; } xfsprogs-5.3.0/libxfs/xfs_alloc.h0000644000175000017500000002103713466663244016677 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_ALLOC_H__ #define __XFS_ALLOC_H__ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; struct xfs_perag; struct xfs_trans; extern struct workqueue_struct *xfs_alloc_wq; unsigned int xfs_agfl_size(struct xfs_mount *mp); /* * Freespace allocation types. Argument to xfs_alloc_[v]extent. */ #define XFS_ALLOCTYPE_FIRST_AG 0x02 /* ... start at ag 0 */ #define XFS_ALLOCTYPE_THIS_AG 0x08 /* anywhere in this a.g. */ #define XFS_ALLOCTYPE_START_BNO 0x10 /* near this block else anywhere */ #define XFS_ALLOCTYPE_NEAR_BNO 0x20 /* in this a.g. and near this block */ #define XFS_ALLOCTYPE_THIS_BNO 0x40 /* at exactly this block */ /* this should become an enum again when the tracing code is fixed */ typedef unsigned int xfs_alloctype_t; #define XFS_ALLOC_TYPES \ { XFS_ALLOCTYPE_FIRST_AG, "FIRST_AG" }, \ { XFS_ALLOCTYPE_THIS_AG, "THIS_AG" }, \ { XFS_ALLOCTYPE_START_BNO, "START_BNO" }, \ { XFS_ALLOCTYPE_NEAR_BNO, "NEAR_BNO" }, \ { XFS_ALLOCTYPE_THIS_BNO, "THIS_BNO" } /* * Flags for xfs_alloc_fix_freelist. */ #define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ #define XFS_ALLOC_FLAG_NORMAP 0x00000004 /* don't modify the rmapbt */ #define XFS_ALLOC_FLAG_NOSHRINK 0x00000008 /* don't shrink the freelist */ #define XFS_ALLOC_FLAG_CHECK 0x00000010 /* test only, don't modify args */ /* * Argument structure for xfs_alloc routines. * This is turned into a structure to avoid having 20 arguments passed * down several levels of the stack. */ typedef struct xfs_alloc_arg { struct xfs_trans *tp; /* transaction pointer */ struct xfs_mount *mp; /* file system mount point */ struct xfs_buf *agbp; /* buffer for a.g. freelist header */ struct xfs_perag *pag; /* per-ag struct for this agno */ struct xfs_inode *ip; /* for userdata zeroing method */ xfs_fsblock_t fsbno; /* file system block number */ xfs_agnumber_t agno; /* allocation group number */ xfs_agblock_t agbno; /* allocation group-relative block # */ xfs_extlen_t minlen; /* minimum size of extent */ xfs_extlen_t maxlen; /* maximum size of extent */ xfs_extlen_t mod; /* mod value for extent size */ xfs_extlen_t prod; /* prod value for extent size */ xfs_extlen_t minleft; /* min blocks must be left after us */ xfs_extlen_t total; /* total blocks needed in xaction */ xfs_extlen_t alignment; /* align answer to multiple of this */ xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */ xfs_agblock_t min_agbno; /* set an agbno range for NEAR allocs */ xfs_agblock_t max_agbno; /* ... */ xfs_extlen_t len; /* output: actual size of extent */ xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */ xfs_alloctype_t otype; /* original allocation type */ int datatype; /* mask defining data type treatment */ char wasdel; /* set if allocation was prev delayed */ char wasfromfl; /* set if allocation is from freelist */ struct xfs_owner_info oinfo; /* owner of blocks being allocated */ enum xfs_ag_resv_type resv; /* block reservation to use */ } xfs_alloc_arg_t; /* * Defines for datatype */ #define XFS_ALLOC_USERDATA (1 << 0)/* allocation is for user data*/ #define XFS_ALLOC_INITIAL_USER_DATA (1 << 1)/* special case start of file */ #define XFS_ALLOC_USERDATA_ZERO (1 << 2)/* zero extent on allocation */ #define XFS_ALLOC_NOBUSY (1 << 3)/* Busy extents not allowed */ static inline bool xfs_alloc_is_userdata(int datatype) { return (datatype & ~XFS_ALLOC_NOBUSY) != 0; } static inline bool xfs_alloc_allow_busy_reuse(int datatype) { return (datatype & XFS_ALLOC_NOBUSY) == 0; } /* freespace limit calculations */ #define XFS_ALLOC_AGFL_RESERVE 4 unsigned int xfs_alloc_set_aside(struct xfs_mount *mp); unsigned int xfs_alloc_ag_max_usable(struct xfs_mount *mp); xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_perag *pag, xfs_extlen_t need, xfs_extlen_t reserved); unsigned int xfs_alloc_min_freelist(struct xfs_mount *mp, struct xfs_perag *pag); /* * Compute and fill in value of m_ag_maxlevels. */ void xfs_alloc_compute_maxlevels( struct xfs_mount *mp); /* file system mount structure */ /* * Get a block from the freelist. * Returns with the buffer for the block gotten. */ int /* error */ xfs_alloc_get_freelist( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer containing the agf structure */ xfs_agblock_t *bnop, /* block address retrieved from freelist */ int btreeblk); /* destination is a AGF btree */ /* * Log the given fields from the agf structure. */ void xfs_alloc_log_agf( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *bp, /* buffer for a.g. freelist header */ int fields);/* mask of fields to be logged (XFS_AGF_...) */ /* * Interface for inode allocation to force the pag data to be initialized. */ int /* error */ xfs_alloc_pagf_init( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags); /* XFS_ALLOC_FLAGS_... */ /* * Put the block on the freelist for the allocation group. */ int /* error */ xfs_alloc_put_freelist( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for a.g. freelist header */ struct xfs_buf *agflbp,/* buffer for a.g. free block array */ xfs_agblock_t bno, /* block being freed */ int btreeblk); /* owner was a AGF btree */ /* * Read in the allocation group header (free/alloc section). */ int /* error */ xfs_alloc_read_agf( struct xfs_mount *mp, /* mount point structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags, /* XFS_ALLOC_FLAG_... */ struct xfs_buf **bpp); /* buffer for the ag freelist header */ /* * Allocate an extent (variable-size). */ int /* error */ xfs_alloc_vextent( xfs_alloc_arg_t *args); /* allocation argument structure */ /* * Free an extent. */ int /* error */ __xfs_free_extent( struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t bno, /* starting block number of extent */ xfs_extlen_t len, /* length of extent */ const struct xfs_owner_info *oinfo, /* extent owner */ enum xfs_ag_resv_type type, /* block reservation type */ bool skip_discard); static inline int xfs_free_extent( struct xfs_trans *tp, xfs_fsblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type) { return __xfs_free_extent(tp, bno, len, oinfo, type, false); } int /* error */ xfs_alloc_lookup_le( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat); /* success/failure */ int /* error */ xfs_alloc_lookup_ge( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat); /* success/failure */ int /* error */ xfs_alloc_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t *bno, /* output: starting block of extent */ xfs_extlen_t *len, /* output: length of extent */ int *stat); /* output: success/failure */ int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, int flags, struct xfs_buf **bpp); int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp); int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t, struct xfs_buf *, struct xfs_owner_info *); int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags); int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **agbp); xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp); typedef int (*xfs_alloc_query_range_fn)( struct xfs_btree_cur *cur, struct xfs_alloc_rec_incore *rec, void *priv); int xfs_alloc_query_range(struct xfs_btree_cur *cur, struct xfs_alloc_rec_incore *low_rec, struct xfs_alloc_rec_incore *high_rec, xfs_alloc_query_range_fn fn, void *priv); int xfs_alloc_query_all(struct xfs_btree_cur *cur, xfs_alloc_query_range_fn fn, void *priv); int xfs_alloc_has_record(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exist); typedef int (*xfs_agfl_walk_fn)(struct xfs_mount *mp, xfs_agblock_t bno, void *priv); int xfs_agfl_walk(struct xfs_mount *mp, struct xfs_agf *agf, struct xfs_buf *agflbp, xfs_agfl_walk_fn walk_fn, void *priv); #endif /* __XFS_ALLOC_H__ */ xfsprogs-5.3.0/libxfs/xfs_alloc_btree.c0000644000175000017500000003165013570057155020047 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_btree.h" #include "xfs_alloc_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" STATIC struct xfs_btree_cur * xfs_allocbt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agbp, cur->bc_private.a.agno, cur->bc_btnum); } STATIC void xfs_allocbt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int inc) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int btnum = cur->bc_btnum; struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); ASSERT(ptr->s != 0); agf->agf_roots[btnum] = ptr->s; be32_add_cpu(&agf->agf_levels[btnum], inc); pag->pagf_levels[btnum] += inc; xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); } STATIC int xfs_allocbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { int error; xfs_agblock_t bno; /* Allocate the new block from the freelist. If we can't, give up. */ error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, &bno, 1); if (error) return error; if (bno == NULLAGBLOCK) { *stat = 0; return 0; } xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false); xfs_trans_agbtree_delta(cur->bc_tp, 1); new->s = cpu_to_be32(bno); *stat = 1; return 0; } STATIC int xfs_allocbt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agblock_t bno; int error; bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); if (error) return error; xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, XFS_EXTENT_BUSY_SKIP_DISCARD); xfs_trans_agbtree_delta(cur->bc_tp, -1); return 0; } /* * Update the longest extent in the AGF */ STATIC void xfs_allocbt_update_lastrec( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_rec *rec, int ptr, int reason) { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); struct xfs_perag *pag; __be32 len; int numrecs; ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); switch (reason) { case LASTREC_UPDATE: /* * If this is the last leaf block and it's the last record, * then update the size of the longest extent in the AG. */ if (ptr != xfs_btree_get_numrecs(block)) return; len = rec->alloc.ar_blockcount; break; case LASTREC_INSREC: if (be32_to_cpu(rec->alloc.ar_blockcount) <= be32_to_cpu(agf->agf_longest)) return; len = rec->alloc.ar_blockcount; break; case LASTREC_DELREC: numrecs = xfs_btree_get_numrecs(block); if (ptr <= numrecs) return; ASSERT(ptr == numrecs + 1); if (numrecs) { xfs_alloc_rec_t *rrp; rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); len = rrp->ar_blockcount; } else { len = 0; } break; default: ASSERT(0); return; } agf->agf_longest = len; pag = xfs_perag_get(cur->bc_mp, seqno); pag->pagf_longest = be32_to_cpu(len); xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); } STATIC int xfs_allocbt_get_minrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_alloc_mnr[level != 0]; } STATIC int xfs_allocbt_get_maxrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_alloc_mxr[level != 0]; } STATIC void xfs_allocbt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->alloc.ar_startblock = rec->alloc.ar_startblock; key->alloc.ar_blockcount = rec->alloc.ar_blockcount; } STATIC void xfs_bnobt_init_high_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { __u32 x; x = be32_to_cpu(rec->alloc.ar_startblock); x += be32_to_cpu(rec->alloc.ar_blockcount) - 1; key->alloc.ar_startblock = cpu_to_be32(x); key->alloc.ar_blockcount = 0; } STATIC void xfs_cntbt_init_high_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->alloc.ar_blockcount = rec->alloc.ar_blockcount; key->alloc.ar_startblock = 0; } STATIC void xfs_allocbt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); } STATIC void xfs_allocbt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); ptr->s = agf->agf_roots[cur->bc_btnum]; } STATIC int64_t xfs_bnobt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; xfs_alloc_key_t *kp = &key->alloc; return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; } STATIC int64_t xfs_cntbt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; xfs_alloc_key_t *kp = &key->alloc; int64_t diff; diff = (int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; if (diff) return diff; return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; } STATIC int64_t xfs_bnobt_diff_two_keys( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return (int64_t)be32_to_cpu(k1->alloc.ar_startblock) - be32_to_cpu(k2->alloc.ar_startblock); } STATIC int64_t xfs_cntbt_diff_two_keys( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { int64_t diff; diff = be32_to_cpu(k1->alloc.ar_blockcount) - be32_to_cpu(k2->alloc.ar_blockcount); if (diff) return diff; return be32_to_cpu(k1->alloc.ar_startblock) - be32_to_cpu(k2->alloc.ar_startblock); } static xfs_failaddr_t xfs_allocbt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_perag *pag = bp->b_pag; xfs_failaddr_t fa; unsigned int level; xfs_btnum_t btnum = XFS_BTNUM_BNOi; if (!xfs_verify_magic(bp, block->bb_magic)) return __this_address; if (xfs_sb_version_hascrc(&mp->m_sb)) { fa = xfs_btree_sblock_v5hdr_verify(bp); if (fa) return fa; } /* * The perag may not be attached during grow operations or fully * initialized from the AGF during log recovery. Therefore we can only * check against maximum tree depth from those contexts. * * Otherwise check against the per-tree limit. Peek at one of the * verifier magic values to determine the type of tree we're verifying * against. */ level = be16_to_cpu(block->bb_level); if (bp->b_ops->magic[0] == cpu_to_be32(XFS_ABTC_MAGIC)) btnum = XFS_BTNUM_CNTi; if (pag && pag->pagf_init) { if (level >= pag->pagf_levels[btnum]) return __this_address; } else if (level >= mp->m_ag_maxlevels) return __this_address; return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]); } static void xfs_allocbt_read_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; if (!xfs_btree_sblock_verify_crc(bp)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_allocbt_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } if (bp->b_error) trace_xfs_btree_corrupt(bp, _RET_IP_); } static void xfs_allocbt_write_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_allocbt_verify(bp); if (fa) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } xfs_btree_sblock_calc_crc(bp); } const struct xfs_buf_ops xfs_bnobt_buf_ops = { .name = "xfs_bnobt", .magic = { cpu_to_be32(XFS_ABTB_MAGIC), cpu_to_be32(XFS_ABTB_CRC_MAGIC) }, .verify_read = xfs_allocbt_read_verify, .verify_write = xfs_allocbt_write_verify, .verify_struct = xfs_allocbt_verify, }; const struct xfs_buf_ops xfs_cntbt_buf_ops = { .name = "xfs_cntbt", .magic = { cpu_to_be32(XFS_ABTC_MAGIC), cpu_to_be32(XFS_ABTC_CRC_MAGIC) }, .verify_read = xfs_allocbt_read_verify, .verify_write = xfs_allocbt_write_verify, .verify_struct = xfs_allocbt_verify, }; STATIC int xfs_bnobt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be32_to_cpu(k1->alloc.ar_startblock) < be32_to_cpu(k2->alloc.ar_startblock); } STATIC int xfs_bnobt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return be32_to_cpu(r1->alloc.ar_startblock) + be32_to_cpu(r1->alloc.ar_blockcount) <= be32_to_cpu(r2->alloc.ar_startblock); } STATIC int xfs_cntbt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be32_to_cpu(k1->alloc.ar_blockcount) < be32_to_cpu(k2->alloc.ar_blockcount) || (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && be32_to_cpu(k1->alloc.ar_startblock) < be32_to_cpu(k2->alloc.ar_startblock)); } STATIC int xfs_cntbt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return be32_to_cpu(r1->alloc.ar_blockcount) < be32_to_cpu(r2->alloc.ar_blockcount) || (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && be32_to_cpu(r1->alloc.ar_startblock) < be32_to_cpu(r2->alloc.ar_startblock)); } static const struct xfs_btree_ops xfs_bnobt_ops = { .rec_len = sizeof(xfs_alloc_rec_t), .key_len = sizeof(xfs_alloc_key_t), .dup_cursor = xfs_allocbt_dup_cursor, .set_root = xfs_allocbt_set_root, .alloc_block = xfs_allocbt_alloc_block, .free_block = xfs_allocbt_free_block, .update_lastrec = xfs_allocbt_update_lastrec, .get_minrecs = xfs_allocbt_get_minrecs, .get_maxrecs = xfs_allocbt_get_maxrecs, .init_key_from_rec = xfs_allocbt_init_key_from_rec, .init_high_key_from_rec = xfs_bnobt_init_high_key_from_rec, .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, .key_diff = xfs_bnobt_key_diff, .buf_ops = &xfs_bnobt_buf_ops, .diff_two_keys = xfs_bnobt_diff_two_keys, .keys_inorder = xfs_bnobt_keys_inorder, .recs_inorder = xfs_bnobt_recs_inorder, }; static const struct xfs_btree_ops xfs_cntbt_ops = { .rec_len = sizeof(xfs_alloc_rec_t), .key_len = sizeof(xfs_alloc_key_t), .dup_cursor = xfs_allocbt_dup_cursor, .set_root = xfs_allocbt_set_root, .alloc_block = xfs_allocbt_alloc_block, .free_block = xfs_allocbt_free_block, .update_lastrec = xfs_allocbt_update_lastrec, .get_minrecs = xfs_allocbt_get_minrecs, .get_maxrecs = xfs_allocbt_get_maxrecs, .init_key_from_rec = xfs_allocbt_init_key_from_rec, .init_high_key_from_rec = xfs_cntbt_init_high_key_from_rec, .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, .key_diff = xfs_cntbt_key_diff, .buf_ops = &xfs_cntbt_buf_ops, .diff_two_keys = xfs_cntbt_diff_two_keys, .keys_inorder = xfs_cntbt_keys_inorder, .recs_inorder = xfs_cntbt_recs_inorder, }; /* * Allocate a new allocation btree cursor. */ struct xfs_btree_cur * /* new alloc btree cursor */ xfs_allocbt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for agf structure */ xfs_agnumber_t agno, /* allocation group number */ xfs_btnum_t btnum) /* btree identifier */ { struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); struct xfs_btree_cur *cur; ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_btnum = btnum; cur->bc_blocklog = mp->m_sb.sb_blocklog; if (btnum == XFS_BTNUM_CNT) { cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtc_2); cur->bc_ops = &xfs_cntbt_ops; cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; } else { cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2); cur->bc_ops = &xfs_bnobt_ops; cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); } cur->bc_private.a.agbp = agbp; cur->bc_private.a.agno = agno; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; return cur; } /* * Calculate number of records in an alloc btree block. */ int xfs_allocbt_maxrecs( struct xfs_mount *mp, int blocklen, int leaf) { blocklen -= XFS_ALLOC_BLOCK_LEN(mp); if (leaf) return blocklen / sizeof(xfs_alloc_rec_t); return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); } /* Calculate the freespace btree size for some records. */ xfs_extlen_t xfs_allocbt_calc_size( struct xfs_mount *mp, unsigned long long len) { return xfs_btree_calc_size(mp->m_alloc_mnr, len); } xfsprogs-5.3.0/libxfs/xfs_alloc_btree.h0000644000175000017500000000275713435336036020060 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_ALLOC_BTREE_H__ #define __XFS_ALLOC_BTREE_H__ /* * Freespace on-disk structures */ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; /* * Btree block header size depends on a superblock flag. */ #define XFS_ALLOC_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN) /* * Record, key, and pointer address macros for btree blocks. * * (note that some of these may appear unused, but they are used in userspace) */ #define XFS_ALLOC_REC_ADDR(mp, block, index) \ ((xfs_alloc_rec_t *) \ ((char *)(block) + \ XFS_ALLOC_BLOCK_LEN(mp) + \ (((index) - 1) * sizeof(xfs_alloc_rec_t)))) #define XFS_ALLOC_KEY_ADDR(mp, block, index) \ ((xfs_alloc_key_t *) \ ((char *)(block) + \ XFS_ALLOC_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_alloc_key_t))) #define XFS_ALLOC_PTR_ADDR(mp, block, index, maxrecs) \ ((xfs_alloc_ptr_t *) \ ((char *)(block) + \ XFS_ALLOC_BLOCK_LEN(mp) + \ (maxrecs) * sizeof(xfs_alloc_key_t) + \ ((index) - 1) * sizeof(xfs_alloc_ptr_t))) extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, xfs_btnum_t); extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int); extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp, unsigned long long len); #endif /* __XFS_ALLOC_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_attr.c0000644000175000017500000010144213570057155016543 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_attr_sf.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_attr.h" #include "xfs_attr_leaf.h" #include "xfs_attr_remote.h" #include "xfs_trans_space.h" #include "xfs_trace.h" /* * xfs_attr.c * * Provide the external interfaces to manage attribute lists. */ /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Internal routines when attribute list fits inside the inode. */ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); /* * Internal routines when attribute list is one block. */ STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); /* * Internal routines when attribute list is more than one block. */ STATIC int xfs_attr_node_get(xfs_da_args_t *args); STATIC int xfs_attr_node_addname(xfs_da_args_t *args); STATIC int xfs_attr_node_removename(xfs_da_args_t *args); STATIC int xfs_attr_fillstate(xfs_da_state_t *state); STATIC int xfs_attr_refillstate(xfs_da_state_t *state); STATIC int xfs_attr_args_init( struct xfs_da_args *args, struct xfs_inode *dp, const unsigned char *name, int flags) { if (!name) return -EINVAL; memset(args, 0, sizeof(*args)); args->geo = dp->i_mount->m_attr_geo; args->whichfork = XFS_ATTR_FORK; args->dp = dp; args->flags = flags; args->name = name; args->namelen = strlen((const char *)name); if (args->namelen >= MAXNAMELEN) return -EFAULT; /* match IRIX behaviour */ args->hashval = xfs_da_hashname(args->name, args->namelen); return 0; } int xfs_inode_hasattr( struct xfs_inode *ip) { if (!XFS_IFORK_Q(ip) || (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && ip->i_d.di_anextents == 0)) return 0; return 1; } /*======================================================================== * Overall external interface routines. *========================================================================*/ /* Retrieve an extended attribute and its value. Must have ilock. */ int xfs_attr_get_ilocked( struct xfs_inode *ip, struct xfs_da_args *args) { ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); if (!xfs_inode_hasattr(ip)) return -ENOATTR; else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) return xfs_attr_shortform_getvalue(args); else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) return xfs_attr_leaf_get(args); else return xfs_attr_node_get(args); } /* Retrieve an extended attribute by name, and its value. */ int xfs_attr_get( struct xfs_inode *ip, const unsigned char *name, unsigned char *value, int *valuelenp, int flags) { struct xfs_da_args args; uint lock_mode; int error; XFS_STATS_INC(ip->i_mount, xs_attr_get); if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; error = xfs_attr_args_init(&args, ip, name, flags); if (error) return error; args.value = value; args.valuelen = *valuelenp; /* Entirely possible to look up a name which doesn't exist */ args.op_flags = XFS_DA_OP_OKNOENT; lock_mode = xfs_ilock_attr_map_shared(ip); error = xfs_attr_get_ilocked(ip, &args); xfs_iunlock(ip, lock_mode); *valuelenp = args.valuelen; return error == -EEXIST ? 0 : error; } /* * Calculate how many blocks we need for the new attribute, */ STATIC int xfs_attr_calc_size( struct xfs_da_args *args, int *local) { struct xfs_mount *mp = args->dp->i_mount; int size; int nblks; /* * Determine space new attribute will use, and if it would be * "local" or "remote" (note: local != inline). */ size = xfs_attr_leaf_newentsize(args, local); nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); if (*local) { if (size > (args->geo->blksize / 2)) { /* Double split possible */ nblks *= 2; } } else { /* * Out of line attribute, cannot double split, but * make room for the attribute value itself. */ uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen); nblks += dblocks; nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); } return nblks; } STATIC int xfs_attr_try_sf_addname( struct xfs_inode *dp, struct xfs_da_args *args) { struct xfs_mount *mp = dp->i_mount; int error, error2; error = xfs_attr_shortform_addname(args); if (error == -ENOSPC) return error; /* * Commit the shortform mods, and we're done. * NOTE: this is also the error path (EEXIST, etc). */ if (!error && (args->flags & ATTR_KERNOTIME) == 0) xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG); if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(args->trans); error2 = xfs_trans_commit(args->trans); args->trans = NULL; return error ? error : error2; } /* * Set the attribute specified in @args. */ int xfs_attr_set_args( struct xfs_da_args *args) { struct xfs_inode *dp = args->dp; struct xfs_buf *leaf_bp = NULL; int error; /* * If the attribute list is non-existent or a shortform list, * upgrade it to a single-leaf-block attribute list. */ if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && dp->i_d.di_anextents == 0)) { /* * Build initial attribute list (if required). */ if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) xfs_attr_shortform_create(args); /* * Try to add the attr to the attribute list in the inode. */ error = xfs_attr_try_sf_addname(dp, args); if (error != -ENOSPC) return error; /* * It won't fit in the shortform, transform to a leaf block. * GROT: another possible req'mt for a double-split btree op. */ error = xfs_attr_shortform_to_leaf(args, &leaf_bp); if (error) return error; /* * Prevent the leaf buffer from being unlocked so that a * concurrent AIL push cannot grab the half-baked leaf * buffer and run into problems with the write verifier. * Once we're done rolling the transaction we can release * the hold and add the attr to the leaf. */ xfs_trans_bhold(args->trans, leaf_bp); error = xfs_defer_finish(&args->trans); xfs_trans_bhold_release(args->trans, leaf_bp); if (error) { xfs_trans_brelse(args->trans, leaf_bp); return error; } } if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) error = xfs_attr_leaf_addname(args); else error = xfs_attr_node_addname(args); return error; } /* * Remove the attribute specified in @args. */ int xfs_attr_remove_args( struct xfs_da_args *args) { struct xfs_inode *dp = args->dp; int error; if (!xfs_inode_hasattr(dp)) { error = -ENOATTR; } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); error = xfs_attr_shortform_remove(args); } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { error = xfs_attr_leaf_removename(args); } else { error = xfs_attr_node_removename(args); } return error; } int xfs_attr_set( struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags) { struct xfs_mount *mp = dp->i_mount; struct xfs_da_args args; struct xfs_trans_res tres; int rsvd = (flags & ATTR_ROOT) != 0; int error, local; XFS_STATS_INC(mp, xs_attr_set); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return -EIO; error = xfs_attr_args_init(&args, dp, name, flags); if (error) return error; args.value = value; args.valuelen = valuelen; args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; args.total = xfs_attr_calc_size(&args, &local); error = xfs_qm_dqattach(dp); if (error) return error; /* * If the inode doesn't have an attribute fork, add one. * (inode must not be locked when we call this routine) */ if (XFS_IFORK_Q(dp) == 0) { int sf_size = sizeof(xfs_attr_sf_hdr_t) + XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen); error = xfs_bmap_add_attrfork(dp, sf_size, rsvd); if (error) return error; } tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + M_RES(mp)->tr_attrsetrt.tr_logres * args.total; tres.tr_logcount = XFS_ATTRSET_LOG_COUNT; tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; /* * Root fork attributes can use reserved data blocks for this * operation if necessary */ error = xfs_trans_alloc(mp, &tres, args.total, 0, rsvd ? XFS_TRANS_RESERVE : 0, &args.trans); if (error) return error; xfs_ilock(dp, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : XFS_QMOPT_RES_REGBLKS); if (error) goto out_trans_cancel; xfs_trans_ijoin(args.trans, dp, 0); error = xfs_attr_set_args(&args); if (error) goto out_trans_cancel; if (!args.trans) { /* shortform attribute has already been committed */ goto out_unlock; } /* * If this is a synchronous mount, make sure that the * transaction goes to disk before returning to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(args.trans); if ((flags & ATTR_KERNOTIME) == 0) xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); /* * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(args.trans); out_unlock: xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; out_trans_cancel: if (args.trans) xfs_trans_cancel(args.trans); goto out_unlock; } /* * Generic handler routine to remove a name from an attribute list. * Transitions attribute list from Btree to shortform as necessary. */ int xfs_attr_remove( struct xfs_inode *dp, const unsigned char *name, int flags) { struct xfs_mount *mp = dp->i_mount; struct xfs_da_args args; int error; XFS_STATS_INC(mp, xs_attr_remove); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return -EIO; error = xfs_attr_args_init(&args, dp, name, flags); if (error) return error; /* * we have no control over the attribute names that userspace passes us * to remove, so we have to allow the name lookup prior to attribute * removal to fail. */ args.op_flags = XFS_DA_OP_OKNOENT; error = xfs_qm_dqattach(dp); if (error) return error; /* * Root fork attributes can use reserved data blocks for this * operation if necessary */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm, XFS_ATTRRM_SPACE_RES(mp), 0, (flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0, &args.trans); if (error) return error; xfs_ilock(dp, XFS_ILOCK_EXCL); /* * No need to make quota reservations here. We expect to release some * blocks not allocate in the common case. */ xfs_trans_ijoin(args.trans, dp, 0); error = xfs_attr_remove_args(&args); if (error) goto out; /* * If this is a synchronous mount, make sure that the * transaction goes to disk before returning to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(args.trans); if ((flags & ATTR_KERNOTIME) == 0) xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); /* * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; out: if (args.trans) xfs_trans_cancel(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; } /*======================================================================== * External routines when attribute list is inside the inode *========================================================================*/ /* * Add a name to the shortform attribute list structure * This is the external routine. */ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args) { int newsize, forkoff, retval; trace_xfs_attr_sf_addname(args); retval = xfs_attr_shortform_lookup(args); if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { return retval; } else if (retval == -EEXIST) { if (args->flags & ATTR_CREATE) return retval; retval = xfs_attr_shortform_remove(args); if (retval) return retval; /* * Since we have removed the old attr, clear ATTR_REPLACE so * that the leaf format add routine won't trip over the attr * not being around. */ args->flags &= ~ATTR_REPLACE; } if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) return -ENOSPC; newsize = XFS_ATTR_SF_TOTSIZE(args->dp); newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); if (!forkoff) return -ENOSPC; xfs_attr_shortform_add(args, forkoff); return 0; } /*======================================================================== * External routines when attribute list is one block *========================================================================*/ /* * Add a name to the leaf attribute list structure * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ STATIC int xfs_attr_leaf_addname( struct xfs_da_args *args) { struct xfs_inode *dp; struct xfs_buf *bp; int retval, error, forkoff; trace_xfs_attr_leaf_addname(args); /* * Read the (only) block in the attribute list in. */ dp = args->dp; args->blkno = 0; error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; /* * Look up the given attribute in the leaf block. Figure out if * the given flags produce an error or call for an atomic rename. */ retval = xfs_attr3_leaf_lookup_int(bp, args); if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { xfs_trans_brelse(args->trans, bp); return retval; } else if (retval == -EEXIST) { if (args->flags & ATTR_CREATE) { /* pure create op */ xfs_trans_brelse(args->trans, bp); return retval; } trace_xfs_attr_leaf_replace(args); /* save the attribute state for later removal*/ args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ args->blkno2 = args->blkno; /* set 2nd entry info*/ args->index2 = args->index; args->rmtblkno2 = args->rmtblkno; args->rmtblkcnt2 = args->rmtblkcnt; args->rmtvaluelen2 = args->rmtvaluelen; /* * clear the remote attr state now that it is saved so that the * values reflect the state of the attribute we are about to * add, not the attribute we just found and will remove later. */ args->rmtblkno = 0; args->rmtblkcnt = 0; args->rmtvaluelen = 0; } /* * Add the attribute to the leaf block, transitioning to a Btree * if required. */ retval = xfs_attr3_leaf_add(bp, args); if (retval == -ENOSPC) { /* * Promote the attribute list to the Btree format, then * Commit that transaction so that the node_addname() call * can manage its own transactions. */ error = xfs_attr3_leaf_to_node(args); if (error) return error; error = xfs_defer_finish(&args->trans); if (error) return error; /* * Commit the current trans (including the inode) and start * a new one. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) return error; /* * Fob the whole rest of the problem off on the Btree code. */ error = xfs_attr_node_addname(args); return error; } /* * Commit the transaction that added the attr name so that * later routines can manage their own transactions. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) return error; /* * If there was an out-of-line value, allocate the blocks we * identified for its storage and copy the value. This is done * after we create the attribute so that we don't overflow the * maximum size of a transaction and/or hit a deadlock. */ if (args->rmtblkno > 0) { error = xfs_attr_rmtval_set(args); if (error) return error; } /* * If this is an atomic rename operation, we must "flip" the * incomplete flags on the "new" and "old" attribute/value pairs * so that one disappears and one appears atomically. Then we * must remove the "old" attribute/value pair. */ if (args->op_flags & XFS_DA_OP_RENAME) { /* * In a separate transaction, set the incomplete flag on the * "old" attr and clear the incomplete flag on the "new" attr. */ error = xfs_attr3_leaf_flipflags(args); if (error) return error; /* * Dismantle the "old" attribute/value pair by removing * a "remote" value (if it exists). */ args->index = args->index2; args->blkno = args->blkno2; args->rmtblkno = args->rmtblkno2; args->rmtblkcnt = args->rmtblkcnt2; args->rmtvaluelen = args->rmtvaluelen2; if (args->rmtblkno) { error = xfs_attr_rmtval_remove(args); if (error) return error; } /* * Read in the block containing the "old" attr, then * remove the "old" attr from that block (neat, huh!) */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; xfs_attr3_leaf_remove(bp, args); /* * If the result is small enough, shrink it all into the inode. */ if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); /* bp is gone due to xfs_da_shrink_inode */ if (error) return error; error = xfs_defer_finish(&args->trans); if (error) return error; } /* * Commit the remove and start the next trans in series. */ error = xfs_trans_roll_inode(&args->trans, dp); } else if (args->rmtblkno > 0) { /* * Added a "remote" value, just clear the incomplete flag. */ error = xfs_attr3_leaf_clearflag(args); } return error; } /* * Remove a name from the leaf attribute list structure * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ STATIC int xfs_attr_leaf_removename( struct xfs_da_args *args) { struct xfs_inode *dp; struct xfs_buf *bp; int error, forkoff; trace_xfs_attr_leaf_removename(args); /* * Remove the attribute. */ dp = args->dp; args->blkno = 0; error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; error = xfs_attr3_leaf_lookup_int(bp, args); if (error == -ENOATTR) { xfs_trans_brelse(args->trans, bp); return error; } xfs_attr3_leaf_remove(bp, args); /* * If the result is small enough, shrink it all into the inode. */ if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); /* bp is gone due to xfs_da_shrink_inode */ if (error) return error; error = xfs_defer_finish(&args->trans); if (error) return error; } return 0; } /* * Look up a name in a leaf attribute list structure. * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ STATIC int xfs_attr_leaf_get(xfs_da_args_t *args) { struct xfs_buf *bp; int error; trace_xfs_attr_leaf_get(args); args->blkno = 0; error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; error = xfs_attr3_leaf_lookup_int(bp, args); if (error != -EEXIST) { xfs_trans_brelse(args->trans, bp); return error; } error = xfs_attr3_leaf_getvalue(bp, args); xfs_trans_brelse(args->trans, bp); if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { error = xfs_attr_rmtval_get(args); } return error; } /*======================================================================== * External routines when attribute list size > geo->blksize *========================================================================*/ /* * Add a name to a Btree-format attribute list. * * This will involve walking down the Btree, and may involve splitting * leaf nodes and even splitting intermediate nodes up to and including * the root node (a special case of an intermediate node). * * "Remote" attribute values confuse the issue and atomic rename operations * add a whole extra layer of confusion on top of that. */ STATIC int xfs_attr_node_addname( struct xfs_da_args *args) { struct xfs_da_state *state; struct xfs_da_state_blk *blk; struct xfs_inode *dp; struct xfs_mount *mp; int retval, error; trace_xfs_attr_node_addname(args); /* * Fill in bucket of arguments/results/context to carry around. */ dp = args->dp; mp = dp->i_mount; restart: state = xfs_da_state_alloc(); state->args = args; state->mp = mp; /* * Search to see if name already exists, and get back a pointer * to where it should go. */ error = xfs_da3_node_lookup_int(state, &retval); if (error) goto out; blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { goto out; } else if (retval == -EEXIST) { if (args->flags & ATTR_CREATE) goto out; trace_xfs_attr_node_replace(args); /* save the attribute state for later removal*/ args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ args->blkno2 = args->blkno; /* set 2nd entry info*/ args->index2 = args->index; args->rmtblkno2 = args->rmtblkno; args->rmtblkcnt2 = args->rmtblkcnt; args->rmtvaluelen2 = args->rmtvaluelen; /* * clear the remote attr state now that it is saved so that the * values reflect the state of the attribute we are about to * add, not the attribute we just found and will remove later. */ args->rmtblkno = 0; args->rmtblkcnt = 0; args->rmtvaluelen = 0; } retval = xfs_attr3_leaf_add(blk->bp, state->args); if (retval == -ENOSPC) { if (state->path.active == 1) { /* * Its really a single leaf node, but it had * out-of-line values so it looked like it *might* * have been a b-tree. */ xfs_da_state_free(state); state = NULL; error = xfs_attr3_leaf_to_node(args); if (error) goto out; error = xfs_defer_finish(&args->trans); if (error) goto out; /* * Commit the node conversion and start the next * trans in the chain. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) goto out; goto restart; } /* * Split as many Btree elements as required. * This code tracks the new and old attr's location * in the index/blkno/rmtblkno/rmtblkcnt fields and * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. */ error = xfs_da3_split(state); if (error) goto out; error = xfs_defer_finish(&args->trans); if (error) goto out; } else { /* * Addition succeeded, update Btree hashvals. */ xfs_da3_fixhashpath(state, &state->path); } /* * Kill the state structure, we're done with it and need to * allow the buffers to come back later. */ xfs_da_state_free(state); state = NULL; /* * Commit the leaf addition or btree split and start the next * trans in the chain. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) goto out; /* * If there was an out-of-line value, allocate the blocks we * identified for its storage and copy the value. This is done * after we create the attribute so that we don't overflow the * maximum size of a transaction and/or hit a deadlock. */ if (args->rmtblkno > 0) { error = xfs_attr_rmtval_set(args); if (error) return error; } /* * If this is an atomic rename operation, we must "flip" the * incomplete flags on the "new" and "old" attribute/value pairs * so that one disappears and one appears atomically. Then we * must remove the "old" attribute/value pair. */ if (args->op_flags & XFS_DA_OP_RENAME) { /* * In a separate transaction, set the incomplete flag on the * "old" attr and clear the incomplete flag on the "new" attr. */ error = xfs_attr3_leaf_flipflags(args); if (error) goto out; /* * Dismantle the "old" attribute/value pair by removing * a "remote" value (if it exists). */ args->index = args->index2; args->blkno = args->blkno2; args->rmtblkno = args->rmtblkno2; args->rmtblkcnt = args->rmtblkcnt2; args->rmtvaluelen = args->rmtvaluelen2; if (args->rmtblkno) { error = xfs_attr_rmtval_remove(args); if (error) return error; } /* * Re-find the "old" attribute entry after any split ops. * The INCOMPLETE flag means that we will find the "old" * attr, not the "new" one. */ args->flags |= XFS_ATTR_INCOMPLETE; state = xfs_da_state_alloc(); state->args = args; state->mp = mp; state->inleaf = 0; error = xfs_da3_node_lookup_int(state, &retval); if (error) goto out; /* * Remove the name and update the hashvals in the tree. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); error = xfs_attr3_leaf_remove(blk->bp, args); xfs_da3_fixhashpath(state, &state->path); /* * Check to see if the tree needs to be collapsed. */ if (retval && (state->path.active > 1)) { error = xfs_da3_join(state); if (error) goto out; error = xfs_defer_finish(&args->trans); if (error) goto out; } /* * Commit and start the next trans in the chain. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) goto out; } else if (args->rmtblkno > 0) { /* * Added a "remote" value, just clear the incomplete flag. */ error = xfs_attr3_leaf_clearflag(args); if (error) goto out; } retval = error = 0; out: if (state) xfs_da_state_free(state); if (error) return error; return retval; } /* * Remove a name from a B-tree attribute list. * * This will involve walking down the Btree, and may involve joining * leaf nodes and even joining intermediate nodes up to and including * the root node (a special case of an intermediate node). */ STATIC int xfs_attr_node_removename( struct xfs_da_args *args) { struct xfs_da_state *state; struct xfs_da_state_blk *blk; struct xfs_inode *dp; struct xfs_buf *bp; int retval, error, forkoff; trace_xfs_attr_node_removename(args); /* * Tie a string around our finger to remind us where we are. */ dp = args->dp; state = xfs_da_state_alloc(); state->args = args; state->mp = dp->i_mount; /* * Search to see if name exists, and get back a pointer to it. */ error = xfs_da3_node_lookup_int(state, &retval); if (error || (retval != -EEXIST)) { if (error == 0) error = retval; goto out; } /* * If there is an out-of-line value, de-allocate the blocks. * This is done before we remove the attribute so that we don't * overflow the maximum size of a transaction and/or hit a deadlock. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->bp != NULL); ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); if (args->rmtblkno > 0) { /* * Fill in disk block numbers in the state structure * so that we can get the buffers back after we commit * several transactions in the following calls. */ error = xfs_attr_fillstate(state); if (error) goto out; /* * Mark the attribute as INCOMPLETE, then bunmapi() the * remote value. */ error = xfs_attr3_leaf_setflag(args); if (error) goto out; error = xfs_attr_rmtval_remove(args); if (error) goto out; /* * Refill the state structure with buffers, the prior calls * released our buffers. */ error = xfs_attr_refillstate(state); if (error) goto out; } /* * Remove the name and update the hashvals in the tree. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); retval = xfs_attr3_leaf_remove(blk->bp, args); xfs_da3_fixhashpath(state, &state->path); /* * Check to see if the tree needs to be collapsed. */ if (retval && (state->path.active > 1)) { error = xfs_da3_join(state); if (error) goto out; error = xfs_defer_finish(&args->trans); if (error) goto out; /* * Commit the Btree join operation and start a new trans. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) goto out; } /* * If the result is small enough, push it all into the inode. */ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { /* * Have to get rid of the copy of this dabuf in the state. */ ASSERT(state->path.active == 1); ASSERT(state->path.blk[0].bp); state->path.blk[0].bp = NULL; error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp); if (error) goto out; if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); /* bp is gone due to xfs_da_shrink_inode */ if (error) goto out; error = xfs_defer_finish(&args->trans); if (error) goto out; } else xfs_trans_brelse(args->trans, bp); } error = 0; out: xfs_da_state_free(state); return error; } /* * Fill in the disk block numbers in the state structure for the buffers * that are attached to the state structure. * This is done so that we can quickly reattach ourselves to those buffers * after some set of transaction commits have released these buffers. */ STATIC int xfs_attr_fillstate(xfs_da_state_t *state) { xfs_da_state_path_t *path; xfs_da_state_blk_t *blk; int level; trace_xfs_attr_fillstate(state->args); /* * Roll down the "path" in the state structure, storing the on-disk * block number for those buffers in the "path". */ path = &state->path; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->bp) { blk->disk_blkno = XFS_BUF_ADDR(blk->bp); blk->bp = NULL; } else { blk->disk_blkno = 0; } } /* * Roll down the "altpath" in the state structure, storing the on-disk * block number for those buffers in the "altpath". */ path = &state->altpath; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->bp) { blk->disk_blkno = XFS_BUF_ADDR(blk->bp); blk->bp = NULL; } else { blk->disk_blkno = 0; } } return 0; } /* * Reattach the buffers to the state structure based on the disk block * numbers stored in the state structure. * This is done after some set of transaction commits have released those * buffers from our grip. */ STATIC int xfs_attr_refillstate(xfs_da_state_t *state) { xfs_da_state_path_t *path; xfs_da_state_blk_t *blk; int level, error; trace_xfs_attr_refillstate(state->args); /* * Roll down the "path" in the state structure, storing the on-disk * block number for those buffers in the "path". */ path = &state->path; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->disk_blkno) { error = xfs_da3_node_read(state->args->trans, state->args->dp, blk->blkno, blk->disk_blkno, &blk->bp, XFS_ATTR_FORK); if (error) return error; } else { blk->bp = NULL; } } /* * Roll down the "altpath" in the state structure, storing the on-disk * block number for those buffers in the "altpath". */ path = &state->altpath; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->disk_blkno) { error = xfs_da3_node_read(state->args->trans, state->args->dp, blk->blkno, blk->disk_blkno, &blk->bp, XFS_ATTR_FORK); if (error) return error; } else { blk->bp = NULL; } } return 0; } /* * Look up a filename in a node attribute list. * * This routine gets called for any attribute fork that has more than one * block, ie: both true Btree attr lists and for single-leaf-blocks with * "remote" values taking up more blocks. */ STATIC int xfs_attr_node_get(xfs_da_args_t *args) { xfs_da_state_t *state; xfs_da_state_blk_t *blk; int error, retval; int i; trace_xfs_attr_node_get(args); state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * Search to see if name exists, and get back a pointer to it. */ error = xfs_da3_node_lookup_int(state, &retval); if (error) { retval = error; } else if (retval == -EEXIST) { blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->bp != NULL); ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); /* * Get the value, local or "remote" */ retval = xfs_attr3_leaf_getvalue(blk->bp, args); if (!retval && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { retval = xfs_attr_rmtval_get(args); } } /* * If not in a transaction, we have to release all the buffers. */ for (i = 0; i < state->path.active; i++) { xfs_trans_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } xfs_da_state_free(state); return retval; } /* Returns true if the attribute entry name is valid. */ bool xfs_attr_namecheck( const void *name, size_t length) { /* * MAXNAMELEN includes the trailing null, but (name/length) leave it * out, so use >= for the length check. */ if (length >= MAXNAMELEN) return false; /* There shouldn't be any nulls here */ return !memchr(name, 0, length); } xfsprogs-5.3.0/libxfs/xfs_attr.h0000644000175000017500000001345513570057155016556 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_ATTR_H__ #define __XFS_ATTR_H__ struct xfs_inode; struct xfs_da_args; struct xfs_attr_list_context; /* * Large attribute lists are structured around Btrees where all the data * elements are in the leaf nodes. Attribute names are hashed into an int, * then that int is used as the index into the Btree. Since the hashval * of an attribute name may not be unique, we may have duplicate keys. * The internal links in the Btree are logical block offsets into the file. * * Small attribute lists use a different format and are packed as tightly * as possible so as to fit into the literal area of the inode. */ /*======================================================================== * External interfaces *========================================================================*/ #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ #define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */ #define ATTR_SECURE 0x0008 /* use attrs in security namespace */ #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ #define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */ #define XFS_ATTR_FLAGS \ { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \ { ATTR_ROOT, "ROOT" }, \ { ATTR_TRUST, "TRUST" }, \ { ATTR_SECURE, "SECURE" }, \ { ATTR_CREATE, "CREATE" }, \ { ATTR_REPLACE, "REPLACE" }, \ { ATTR_KERNOTIME, "KERNOTIME" }, \ { ATTR_KERNOVAL, "KERNOVAL" }, \ { ATTR_INCOMPLETE, "INCOMPLETE" } /* * The maximum size (into the kernel or returned from the kernel) of an * attribute value or the buffer used for an attr_list() call. Larger * sizes will result in an ERANGE return code. */ #define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */ /* * Define how lists of attribute names are returned to the user from * the attr_list() call. A large, 32bit aligned, buffer is passed in * along with its size. We put an array of offsets at the top that each * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom. */ typedef struct attrlist { __s32 al_count; /* number of entries in attrlist */ __s32 al_more; /* T/F: more attrs (do call again) */ __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */ } attrlist_t; /* * Show the interesting info about one attribute. This is what the * al_offset[i] entry points to. */ typedef struct attrlist_ent { /* data from attr_list() */ __u32 a_valuelen; /* number bytes in value of attr */ char a_name[1]; /* attr name (NULL terminated) */ } attrlist_ent_t; /* * Given a pointer to the (char*) buffer containing the attr_list() result, * and an index, return a pointer to the indicated attribute in the buffer. */ #define ATTR_ENTRY(buffer, index) \ ((attrlist_ent_t *) \ &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) /* * Kernel-internal version of the attrlist cursor. */ typedef struct attrlist_cursor_kern { __u32 hashval; /* hash value of next entry to add */ __u32 blkno; /* block containing entry (suggestion) */ __u32 offset; /* offset in list of equal-hashvals */ __u16 pad1; /* padding to match user-level */ __u8 pad2; /* padding to match user-level */ __u8 initted; /* T/F: cursor has been initialized */ } attrlist_cursor_kern_t; /*======================================================================== * Structure used to pass context around among the routines. *========================================================================*/ /* void; state communicated via *context */ typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int, unsigned char *, int, int); typedef struct xfs_attr_list_context { struct xfs_trans *tp; struct xfs_inode *dp; /* inode */ struct attrlist_cursor_kern *cursor; /* position in list */ char *alist; /* output buffer */ /* * Abort attribute list iteration if non-zero. Can be used to pass * error values to the xfs_attr_list caller. */ int seen_enough; ssize_t count; /* num used entries */ int dupcnt; /* count dup hashvals seen */ int bufsize; /* total buffer size */ int firstu; /* first used byte in buffer */ int flags; /* from VOP call */ int resynch; /* T/F: resynch with cursor */ put_listent_func_t put_listent; /* list output fmt function */ int index; /* index into output buffer */ } xfs_attr_list_context_t; /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Overall external interface routines. */ int xfs_attr_inactive(struct xfs_inode *dp); int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *); int xfs_attr_list_int(struct xfs_attr_list_context *); int xfs_inode_hasattr(struct xfs_inode *ip); int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args); int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, unsigned char *value, int *valuelenp, int flags); int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags); int xfs_attr_set_args(struct xfs_da_args *args); int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_attr_remove_args(struct xfs_da_args *args); int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int flags, struct attrlist_cursor_kern *cursor); bool xfs_attr_namecheck(const void *name, size_t length); #endif /* __XFS_ATTR_H__ */ xfsprogs-5.3.0/libxfs/xfs_attr_leaf.c0000644000175000017500000024264313570057155017543 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap_btree.h" #include "xfs_bmap.h" #include "xfs_attr_sf.h" #include "xfs_attr_remote.h" #include "xfs_attr.h" #include "xfs_attr_leaf.h" #include "xfs_trace.h" #include "xfs_dir2.h" /* * xfs_attr_leaf.c * * Routines to implement leaf blocks of attributes as Btrees of hashed names. */ /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Routines used for growing the Btree. */ STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, struct xfs_buf **bpp); STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer, struct xfs_attr3_icleaf_hdr *ichdr, struct xfs_da_args *args, int freemap_index); STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args, struct xfs_attr3_icleaf_hdr *ichdr, struct xfs_buf *leaf_buffer); STATIC void xfs_attr3_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2); STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state, xfs_da_state_blk_t *leaf_blk_1, struct xfs_attr3_icleaf_hdr *ichdr1, xfs_da_state_blk_t *leaf_blk_2, struct xfs_attr3_icleaf_hdr *ichdr2, int *number_entries_in_blk1, int *number_usedbytes_in_blk1); /* * Utility routines. */ STATIC void xfs_attr3_leaf_moveents(struct xfs_da_args *args, struct xfs_attr_leafblock *src_leaf, struct xfs_attr3_icleaf_hdr *src_ichdr, int src_start, struct xfs_attr_leafblock *dst_leaf, struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start, int move_count); STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); /* * attr3 block 'firstused' conversion helpers. * * firstused refers to the offset of the first used byte of the nameval region * of an attr leaf block. The region starts at the tail of the block and expands * backwards towards the middle. As such, firstused is initialized to the block * size for an empty leaf block and is reduced from there. * * The attr3 block size is pegged to the fsb size and the maximum fsb is 64k. * The in-core firstused field is 32-bit and thus supports the maximum fsb size. * The on-disk field is only 16-bit, however, and overflows at 64k. Since this * only occurs at exactly 64k, we use zero as a magic on-disk value to represent * the attr block size. The following helpers manage the conversion between the * in-core and on-disk formats. */ static void xfs_attr3_leaf_firstused_from_disk( struct xfs_da_geometry *geo, struct xfs_attr3_icleaf_hdr *to, struct xfs_attr_leafblock *from) { struct xfs_attr3_leaf_hdr *hdr3; if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) { hdr3 = (struct xfs_attr3_leaf_hdr *) from; to->firstused = be16_to_cpu(hdr3->firstused); } else { to->firstused = be16_to_cpu(from->hdr.firstused); } /* * Convert from the magic fsb size value to actual blocksize. This * should only occur for empty blocks when the block size overflows * 16-bits. */ if (to->firstused == XFS_ATTR3_LEAF_NULLOFF) { ASSERT(!to->count && !to->usedbytes); ASSERT(geo->blksize > USHRT_MAX); to->firstused = geo->blksize; } } static void xfs_attr3_leaf_firstused_to_disk( struct xfs_da_geometry *geo, struct xfs_attr_leafblock *to, struct xfs_attr3_icleaf_hdr *from) { struct xfs_attr3_leaf_hdr *hdr3; uint32_t firstused; /* magic value should only be seen on disk */ ASSERT(from->firstused != XFS_ATTR3_LEAF_NULLOFF); /* * Scale down the 32-bit in-core firstused value to the 16-bit on-disk * value. This only overflows at the max supported value of 64k. Use the * magic on-disk value to represent block size in this case. */ firstused = from->firstused; if (firstused > USHRT_MAX) { ASSERT(from->firstused == geo->blksize); firstused = XFS_ATTR3_LEAF_NULLOFF; } if (from->magic == XFS_ATTR3_LEAF_MAGIC) { hdr3 = (struct xfs_attr3_leaf_hdr *) to; hdr3->firstused = cpu_to_be16(firstused); } else { to->hdr.firstused = cpu_to_be16(firstused); } } void xfs_attr3_leaf_hdr_from_disk( struct xfs_da_geometry *geo, struct xfs_attr3_icleaf_hdr *to, struct xfs_attr_leafblock *from) { int i; ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) { struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)from; to->forw = be32_to_cpu(hdr3->info.hdr.forw); to->back = be32_to_cpu(hdr3->info.hdr.back); to->magic = be16_to_cpu(hdr3->info.hdr.magic); to->count = be16_to_cpu(hdr3->count); to->usedbytes = be16_to_cpu(hdr3->usedbytes); xfs_attr3_leaf_firstused_from_disk(geo, to, from); to->holes = hdr3->holes; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { to->freemap[i].base = be16_to_cpu(hdr3->freemap[i].base); to->freemap[i].size = be16_to_cpu(hdr3->freemap[i].size); } return; } to->forw = be32_to_cpu(from->hdr.info.forw); to->back = be32_to_cpu(from->hdr.info.back); to->magic = be16_to_cpu(from->hdr.info.magic); to->count = be16_to_cpu(from->hdr.count); to->usedbytes = be16_to_cpu(from->hdr.usedbytes); xfs_attr3_leaf_firstused_from_disk(geo, to, from); to->holes = from->hdr.holes; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { to->freemap[i].base = be16_to_cpu(from->hdr.freemap[i].base); to->freemap[i].size = be16_to_cpu(from->hdr.freemap[i].size); } } void xfs_attr3_leaf_hdr_to_disk( struct xfs_da_geometry *geo, struct xfs_attr_leafblock *to, struct xfs_attr3_icleaf_hdr *from) { int i; ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC || from->magic == XFS_ATTR3_LEAF_MAGIC); if (from->magic == XFS_ATTR3_LEAF_MAGIC) { struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)to; hdr3->info.hdr.forw = cpu_to_be32(from->forw); hdr3->info.hdr.back = cpu_to_be32(from->back); hdr3->info.hdr.magic = cpu_to_be16(from->magic); hdr3->count = cpu_to_be16(from->count); hdr3->usedbytes = cpu_to_be16(from->usedbytes); xfs_attr3_leaf_firstused_to_disk(geo, to, from); hdr3->holes = from->holes; hdr3->pad1 = 0; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { hdr3->freemap[i].base = cpu_to_be16(from->freemap[i].base); hdr3->freemap[i].size = cpu_to_be16(from->freemap[i].size); } return; } to->hdr.info.forw = cpu_to_be32(from->forw); to->hdr.info.back = cpu_to_be32(from->back); to->hdr.info.magic = cpu_to_be16(from->magic); to->hdr.count = cpu_to_be16(from->count); to->hdr.usedbytes = cpu_to_be16(from->usedbytes); xfs_attr3_leaf_firstused_to_disk(geo, to, from); to->hdr.holes = from->holes; to->hdr.pad1 = 0; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { to->hdr.freemap[i].base = cpu_to_be16(from->freemap[i].base); to->hdr.freemap[i].size = cpu_to_be16(from->freemap[i].size); } } static xfs_failaddr_t xfs_attr3_leaf_verify( struct xfs_buf *bp) { struct xfs_attr3_icleaf_hdr ichdr; struct xfs_mount *mp = bp->b_mount; struct xfs_attr_leafblock *leaf = bp->b_addr; struct xfs_attr_leaf_entry *entries; uint32_t end; /* must be 32bit - see below */ int i; xfs_failaddr_t fa; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); fa = xfs_da3_blkinfo_verify(bp, bp->b_addr); if (fa) return fa; /* * In recovery there is a transient state where count == 0 is valid * because we may have transitioned an empty shortform attr to a leaf * if the attr didn't fit in shortform. */ if (!xfs_log_in_recovery(mp) && ichdr.count == 0) return __this_address; /* * firstused is the block offset of the first name info structure. * Make sure it doesn't go off the block or crash into the header. */ if (ichdr.firstused > mp->m_attr_geo->blksize) return __this_address; if (ichdr.firstused < xfs_attr3_leaf_hdr_size(leaf)) return __this_address; /* Make sure the entries array doesn't crash into the name info. */ entries = xfs_attr3_leaf_entryp(bp->b_addr); if ((char *)&entries[ichdr.count] > (char *)bp->b_addr + ichdr.firstused) return __this_address; /* XXX: need to range check rest of attr header values */ /* XXX: hash order check? */ /* * Quickly check the freemap information. Attribute data has to be * aligned to 4-byte boundaries, and likewise for the free space. * * Note that for 64k block size filesystems, the freemap entries cannot * overflow as they are only be16 fields. However, when checking end * pointer of the freemap, we have to be careful to detect overflows and * so use uint32_t for those checks. */ for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { if (ichdr.freemap[i].base > mp->m_attr_geo->blksize) return __this_address; if (ichdr.freemap[i].base & 0x3) return __this_address; if (ichdr.freemap[i].size > mp->m_attr_geo->blksize) return __this_address; if (ichdr.freemap[i].size & 0x3) return __this_address; /* be care of 16 bit overflows here */ end = (uint32_t)ichdr.freemap[i].base + ichdr.freemap[i].size; if (end < ichdr.freemap[i].base) return __this_address; if (end > mp->m_attr_geo->blksize) return __this_address; } return NULL; } static void xfs_attr3_leaf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_attr3_leaf_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF); } /* * leaf/node format detection on trees is sketchy, so a node read can be done on * leaf level blocks when detection identifies the tree as a node format tree * incorrectly. In this case, we need to swap the verifier to match the correct * format of the block being read. */ static void xfs_attr3_leaf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_attr3_leaf_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = { .name = "xfs_attr3_leaf", .magic16 = { cpu_to_be16(XFS_ATTR_LEAF_MAGIC), cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) }, .verify_read = xfs_attr3_leaf_read_verify, .verify_write = xfs_attr3_leaf_write_verify, .verify_struct = xfs_attr3_leaf_verify, }; int xfs_attr3_leaf_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops); if (!err && tp && *bpp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF); return err; } /*======================================================================== * Namespace helper routines *========================================================================*/ /* * If namespace bits don't match return 0. * If all match then return 1. */ STATIC int xfs_attr_namesp_match(int arg_flags, int ondisk_flags) { return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); } /*======================================================================== * External routines when attribute fork size < XFS_LITINO(mp). *========================================================================*/ /* * Query whether the requested number of additional bytes of extended * attribute space will be able to fit inline. * * Returns zero if not, else the di_forkoff fork offset to be used in the * literal area for attribute data once the new bytes have been added. * * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value; * special case for dev/uuid inodes, they have fixed size data forks. */ int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) { int offset; int minforkoff; /* lower limit on valid forkoff locations */ int maxforkoff; /* upper limit on valid forkoff locations */ int dsize; xfs_mount_t *mp = dp->i_mount; /* rounded down */ offset = (XFS_LITINO(mp, dp->i_d.di_version) - bytes) >> 3; if (dp->i_d.di_format == XFS_DINODE_FMT_DEV) { minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; return (offset >= minforkoff) ? minforkoff : 0; } /* * If the requested numbers of bytes is smaller or equal to the * current attribute fork size we can always proceed. * * Note that if_bytes in the data fork might actually be larger than * the current data fork size is due to delalloc extents. In that * case either the extent count will go down when they are converted * to real extents, or the delalloc conversion will take care of the * literal area rebalancing. */ if (bytes <= XFS_IFORK_ASIZE(dp)) return dp->i_d.di_forkoff; /* * For attr2 we can try to move the forkoff if there is space in the * literal area, but for the old format we are done if there is no * space in the fixed attribute fork. */ if (!(mp->m_flags & XFS_MOUNT_ATTR2)) return 0; dsize = dp->i_df.if_bytes; switch (dp->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: /* * If there is no attr fork and the data fork is extents, * determine if creating the default attr fork will result * in the extents form migrating to btree. If so, the * minimum offset only needs to be the space required for * the btree root. */ if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > xfs_default_attroffset(dp)) dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); break; case XFS_DINODE_FMT_BTREE: /* * If we have a data btree then keep forkoff if we have one, * otherwise we are adding a new attr, so then we set * minforkoff to where the btree root can finish so we have * plenty of room for attrs */ if (dp->i_d.di_forkoff) { if (offset < dp->i_d.di_forkoff) return 0; return dp->i_d.di_forkoff; } dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot); break; } /* * A data fork btree root must have space for at least * MINDBTPTRS key/ptr pairs if the data fork is small or empty. */ minforkoff = max(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); minforkoff = roundup(minforkoff, 8) >> 3; /* attr fork btree root can have at least this many key/ptr pairs */ maxforkoff = XFS_LITINO(mp, dp->i_d.di_version) - XFS_BMDR_SPACE_CALC(MINABTPTRS); maxforkoff = maxforkoff >> 3; /* rounded down */ if (offset >= maxforkoff) return maxforkoff; if (offset >= minforkoff) return offset; return 0; } /* * Switch on the ATTR2 superblock bit (implies also FEATURES2) */ STATIC void xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp) { if ((mp->m_flags & XFS_MOUNT_ATTR2) && !(xfs_sb_version_hasattr2(&mp->m_sb))) { spin_lock(&mp->m_sb_lock); if (!xfs_sb_version_hasattr2(&mp->m_sb)) { xfs_sb_version_addattr2(&mp->m_sb); spin_unlock(&mp->m_sb_lock); xfs_log_sb(tp); } else spin_unlock(&mp->m_sb_lock); } } /* * Create the initial contents of a shortform attribute list. */ void xfs_attr_shortform_create(xfs_da_args_t *args) { xfs_attr_sf_hdr_t *hdr; xfs_inode_t *dp; struct xfs_ifork *ifp; trace_xfs_attr_sf_create(args); dp = args->dp; ASSERT(dp != NULL); ifp = dp->i_afp; ASSERT(ifp != NULL); ASSERT(ifp->if_bytes == 0); if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; ifp->if_flags |= XFS_IFINLINE; } else { ASSERT(ifp->if_flags & XFS_IFINLINE); } xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; hdr->count = 0; hdr->totsize = cpu_to_be16(sizeof(*hdr)); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } /* * Add a name/value pair to the shortform attribute list. * Overflow from the inode has already been checked for. */ void xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i, offset, size; xfs_mount_t *mp; xfs_inode_t *dp; struct xfs_ifork *ifp; trace_xfs_attr_sf_add(args); dp = args->dp; mp = dp->i_mount; dp->i_d.di_forkoff = forkoff; ifp = dp->i_afp; ASSERT(ifp->if_flags & XFS_IFINLINE); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { #ifdef DEBUG if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; ASSERT(0); #endif } offset = (char *)sfe - (char *)sf; size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); xfs_idata_realloc(dp, size, XFS_ATTR_FORK); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); sfe->namelen = args->namelen; sfe->valuelen = args->valuelen; sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); memcpy(sfe->nameval, args->name, args->namelen); memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); sf->hdr.count++; be16_add_cpu(&sf->hdr.totsize, size); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); xfs_sbversion_add_attr2(mp, args->trans); } /* * After the last attribute is removed revert to original inode format, * making all literal area available to the data fork once more. */ void xfs_attr_fork_remove( struct xfs_inode *ip, struct xfs_trans *tp) { xfs_idestroy_fork(ip, XFS_ATTR_FORK); ip->i_d.di_forkoff = 0; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ASSERT(ip->i_d.di_anextents == 0); ASSERT(ip->i_afp == NULL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); } /* * Remove an attribute from the shortform attribute list structure. */ int xfs_attr_shortform_remove(xfs_da_args_t *args) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int base, size=0, end, totsize, i; xfs_mount_t *mp; xfs_inode_t *dp; trace_xfs_attr_sf_remove(args); dp = args->dp; mp = dp->i_mount; base = sizeof(xfs_attr_sf_hdr_t); sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; sfe = &sf->list[0]; end = sf->hdr.count; for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), base += size, i++) { size = XFS_ATTR_SF_ENTSIZE(sfe); if (sfe->namelen != args->namelen) continue; if (memcmp(sfe->nameval, args->name, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; break; } if (i == end) return -ENOATTR; /* * Fix up the attribute fork data, covering the hole */ end = base + size; totsize = be16_to_cpu(sf->hdr.totsize); if (end != totsize) memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end); sf->hdr.count--; be16_add_cpu(&sf->hdr.totsize, -size); /* * Fix up the start offset of the attribute fork */ totsize -= size; if (totsize == sizeof(xfs_attr_sf_hdr_t) && (mp->m_flags & XFS_MOUNT_ATTR2) && (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && !(args->op_flags & XFS_DA_OP_ADDNAME)) { xfs_attr_fork_remove(dp, args->trans); } else { xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); ASSERT(dp->i_d.di_forkoff); ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || (args->op_flags & XFS_DA_OP_ADDNAME) || !(mp->m_flags & XFS_MOUNT_ATTR2) || dp->i_d.di_format == XFS_DINODE_FMT_BTREE); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } xfs_sbversion_add_attr2(mp, args->trans); return 0; } /* * Look up a name in a shortform attribute list structure. */ /*ARGSUSED*/ int xfs_attr_shortform_lookup(xfs_da_args_t *args) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i; struct xfs_ifork *ifp; trace_xfs_attr_sf_lookup(args); ifp = args->dp->i_afp; ASSERT(ifp->if_flags & XFS_IFINLINE); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; return -EEXIST; } return -ENOATTR; } /* * Look up a name in a shortform attribute list structure. */ /*ARGSUSED*/ int xfs_attr_shortform_getvalue(xfs_da_args_t *args) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i; ASSERT(args->dp->i_afp->if_flags == XFS_IFINLINE); sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; if (args->flags & ATTR_KERNOVAL) { args->valuelen = sfe->valuelen; return -EEXIST; } if (args->valuelen < sfe->valuelen) { args->valuelen = sfe->valuelen; return -ERANGE; } args->valuelen = sfe->valuelen; memcpy(args->value, &sfe->nameval[args->namelen], args->valuelen); return -EEXIST; } return -ENOATTR; } /* * Convert from using the shortform to the leaf. On success, return the * buffer so that we can keep it locked until we're totally done with it. */ int xfs_attr_shortform_to_leaf( struct xfs_da_args *args, struct xfs_buf **leaf_bp) { struct xfs_inode *dp; struct xfs_attr_shortform *sf; struct xfs_attr_sf_entry *sfe; struct xfs_da_args nargs; char *tmpbuffer; int error, i, size; xfs_dablk_t blkno; struct xfs_buf *bp; struct xfs_ifork *ifp; trace_xfs_attr_sf_to_leaf(args); dp = args->dp; ifp = dp->i_afp; sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; size = be16_to_cpu(sf->hdr.totsize); tmpbuffer = kmem_alloc(size, KM_SLEEP); ASSERT(tmpbuffer != NULL); memcpy(tmpbuffer, ifp->if_u1.if_data, size); sf = (xfs_attr_shortform_t *)tmpbuffer; xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); xfs_bmap_local_to_extents_empty(dp, XFS_ATTR_FORK); bp = NULL; error = xfs_da_grow_inode(args, &blkno); if (error) { /* * If we hit an IO error middle of the transaction inside * grow_inode(), we may have inconsistent data. Bail out. */ if (error == -EIO) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ goto out; } ASSERT(blkno == 0); error = xfs_attr3_leaf_create(args, blkno, &bp); if (error) { /* xfs_attr3_leaf_create may not have instantiated a block */ if (bp && (xfs_da_shrink_inode(args, 0, bp) != 0)) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ goto out; } memset((char *)&nargs, 0, sizeof(nargs)); nargs.dp = dp; nargs.geo = args->geo; nargs.total = args->total; nargs.whichfork = XFS_ATTR_FORK; nargs.trans = args->trans; nargs.op_flags = XFS_DA_OP_OKNOENT; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; i++) { nargs.name = sfe->nameval; nargs.namelen = sfe->namelen; nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; nargs.hashval = xfs_da_hashname(sfe->nameval, sfe->namelen); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags); error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */ ASSERT(error == -ENOATTR); error = xfs_attr3_leaf_add(bp, &nargs); ASSERT(error != -ENOSPC); if (error) goto out; sfe = XFS_ATTR_SF_NEXTENTRY(sfe); } error = 0; *leaf_bp = bp; out: kmem_free(tmpbuffer); return error; } /* * Check a leaf attribute block to see if all the entries would fit into * a shortform attribute list. */ int xfs_attr_shortform_allfit( struct xfs_buf *bp, struct xfs_inode *dp) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; xfs_attr_leaf_name_local_t *name_loc; struct xfs_attr3_icleaf_hdr leafhdr; int bytes; int i; struct xfs_mount *mp = bp->b_mount; leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); entry = xfs_attr3_leaf_entryp(leaf); bytes = sizeof(struct xfs_attr_sf_hdr); for (i = 0; i < leafhdr.count; entry++, i++) { if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* don't copy partial entries */ if (!(entry->flags & XFS_ATTR_LOCAL)) return 0; name_loc = xfs_attr3_leaf_name_local(leaf, i); if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX) return 0; if (be16_to_cpu(name_loc->valuelen) >= XFS_ATTR_SF_ENTSIZE_MAX) return 0; bytes += sizeof(struct xfs_attr_sf_entry) - 1 + name_loc->namelen + be16_to_cpu(name_loc->valuelen); } if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) && (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && (bytes == sizeof(struct xfs_attr_sf_hdr))) return -1; return xfs_attr_shortform_bytesfit(dp, bytes); } /* Verify the consistency of an inline attribute fork. */ xfs_failaddr_t xfs_attr_shortform_verify( struct xfs_inode *ip) { struct xfs_attr_shortform *sfp; struct xfs_attr_sf_entry *sfep; struct xfs_attr_sf_entry *next_sfep; char *endp; struct xfs_ifork *ifp; int i; int size; ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL); ifp = XFS_IFORK_PTR(ip, XFS_ATTR_FORK); sfp = (struct xfs_attr_shortform *)ifp->if_u1.if_data; size = ifp->if_bytes; /* * Give up if the attribute is way too short. */ if (size < sizeof(struct xfs_attr_sf_hdr)) return __this_address; endp = (char *)sfp + size; /* Check all reported entries */ sfep = &sfp->list[0]; for (i = 0; i < sfp->hdr.count; i++) { /* * struct xfs_attr_sf_entry has a variable length. * Check the fixed-offset parts of the structure are * within the data buffer. */ if (((char *)sfep + sizeof(*sfep)) >= endp) return __this_address; /* Don't allow names with known bad length. */ if (sfep->namelen == 0) return __this_address; /* * Check that the variable-length part of the structure is * within the data buffer. The next entry starts after the * name component, so nextentry is an acceptable test. */ next_sfep = XFS_ATTR_SF_NEXTENTRY(sfep); if ((char *)next_sfep > endp) return __this_address; /* * Check for unknown flags. Short form doesn't support * the incomplete or local bits, so we can use the namespace * mask here. */ if (sfep->flags & ~XFS_ATTR_NSP_ONDISK_MASK) return __this_address; /* * Check for invalid namespace combinations. We only allow * one namespace flag per xattr, so we can just count the * bits (i.e. hweight) here. */ if (hweight8(sfep->flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) return __this_address; sfep = next_sfep; } if ((void *)sfep != (void *)endp) return __this_address; return NULL; } /* * Convert a leaf attribute list to shortform attribute list */ int xfs_attr3_leaf_to_shortform( struct xfs_buf *bp, struct xfs_da_args *args, int forkoff) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_local *name_loc; struct xfs_da_args nargs; struct xfs_inode *dp = args->dp; char *tmpbuffer; int error; int i; trace_xfs_attr_leaf_to_sf(args); tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP); if (!tmpbuffer) return -ENOMEM; memcpy(tmpbuffer, bp->b_addr, args->geo->blksize); leaf = (xfs_attr_leafblock_t *)tmpbuffer; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); entry = xfs_attr3_leaf_entryp(leaf); /* XXX (dgc): buffer is about to be marked stale - why zero it? */ memset(bp->b_addr, 0, args->geo->blksize); /* * Clean out the prior contents of the attribute list. */ error = xfs_da_shrink_inode(args, 0, bp); if (error) goto out; if (forkoff == -1) { ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); xfs_attr_fork_remove(dp, args->trans); goto out; } xfs_attr_shortform_create(args); /* * Copy the attributes */ memset((char *)&nargs, 0, sizeof(nargs)); nargs.geo = args->geo; nargs.dp = dp; nargs.total = args->total; nargs.whichfork = XFS_ATTR_FORK; nargs.trans = args->trans; nargs.op_flags = XFS_DA_OP_OKNOENT; for (i = 0; i < ichdr.count; entry++, i++) { if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* don't copy partial entries */ if (!entry->nameidx) continue; ASSERT(entry->flags & XFS_ATTR_LOCAL); name_loc = xfs_attr3_leaf_name_local(leaf, i); nargs.name = name_loc->nameval; nargs.namelen = name_loc->namelen; nargs.value = &name_loc->nameval[nargs.namelen]; nargs.valuelen = be16_to_cpu(name_loc->valuelen); nargs.hashval = be32_to_cpu(entry->hashval); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags); xfs_attr_shortform_add(&nargs, forkoff); } error = 0; out: kmem_free(tmpbuffer); return error; } /* * Convert from using a single leaf to a root node and a leaf. */ int xfs_attr3_leaf_to_node( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr icleafhdr; struct xfs_attr_leaf_entry *entries; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr icnodehdr; struct xfs_da_intnode *node; struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp1 = NULL; struct xfs_buf *bp2 = NULL; xfs_dablk_t blkno; int error; trace_xfs_attr_leaf_to_node(args); error = xfs_da_grow_inode(args, &blkno); if (error) goto out; error = xfs_attr3_leaf_read(args->trans, dp, 0, -1, &bp1); if (error) goto out; error = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp2, XFS_ATTR_FORK); if (error) goto out; /* copy leaf to new buffer, update identifiers */ xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF); bp2->b_ops = bp1->b_ops; memcpy(bp2->b_addr, bp1->b_addr, args->geo->blksize); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_blkinfo *hdr3 = bp2->b_addr; hdr3->blkno = cpu_to_be64(bp2->b_bn); } xfs_trans_log_buf(args->trans, bp2, 0, args->geo->blksize - 1); /* * Set up the new root node. */ error = xfs_da3_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); if (error) goto out; node = bp1->b_addr; dp->d_ops->node_hdr_from_disk(&icnodehdr, node); btree = dp->d_ops->node_tree_p(node); leaf = bp2->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &icleafhdr, leaf); entries = xfs_attr3_leaf_entryp(leaf); /* both on-disk, don't endian-flip twice */ btree[0].hashval = entries[icleafhdr.count - 1].hashval; btree[0].before = cpu_to_be32(blkno); icnodehdr.count = 1; dp->d_ops->node_hdr_to_disk(node, &icnodehdr); xfs_trans_log_buf(args->trans, bp1, 0, args->geo->blksize - 1); error = 0; out: return error; } /*======================================================================== * Routines used for growing the Btree. *========================================================================*/ /* * Create the initial contents of a leaf attribute list * or a leaf in a node attribute list. */ STATIC int xfs_attr3_leaf_create( struct xfs_da_args *args, xfs_dablk_t blkno, struct xfs_buf **bpp) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp; int error; trace_xfs_attr_leaf_create(args); error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, XFS_ATTR_FORK); if (error) return error; bp->b_ops = &xfs_attr3_leaf_buf_ops; xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF); leaf = bp->b_addr; memset(leaf, 0, args->geo->blksize); memset(&ichdr, 0, sizeof(ichdr)); ichdr.firstused = args->geo->blksize; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_blkinfo *hdr3 = bp->b_addr; ichdr.magic = XFS_ATTR3_LEAF_MAGIC; hdr3->blkno = cpu_to_be64(bp->b_bn); hdr3->owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr); } else { ichdr.magic = XFS_ATTR_LEAF_MAGIC; ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); } ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1); *bpp = bp; return 0; } /* * Split the leaf node, rebalance, then add the new entry. */ int xfs_attr3_leaf_split( struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk) { xfs_dablk_t blkno; int error; trace_xfs_attr_leaf_split(state->args); /* * Allocate space for a new leaf node. */ ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); error = xfs_da_grow_inode(state->args, &blkno); if (error) return error; error = xfs_attr3_leaf_create(state->args, blkno, &newblk->bp); if (error) return error; newblk->blkno = blkno; newblk->magic = XFS_ATTR_LEAF_MAGIC; /* * Rebalance the entries across the two leaves. * NOTE: rebalance() currently depends on the 2nd block being empty. */ xfs_attr3_leaf_rebalance(state, oldblk, newblk); error = xfs_da3_blk_link(state, oldblk, newblk); if (error) return error; /* * Save info on "old" attribute for "atomic rename" ops, leaf_add() * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the * "new" attrs info. Will need the "old" info to remove it later. * * Insert the "new" entry in the correct block. */ if (state->inleaf) { trace_xfs_attr_leaf_add_old(state->args); error = xfs_attr3_leaf_add(oldblk->bp, state->args); } else { trace_xfs_attr_leaf_add_new(state->args); error = xfs_attr3_leaf_add(newblk->bp, state->args); } /* * Update last hashval in each block since we added the name. */ oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); return error; } /* * Add a name to the leaf attribute list structure. */ int xfs_attr3_leaf_add( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; int tablesize; int entsize; int sum; int tmp; int i; trace_xfs_attr_leaf_add(args); leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(args->index >= 0 && args->index <= ichdr.count); entsize = xfs_attr_leaf_newentsize(args, NULL); /* * Search through freemap for first-fit on new name length. * (may need to figure in size of entry struct too) */ tablesize = (ichdr.count + 1) * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf); for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE - 1; i >= 0; i--) { if (tablesize > ichdr.firstused) { sum += ichdr.freemap[i].size; continue; } if (!ichdr.freemap[i].size) continue; /* no space in this map */ tmp = entsize; if (ichdr.freemap[i].base < ichdr.firstused) tmp += sizeof(xfs_attr_leaf_entry_t); if (ichdr.freemap[i].size >= tmp) { tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i); goto out_log_hdr; } sum += ichdr.freemap[i].size; } /* * If there are no holes in the address space of the block, * and we don't have enough freespace, then compaction will do us * no good and we should just give up. */ if (!ichdr.holes && sum < entsize) return -ENOSPC; /* * Compact the entries to coalesce free space. * This may change the hdr->count via dropping INCOMPLETE entries. */ xfs_attr3_leaf_compact(args, &ichdr, bp); /* * After compaction, the block is guaranteed to have only one * free region, in freemap[0]. If it is not big enough, give up. */ if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) { tmp = -ENOSPC; goto out_log_hdr; } tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0); out_log_hdr: xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, &leaf->hdr, xfs_attr3_leaf_hdr_size(leaf))); return tmp; } /* * Add a name to a leaf attribute list structure. */ STATIC int xfs_attr3_leaf_add_work( struct xfs_buf *bp, struct xfs_attr3_icleaf_hdr *ichdr, struct xfs_da_args *args, int mapindex) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_mount *mp; int tmp; int i; trace_xfs_attr_leaf_add_work(args); leaf = bp->b_addr; ASSERT(mapindex >= 0 && mapindex < XFS_ATTR_LEAF_MAPSIZE); ASSERT(args->index >= 0 && args->index <= ichdr->count); /* * Force open some space in the entry array and fill it in. */ entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; if (args->index < ichdr->count) { tmp = ichdr->count - args->index; tmp *= sizeof(xfs_attr_leaf_entry_t); memmove(entry + 1, entry, tmp); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); } ichdr->count++; /* * Allocate space for the new string (at the end of the run). */ mp = args->trans->t_mountp; ASSERT(ichdr->freemap[mapindex].base < args->geo->blksize); ASSERT((ichdr->freemap[mapindex].base & 0x3) == 0); ASSERT(ichdr->freemap[mapindex].size >= xfs_attr_leaf_newentsize(args, NULL)); ASSERT(ichdr->freemap[mapindex].size < args->geo->blksize); ASSERT((ichdr->freemap[mapindex].size & 0x3) == 0); ichdr->freemap[mapindex].size -= xfs_attr_leaf_newentsize(args, &tmp); entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base + ichdr->freemap[mapindex].size); entry->hashval = cpu_to_be32(args->hashval); entry->flags = tmp ? XFS_ATTR_LOCAL : 0; entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); if (args->op_flags & XFS_DA_OP_RENAME) { entry->flags |= XFS_ATTR_INCOMPLETE; if ((args->blkno2 == args->blkno) && (args->index2 <= args->index)) { args->index2++; } } xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); ASSERT((args->index == 0) || (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval))); ASSERT((args->index == ichdr->count - 1) || (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval))); /* * For "remote" attribute values, simply note that we need to * allocate space for the "remote" value. We can't actually * allocate the extents in this transaction, and we can't decide * which blocks they should be as we might allocate more blocks * as part of this transaction (a split operation for example). */ if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, args->index); name_loc->namelen = args->namelen; name_loc->valuelen = cpu_to_be16(args->valuelen); memcpy((char *)name_loc->nameval, args->name, args->namelen); memcpy((char *)&name_loc->nameval[args->namelen], args->value, be16_to_cpu(name_loc->valuelen)); } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); name_rmt->namelen = args->namelen; memcpy((char *)name_rmt->name, args->name, args->namelen); entry->flags |= XFS_ATTR_INCOMPLETE; /* just in case */ name_rmt->valuelen = 0; name_rmt->valueblk = 0; args->rmtblkno = 1; args->rmtblkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); args->rmtvaluelen = args->valuelen; } xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), xfs_attr_leaf_entsize(leaf, args->index))); /* * Update the control info for this leaf node */ if (be16_to_cpu(entry->nameidx) < ichdr->firstused) ichdr->firstused = be16_to_cpu(entry->nameidx); ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf)); tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { if (ichdr->freemap[i].base == tmp) { ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t); ichdr->freemap[i].size -= sizeof(xfs_attr_leaf_entry_t); } } ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index); return 0; } /* * Garbage collect a leaf attribute list block by copying it to a new buffer. */ STATIC void xfs_attr3_leaf_compact( struct xfs_da_args *args, struct xfs_attr3_icleaf_hdr *ichdr_dst, struct xfs_buf *bp) { struct xfs_attr_leafblock *leaf_src; struct xfs_attr_leafblock *leaf_dst; struct xfs_attr3_icleaf_hdr ichdr_src; struct xfs_trans *trans = args->trans; char *tmpbuffer; trace_xfs_attr_leaf_compact(args); tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP); memcpy(tmpbuffer, bp->b_addr, args->geo->blksize); memset(bp->b_addr, 0, args->geo->blksize); leaf_src = (xfs_attr_leafblock_t *)tmpbuffer; leaf_dst = bp->b_addr; /* * Copy the on-disk header back into the destination buffer to ensure * all the information in the header that is not part of the incore * header structure is preserved. */ memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src)); /* Initialise the incore headers */ ichdr_src = *ichdr_dst; /* struct copy */ ichdr_dst->firstused = args->geo->blksize; ichdr_dst->usedbytes = 0; ichdr_dst->count = 0; ichdr_dst->holes = 0; ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src); ichdr_dst->freemap[0].size = ichdr_dst->firstused - ichdr_dst->freemap[0].base; /* write the header back to initialise the underlying buffer */ xfs_attr3_leaf_hdr_to_disk(args->geo, leaf_dst, ichdr_dst); /* * Copy all entry's in the same (sorted) order, * but allocate name/value pairs packed and in sequence. */ xfs_attr3_leaf_moveents(args, leaf_src, &ichdr_src, 0, leaf_dst, ichdr_dst, 0, ichdr_src.count); /* * this logs the entire buffer, but the caller must write the header * back to the buffer when it is finished modifying it. */ xfs_trans_log_buf(trans, bp, 0, args->geo->blksize - 1); kmem_free(tmpbuffer); } /* * Compare two leaf blocks "order". * Return 0 unless leaf2 should go before leaf1. */ static int xfs_attr3_leaf_order( struct xfs_buf *leaf1_bp, struct xfs_attr3_icleaf_hdr *leaf1hdr, struct xfs_buf *leaf2_bp, struct xfs_attr3_icleaf_hdr *leaf2hdr) { struct xfs_attr_leaf_entry *entries1; struct xfs_attr_leaf_entry *entries2; entries1 = xfs_attr3_leaf_entryp(leaf1_bp->b_addr); entries2 = xfs_attr3_leaf_entryp(leaf2_bp->b_addr); if (leaf1hdr->count > 0 && leaf2hdr->count > 0 && ((be32_to_cpu(entries2[0].hashval) < be32_to_cpu(entries1[0].hashval)) || (be32_to_cpu(entries2[leaf2hdr->count - 1].hashval) < be32_to_cpu(entries1[leaf1hdr->count - 1].hashval)))) { return 1; } return 0; } int xfs_attr_leaf_order( struct xfs_buf *leaf1_bp, struct xfs_buf *leaf2_bp) { struct xfs_attr3_icleaf_hdr ichdr1; struct xfs_attr3_icleaf_hdr ichdr2; struct xfs_mount *mp = leaf1_bp->b_mount; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr1, leaf1_bp->b_addr); xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr2, leaf2_bp->b_addr); return xfs_attr3_leaf_order(leaf1_bp, &ichdr1, leaf2_bp, &ichdr2); } /* * Redistribute the attribute list entries between two leaf nodes, * taking into account the size of the new entry. * * NOTE: if new block is empty, then it will get the upper half of the * old block. At present, all (one) callers pass in an empty second block. * * This code adjusts the args->index/blkno and args->index2/blkno2 fields * to match what it is doing in splitting the attribute leaf block. Those * values are used in "atomic rename" operations on attributes. Note that * the "new" and "old" values can end up in different blocks. */ STATIC void xfs_attr3_leaf_rebalance( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_da_state_blk *blk2) { struct xfs_da_args *args; struct xfs_attr_leafblock *leaf1; struct xfs_attr_leafblock *leaf2; struct xfs_attr3_icleaf_hdr ichdr1; struct xfs_attr3_icleaf_hdr ichdr2; struct xfs_attr_leaf_entry *entries1; struct xfs_attr_leaf_entry *entries2; int count; int totallen; int max; int space; int swap; /* * Set up environment. */ ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); leaf1 = blk1->bp->b_addr; leaf2 = blk2->bp->b_addr; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr1, leaf1); xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, leaf2); ASSERT(ichdr2.count == 0); args = state->args; trace_xfs_attr_leaf_rebalance(args); /* * Check ordering of blocks, reverse if it makes things simpler. * * NOTE: Given that all (current) callers pass in an empty * second block, this code should never set "swap". */ swap = 0; if (xfs_attr3_leaf_order(blk1->bp, &ichdr1, blk2->bp, &ichdr2)) { swap(blk1, blk2); /* swap structures rather than reconverting them */ swap(ichdr1, ichdr2); leaf1 = blk1->bp->b_addr; leaf2 = blk2->bp->b_addr; swap = 1; } /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. Then get * the direction to copy and the number of elements to move. * * "inleaf" is true if the new entry should be inserted into blk1. * If "swap" is also true, then reverse the sense of "inleaf". */ state->inleaf = xfs_attr3_leaf_figure_balance(state, blk1, &ichdr1, blk2, &ichdr2, &count, &totallen); if (swap) state->inleaf = !state->inleaf; /* * Move any entries required from leaf to leaf: */ if (count < ichdr1.count) { /* * Figure the total bytes to be added to the destination leaf. */ /* number entries being moved */ count = ichdr1.count - count; space = ichdr1.usedbytes - totallen; space += count * sizeof(xfs_attr_leaf_entry_t); /* * leaf2 is the destination, compact it if it looks tight. */ max = ichdr2.firstused - xfs_attr3_leaf_hdr_size(leaf1); max -= ichdr2.count * sizeof(xfs_attr_leaf_entry_t); if (space > max) xfs_attr3_leaf_compact(args, &ichdr2, blk2->bp); /* * Move high entries from leaf1 to low end of leaf2. */ xfs_attr3_leaf_moveents(args, leaf1, &ichdr1, ichdr1.count - count, leaf2, &ichdr2, 0, count); } else if (count > ichdr1.count) { /* * I assert that since all callers pass in an empty * second buffer, this code should never execute. */ ASSERT(0); /* * Figure the total bytes to be added to the destination leaf. */ /* number entries being moved */ count -= ichdr1.count; space = totallen - ichdr1.usedbytes; space += count * sizeof(xfs_attr_leaf_entry_t); /* * leaf1 is the destination, compact it if it looks tight. */ max = ichdr1.firstused - xfs_attr3_leaf_hdr_size(leaf1); max -= ichdr1.count * sizeof(xfs_attr_leaf_entry_t); if (space > max) xfs_attr3_leaf_compact(args, &ichdr1, blk1->bp); /* * Move low entries from leaf2 to high end of leaf1. */ xfs_attr3_leaf_moveents(args, leaf2, &ichdr2, 0, leaf1, &ichdr1, ichdr1.count, count); } xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf1, &ichdr1); xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf2, &ichdr2); xfs_trans_log_buf(args->trans, blk1->bp, 0, args->geo->blksize - 1); xfs_trans_log_buf(args->trans, blk2->bp, 0, args->geo->blksize - 1); /* * Copy out last hashval in each block for B-tree code. */ entries1 = xfs_attr3_leaf_entryp(leaf1); entries2 = xfs_attr3_leaf_entryp(leaf2); blk1->hashval = be32_to_cpu(entries1[ichdr1.count - 1].hashval); blk2->hashval = be32_to_cpu(entries2[ichdr2.count - 1].hashval); /* * Adjust the expected index for insertion. * NOTE: this code depends on the (current) situation that the * second block was originally empty. * * If the insertion point moved to the 2nd block, we must adjust * the index. We must also track the entry just following the * new entry for use in an "atomic rename" operation, that entry * is always the "old" entry and the "new" entry is what we are * inserting. The index/blkno fields refer to the "old" entry, * while the index2/blkno2 fields refer to the "new" entry. */ if (blk1->index > ichdr1.count) { ASSERT(state->inleaf == 0); blk2->index = blk1->index - ichdr1.count; args->index = args->index2 = blk2->index; args->blkno = args->blkno2 = blk2->blkno; } else if (blk1->index == ichdr1.count) { if (state->inleaf) { args->index = blk1->index; args->blkno = blk1->blkno; args->index2 = 0; args->blkno2 = blk2->blkno; } else { /* * On a double leaf split, the original attr location * is already stored in blkno2/index2, so don't * overwrite it overwise we corrupt the tree. */ blk2->index = blk1->index - ichdr1.count; args->index = blk2->index; args->blkno = blk2->blkno; if (!state->extravalid) { /* * set the new attr location to match the old * one and let the higher level split code * decide where in the leaf to place it. */ args->index2 = blk2->index; args->blkno2 = blk2->blkno; } } } else { ASSERT(state->inleaf == 1); args->index = args->index2 = blk1->index; args->blkno = args->blkno2 = blk1->blkno; } } /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. * GROT: Is this really necessary? With other than a 512 byte blocksize, * GROT: there will always be enough room in either block for a new entry. * GROT: Do a double-split for this case? */ STATIC int xfs_attr3_leaf_figure_balance( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_attr3_icleaf_hdr *ichdr1, struct xfs_da_state_blk *blk2, struct xfs_attr3_icleaf_hdr *ichdr2, int *countarg, int *usedbytesarg) { struct xfs_attr_leafblock *leaf1 = blk1->bp->b_addr; struct xfs_attr_leafblock *leaf2 = blk2->bp->b_addr; struct xfs_attr_leaf_entry *entry; int count; int max; int index; int totallen = 0; int half; int lastdelta; int foundit = 0; int tmp; /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. */ max = ichdr1->count + ichdr2->count; half = (max + 1) * sizeof(*entry); half += ichdr1->usedbytes + ichdr2->usedbytes + xfs_attr_leaf_newentsize(state->args, NULL); half /= 2; lastdelta = state->args->geo->blksize; entry = xfs_attr3_leaf_entryp(leaf1); for (count = index = 0; count < max; entry++, index++, count++) { #define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) /* * The new entry is in the first block, account for it. */ if (count == blk1->index) { tmp = totallen + sizeof(*entry) + xfs_attr_leaf_newentsize(state->args, NULL); if (XFS_ATTR_ABS(half - tmp) > lastdelta) break; lastdelta = XFS_ATTR_ABS(half - tmp); totallen = tmp; foundit = 1; } /* * Wrap around into the second block if necessary. */ if (count == ichdr1->count) { leaf1 = leaf2; entry = xfs_attr3_leaf_entryp(leaf1); index = 0; } /* * Figure out if next leaf entry would be too much. */ tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, index); if (XFS_ATTR_ABS(half - tmp) > lastdelta) break; lastdelta = XFS_ATTR_ABS(half - tmp); totallen = tmp; #undef XFS_ATTR_ABS } /* * Calculate the number of usedbytes that will end up in lower block. * If new entry not in lower block, fix up the count. */ totallen -= count * sizeof(*entry); if (foundit) { totallen -= sizeof(*entry) + xfs_attr_leaf_newentsize(state->args, NULL); } *countarg = count; *usedbytesarg = totallen; return foundit; } /*======================================================================== * Routines used for shrinking the Btree. *========================================================================*/ /* * Check a leaf block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. * * GROT: allow for INCOMPLETE entries in calculation. */ int xfs_attr3_leaf_toosmall( struct xfs_da_state *state, int *action) { struct xfs_attr_leafblock *leaf; struct xfs_da_state_blk *blk; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_buf *bp; xfs_dablk_t blkno; int bytes; int forward; int error; int retval; int i; trace_xfs_attr_leaf_toosmall(state->args); /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[ state->path.active-1 ]; leaf = blk->bp->b_addr; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr, leaf); bytes = xfs_attr3_leaf_hdr_size(leaf) + ichdr.count * sizeof(xfs_attr_leaf_entry_t) + ichdr.usedbytes; if (bytes > (state->args->geo->blksize >> 1)) { *action = 0; /* blk over 50%, don't try to join */ return 0; } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (arbitrarily) * to merge with the forward block unless it is NULL. */ if (ichdr.count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (ichdr.forw != 0); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); if (error) return error; if (retval) { *action = 0; } else { *action = 2; } return 0; } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink an attribute list over time. */ /* start with smaller blk num */ forward = ichdr.forw < ichdr.back; for (i = 0; i < 2; forward = !forward, i++) { struct xfs_attr3_icleaf_hdr ichdr2; if (forward) blkno = ichdr.forw; else blkno = ichdr.back; if (blkno == 0) continue; error = xfs_attr3_leaf_read(state->args->trans, state->args->dp, blkno, -1, &bp); if (error) return error; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, bp->b_addr); bytes = state->args->geo->blksize - (state->args->geo->blksize >> 2) - ichdr.usedbytes - ichdr2.usedbytes - ((ichdr.count + ichdr2.count) * sizeof(xfs_attr_leaf_entry_t)) - xfs_attr3_leaf_hdr_size(leaf); xfs_trans_brelse(state->args->trans, bp); if (bytes >= 0) break; /* fits with at least 25% to spare */ } if (i >= 2) { *action = 0; return 0; } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) { error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); } else { error = xfs_da3_path_shift(state, &state->path, forward, 0, &retval); } if (error) return error; if (retval) { *action = 0; } else { *action = 1; } return 0; } /* * Remove a name from the leaf attribute list structure. * * Return 1 if leaf is less than 37% full, 0 if >= 37% full. * If two leaves are 37% full, when combined they will leave 25% free. */ int xfs_attr3_leaf_remove( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; int before; int after; int smallest; int entsize; int tablesize; int tmp; int i; trace_xfs_attr_leaf_remove(args); leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(ichdr.count > 0 && ichdr.count < args->geo->blksize / 8); ASSERT(args->index >= 0 && args->index < ichdr.count); ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) + xfs_attr3_leaf_hdr_size(leaf)); entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused); ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize); /* * Scan through free region table: * check for adjacency of free'd entry with an existing one, * find smallest free region in case we need to replace it, * adjust any map that borders the entry table, */ tablesize = ichdr.count * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf); tmp = ichdr.freemap[0].size; before = after = -1; smallest = XFS_ATTR_LEAF_MAPSIZE - 1; entsize = xfs_attr_leaf_entsize(leaf, args->index); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { ASSERT(ichdr.freemap[i].base < args->geo->blksize); ASSERT(ichdr.freemap[i].size < args->geo->blksize); if (ichdr.freemap[i].base == tablesize) { ichdr.freemap[i].base -= sizeof(xfs_attr_leaf_entry_t); ichdr.freemap[i].size += sizeof(xfs_attr_leaf_entry_t); } if (ichdr.freemap[i].base + ichdr.freemap[i].size == be16_to_cpu(entry->nameidx)) { before = i; } else if (ichdr.freemap[i].base == (be16_to_cpu(entry->nameidx) + entsize)) { after = i; } else if (ichdr.freemap[i].size < tmp) { tmp = ichdr.freemap[i].size; smallest = i; } } /* * Coalesce adjacent freemap regions, * or replace the smallest region. */ if ((before >= 0) || (after >= 0)) { if ((before >= 0) && (after >= 0)) { ichdr.freemap[before].size += entsize; ichdr.freemap[before].size += ichdr.freemap[after].size; ichdr.freemap[after].base = 0; ichdr.freemap[after].size = 0; } else if (before >= 0) { ichdr.freemap[before].size += entsize; } else { ichdr.freemap[after].base = be16_to_cpu(entry->nameidx); ichdr.freemap[after].size += entsize; } } else { /* * Replace smallest region (if it is smaller than free'd entry) */ if (ichdr.freemap[smallest].size < entsize) { ichdr.freemap[smallest].base = be16_to_cpu(entry->nameidx); ichdr.freemap[smallest].size = entsize; } } /* * Did we remove the first entry? */ if (be16_to_cpu(entry->nameidx) == ichdr.firstused) smallest = 1; else smallest = 0; /* * Compress the remaining entries and zero out the removed stuff. */ memset(xfs_attr3_leaf_name(leaf, args->index), 0, entsize); ichdr.usedbytes -= entsize; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), entsize)); tmp = (ichdr.count - args->index) * sizeof(xfs_attr_leaf_entry_t); memmove(entry, entry + 1, tmp); ichdr.count--; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(xfs_attr_leaf_entry_t))); entry = &xfs_attr3_leaf_entryp(leaf)[ichdr.count]; memset(entry, 0, sizeof(xfs_attr_leaf_entry_t)); /* * If we removed the first entry, re-find the first used byte * in the name area. Note that if the entry was the "firstused", * then we don't have a "hole" in our block resulting from * removing the name. */ if (smallest) { tmp = args->geo->blksize; entry = xfs_attr3_leaf_entryp(leaf); for (i = ichdr.count - 1; i >= 0; entry++, i--) { ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused); ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize); if (be16_to_cpu(entry->nameidx) < tmp) tmp = be16_to_cpu(entry->nameidx); } ichdr.firstused = tmp; ASSERT(ichdr.firstused != 0); } else { ichdr.holes = 1; /* mark as needing compaction */ } xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, &leaf->hdr, xfs_attr3_leaf_hdr_size(leaf))); /* * Check if leaf is less than 50% full, caller may want to * "join" the leaf with a sibling if so. */ tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) + ichdr.count * sizeof(xfs_attr_leaf_entry_t); return tmp < args->geo->magicpct; /* leaf is < 37% full */ } /* * Move all the attribute list entries from drop_leaf into save_leaf. */ void xfs_attr3_leaf_unbalance( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk) { struct xfs_attr_leafblock *drop_leaf = drop_blk->bp->b_addr; struct xfs_attr_leafblock *save_leaf = save_blk->bp->b_addr; struct xfs_attr3_icleaf_hdr drophdr; struct xfs_attr3_icleaf_hdr savehdr; struct xfs_attr_leaf_entry *entry; trace_xfs_attr_leaf_unbalance(state->args); drop_leaf = drop_blk->bp->b_addr; save_leaf = save_blk->bp->b_addr; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &drophdr, drop_leaf); xfs_attr3_leaf_hdr_from_disk(state->args->geo, &savehdr, save_leaf); entry = xfs_attr3_leaf_entryp(drop_leaf); /* * Save last hashval from dying block for later Btree fixup. */ drop_blk->hashval = be32_to_cpu(entry[drophdr.count - 1].hashval); /* * Check if we need a temp buffer, or can we do it in place. * Note that we don't check "leaf" for holes because we will * always be dropping it, toosmall() decided that for us already. */ if (savehdr.holes == 0) { /* * dest leaf has no holes, so we add there. May need * to make some room in the entry array. */ if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, drop_blk->bp, &drophdr)) { xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, save_leaf, &savehdr, 0, drophdr.count); } else { xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, save_leaf, &savehdr, savehdr.count, drophdr.count); } } else { /* * Destination has holes, so we make a temporary copy * of the leaf and add them both to that. */ struct xfs_attr_leafblock *tmp_leaf; struct xfs_attr3_icleaf_hdr tmphdr; tmp_leaf = kmem_zalloc(state->args->geo->blksize, KM_SLEEP); /* * Copy the header into the temp leaf so that all the stuff * not in the incore header is present and gets copied back in * once we've moved all the entries. */ memcpy(tmp_leaf, save_leaf, xfs_attr3_leaf_hdr_size(save_leaf)); memset(&tmphdr, 0, sizeof(tmphdr)); tmphdr.magic = savehdr.magic; tmphdr.forw = savehdr.forw; tmphdr.back = savehdr.back; tmphdr.firstused = state->args->geo->blksize; /* write the header to the temp buffer to initialise it */ xfs_attr3_leaf_hdr_to_disk(state->args->geo, tmp_leaf, &tmphdr); if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, drop_blk->bp, &drophdr)) { xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, tmp_leaf, &tmphdr, 0, drophdr.count); xfs_attr3_leaf_moveents(state->args, save_leaf, &savehdr, 0, tmp_leaf, &tmphdr, tmphdr.count, savehdr.count); } else { xfs_attr3_leaf_moveents(state->args, save_leaf, &savehdr, 0, tmp_leaf, &tmphdr, 0, savehdr.count); xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, tmp_leaf, &tmphdr, tmphdr.count, drophdr.count); } memcpy(save_leaf, tmp_leaf, state->args->geo->blksize); savehdr = tmphdr; /* struct copy */ kmem_free(tmp_leaf); } xfs_attr3_leaf_hdr_to_disk(state->args->geo, save_leaf, &savehdr); xfs_trans_log_buf(state->args->trans, save_blk->bp, 0, state->args->geo->blksize - 1); /* * Copy out last hashval in each block for B-tree code. */ entry = xfs_attr3_leaf_entryp(save_leaf); save_blk->hashval = be32_to_cpu(entry[savehdr.count - 1].hashval); } /*======================================================================== * Routines used for finding things in the Btree. *========================================================================*/ /* * Look up a name in a leaf attribute list structure. * This is the internal routine, it uses the caller's buffer. * * Note that duplicate keys are allowed, but only check within the * current leaf node. The Btree code must check in adjacent leaf nodes. * * Return in args->index the index into the entry[] array of either * the found entry, or where the entry should have been (insert before * that entry). * * Don't change the args->value unless we find the attribute. */ int xfs_attr3_leaf_lookup_int( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_entry *entries; struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; xfs_dahash_t hashval; int probe; int span; trace_xfs_attr_leaf_lookup(args); leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); entries = xfs_attr3_leaf_entryp(leaf); if (ichdr.count >= args->geo->blksize / 8) return -EFSCORRUPTED; /* * Binary search. (note: small blocks will skip this loop) */ hashval = args->hashval; probe = span = ichdr.count / 2; for (entry = &entries[probe]; span > 4; entry = &entries[probe]) { span /= 2; if (be32_to_cpu(entry->hashval) < hashval) probe += span; else if (be32_to_cpu(entry->hashval) > hashval) probe -= span; else break; } if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) return -EFSCORRUPTED; if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) return -EFSCORRUPTED; /* * Since we may have duplicate hashval's, find the first matching * hashval in the leaf. */ while (probe > 0 && be32_to_cpu(entry->hashval) >= hashval) { entry--; probe--; } while (probe < ichdr.count && be32_to_cpu(entry->hashval) < hashval) { entry++; probe++; } if (probe == ichdr.count || be32_to_cpu(entry->hashval) != hashval) { args->index = probe; return -ENOATTR; } /* * Duplicate keys may be present, so search all of them for a match. */ for (; probe < ichdr.count && (be32_to_cpu(entry->hashval) == hashval); entry++, probe++) { /* * GROT: Add code to remove incomplete entries. */ /* * If we are looking for INCOMPLETE entries, show only those. * If we are looking for complete entries, show only those. */ if ((args->flags & XFS_ATTR_INCOMPLETE) != (entry->flags & XFS_ATTR_INCOMPLETE)) { continue; } if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, probe); if (name_loc->namelen != args->namelen) continue; if (memcmp(args->name, name_loc->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, entry->flags)) continue; args->index = probe; return -EEXIST; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, probe); if (name_rmt->namelen != args->namelen) continue; if (memcmp(args->name, name_rmt->name, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, entry->flags)) continue; args->index = probe; args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); args->rmtblkno = be32_to_cpu(name_rmt->valueblk); args->rmtblkcnt = xfs_attr3_rmt_blocks( args->dp->i_mount, args->rmtvaluelen); return -EEXIST; } } args->index = probe; return -ENOATTR; } /* * Get the value associated with an attribute name from a leaf attribute * list structure. */ int xfs_attr3_leaf_getvalue( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; int valuelen; leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(ichdr.count < args->geo->blksize / 8); ASSERT(args->index < ichdr.count); entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, args->index); ASSERT(name_loc->namelen == args->namelen); ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0); valuelen = be16_to_cpu(name_loc->valuelen); if (args->flags & ATTR_KERNOVAL) { args->valuelen = valuelen; return 0; } if (args->valuelen < valuelen) { args->valuelen = valuelen; return -ERANGE; } args->valuelen = valuelen; memcpy(args->value, &name_loc->nameval[args->namelen], valuelen); } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); ASSERT(name_rmt->namelen == args->namelen); ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0); args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); args->rmtblkno = be32_to_cpu(name_rmt->valueblk); args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount, args->rmtvaluelen); if (args->flags & ATTR_KERNOVAL) { args->valuelen = args->rmtvaluelen; return 0; } if (args->valuelen < args->rmtvaluelen) { args->valuelen = args->rmtvaluelen; return -ERANGE; } args->valuelen = args->rmtvaluelen; } return 0; } /*======================================================================== * Utility routines. *========================================================================*/ /* * Move the indicated entries from one leaf to another. * NOTE: this routine modifies both source and destination leaves. */ /*ARGSUSED*/ STATIC void xfs_attr3_leaf_moveents( struct xfs_da_args *args, struct xfs_attr_leafblock *leaf_s, struct xfs_attr3_icleaf_hdr *ichdr_s, int start_s, struct xfs_attr_leafblock *leaf_d, struct xfs_attr3_icleaf_hdr *ichdr_d, int start_d, int count) { struct xfs_attr_leaf_entry *entry_s; struct xfs_attr_leaf_entry *entry_d; int desti; int tmp; int i; /* * Check for nothing to do. */ if (count == 0) return; /* * Set up environment. */ ASSERT(ichdr_s->magic == XFS_ATTR_LEAF_MAGIC || ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC); ASSERT(ichdr_s->magic == ichdr_d->magic); ASSERT(ichdr_s->count > 0 && ichdr_s->count < args->geo->blksize / 8); ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s)) + xfs_attr3_leaf_hdr_size(leaf_s)); ASSERT(ichdr_d->count < args->geo->blksize / 8); ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d)) + xfs_attr3_leaf_hdr_size(leaf_d)); ASSERT(start_s < ichdr_s->count); ASSERT(start_d <= ichdr_d->count); ASSERT(count <= ichdr_s->count); /* * Move the entries in the destination leaf up to make a hole? */ if (start_d < ichdr_d->count) { tmp = ichdr_d->count - start_d; tmp *= sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_d)[start_d]; entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d + count]; memmove(entry_d, entry_s, tmp); } /* * Copy all entry's in the same (sorted) order, * but allocate attribute info packed and in sequence. */ entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d]; desti = start_d; for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { ASSERT(be16_to_cpu(entry_s->nameidx) >= ichdr_s->firstused); tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); #ifdef GROT /* * Code to drop INCOMPLETE entries. Difficult to use as we * may also need to change the insertion index. Code turned * off for 6.2, should be revisited later. */ if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp); ichdr_s->usedbytes -= tmp; ichdr_s->count -= 1; entry_d--; /* to compensate for ++ in loop hdr */ desti--; if ((start_s + i) < offset) result++; /* insertion index adjustment */ } else { #endif /* GROT */ ichdr_d->firstused -= tmp; /* both on-disk, don't endian flip twice */ entry_d->hashval = entry_s->hashval; entry_d->nameidx = cpu_to_be16(ichdr_d->firstused); entry_d->flags = entry_s->flags; ASSERT(be16_to_cpu(entry_d->nameidx) + tmp <= args->geo->blksize); memmove(xfs_attr3_leaf_name(leaf_d, desti), xfs_attr3_leaf_name(leaf_s, start_s + i), tmp); ASSERT(be16_to_cpu(entry_s->nameidx) + tmp <= args->geo->blksize); memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp); ichdr_s->usedbytes -= tmp; ichdr_d->usedbytes += tmp; ichdr_s->count -= 1; ichdr_d->count += 1; tmp = ichdr_d->count * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf_d); ASSERT(ichdr_d->firstused >= tmp); #ifdef GROT } #endif /* GROT */ } /* * Zero out the entries we just copied. */ if (start_s == ichdr_s->count) { tmp = count * sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; ASSERT(((char *)entry_s + tmp) <= ((char *)leaf_s + args->geo->blksize)); memset(entry_s, 0, tmp); } else { /* * Move the remaining entries down to fill the hole, * then zero the entries at the top. */ tmp = (ichdr_s->count - count) * sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s + count]; entry_d = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; memmove(entry_d, entry_s, tmp); tmp = count * sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_s)[ichdr_s->count]; ASSERT(((char *)entry_s + tmp) <= ((char *)leaf_s + args->geo->blksize)); memset(entry_s, 0, tmp); } /* * Fill in the freemap information */ ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_d); ichdr_d->freemap[0].base += ichdr_d->count * sizeof(xfs_attr_leaf_entry_t); ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base; ichdr_d->freemap[1].base = 0; ichdr_d->freemap[2].base = 0; ichdr_d->freemap[1].size = 0; ichdr_d->freemap[2].size = 0; ichdr_s->holes = 1; /* leaf may not be compact */ } /* * Pick up the last hashvalue from a leaf block. */ xfs_dahash_t xfs_attr_leaf_lasthash( struct xfs_buf *bp, int *count) { struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entries; struct xfs_mount *mp = bp->b_mount; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, bp->b_addr); entries = xfs_attr3_leaf_entryp(bp->b_addr); if (count) *count = ichdr.count; if (!ichdr.count) return 0; return be32_to_cpu(entries[ichdr.count - 1].hashval); } /* * Calculate the number of bytes used to store the indicated attribute * (whether local or remote only calculate bytes in this block). */ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) { struct xfs_attr_leaf_entry *entries; xfs_attr_leaf_name_local_t *name_loc; xfs_attr_leaf_name_remote_t *name_rmt; int size; entries = xfs_attr3_leaf_entryp(leaf); if (entries[index].flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, index); size = xfs_attr_leaf_entsize_local(name_loc->namelen, be16_to_cpu(name_loc->valuelen)); } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, index); size = xfs_attr_leaf_entsize_remote(name_rmt->namelen); } return size; } /* * Calculate the number of bytes that would be required to store the new * attribute (whether local or remote only calculate bytes in this block). * This routine decides as a side effect whether the attribute will be * a "local" or a "remote" attribute. */ int xfs_attr_leaf_newentsize( struct xfs_da_args *args, int *local) { int size; size = xfs_attr_leaf_entsize_local(args->namelen, args->valuelen); if (size < xfs_attr_leaf_entsize_local_max(args->geo->blksize)) { if (local) *local = 1; return size; } if (local) *local = 0; return xfs_attr_leaf_entsize_remote(args->namelen); } /*======================================================================== * Manage the INCOMPLETE flag in a leaf entry *========================================================================*/ /* * Clear the INCOMPLETE flag on an entry in a leaf block. */ int xfs_attr3_leaf_clearflag( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_buf *bp; int error; #ifdef DEBUG struct xfs_attr3_icleaf_hdr ichdr; xfs_attr_leaf_name_local_t *name_loc; int namelen; char *name; #endif /* DEBUG */ trace_xfs_attr_leaf_clearflag(args); /* * Set up the operation. */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; leaf = bp->b_addr; entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; ASSERT(entry->flags & XFS_ATTR_INCOMPLETE); #ifdef DEBUG xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(args->index < ichdr.count); ASSERT(args->index >= 0); if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, args->index); namelen = name_loc->namelen; name = (char *)name_loc->nameval; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); namelen = name_rmt->namelen; name = (char *)name_rmt->name; } ASSERT(be32_to_cpu(entry->hashval) == args->hashval); ASSERT(namelen == args->namelen); ASSERT(memcmp(name, args->name, namelen) == 0); #endif /* DEBUG */ entry->flags &= ~XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); if (args->rmtblkno) { ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0); name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); name_rmt->valueblk = cpu_to_be32(args->rmtblkno); name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); } /* * Commit the flag value change and start the next trans in series. */ return xfs_trans_roll_inode(&args->trans, args->dp); } /* * Set the INCOMPLETE flag on an entry in a leaf block. */ int xfs_attr3_leaf_setflag( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_buf *bp; int error; #ifdef DEBUG struct xfs_attr3_icleaf_hdr ichdr; #endif trace_xfs_attr_leaf_setflag(args); /* * Set up the operation. */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; leaf = bp->b_addr; #ifdef DEBUG xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(args->index < ichdr.count); ASSERT(args->index >= 0); #endif entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0); entry->flags |= XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); if ((entry->flags & XFS_ATTR_LOCAL) == 0) { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); name_rmt->valueblk = 0; name_rmt->valuelen = 0; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); } /* * Commit the flag value change and start the next trans in series. */ return xfs_trans_roll_inode(&args->trans, args->dp); } /* * In a single transaction, clear the INCOMPLETE flag on the leaf entry * given by args->blkno/index and set the INCOMPLETE flag on the leaf * entry given by args->blkno2/index2. * * Note that they could be in different blocks, or in the same block. */ int xfs_attr3_leaf_flipflags( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf1; struct xfs_attr_leafblock *leaf2; struct xfs_attr_leaf_entry *entry1; struct xfs_attr_leaf_entry *entry2; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_buf *bp1; struct xfs_buf *bp2; int error; #ifdef DEBUG struct xfs_attr3_icleaf_hdr ichdr1; struct xfs_attr3_icleaf_hdr ichdr2; xfs_attr_leaf_name_local_t *name_loc; int namelen1, namelen2; char *name1, *name2; #endif /* DEBUG */ trace_xfs_attr_leaf_flipflags(args); /* * Read the block containing the "old" attr */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1); if (error) return error; /* * Read the block containing the "new" attr, if it is different */ if (args->blkno2 != args->blkno) { error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2, -1, &bp2); if (error) return error; } else { bp2 = bp1; } leaf1 = bp1->b_addr; entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index]; leaf2 = bp2->b_addr; entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2]; #ifdef DEBUG xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr1, leaf1); ASSERT(args->index < ichdr1.count); ASSERT(args->index >= 0); xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr2, leaf2); ASSERT(args->index2 < ichdr2.count); ASSERT(args->index2 >= 0); if (entry1->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf1, args->index); namelen1 = name_loc->namelen; name1 = (char *)name_loc->nameval; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index); namelen1 = name_rmt->namelen; name1 = (char *)name_rmt->name; } if (entry2->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf2, args->index2); namelen2 = name_loc->namelen; name2 = (char *)name_loc->nameval; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2); namelen2 = name_rmt->namelen; name2 = (char *)name_rmt->name; } ASSERT(be32_to_cpu(entry1->hashval) == be32_to_cpu(entry2->hashval)); ASSERT(namelen1 == namelen2); ASSERT(memcmp(name1, name2, namelen1) == 0); #endif /* DEBUG */ ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE); ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0); entry1->flags &= ~XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp1, XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1))); if (args->rmtblkno) { ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0); name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index); name_rmt->valueblk = cpu_to_be32(args->rmtblkno); name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen); xfs_trans_log_buf(args->trans, bp1, XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt))); } entry2->flags |= XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp2, XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2))); if ((entry2->flags & XFS_ATTR_LOCAL) == 0) { name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2); name_rmt->valueblk = 0; name_rmt->valuelen = 0; xfs_trans_log_buf(args->trans, bp2, XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt))); } /* * Commit the flag value change and start the next trans in series. */ error = xfs_trans_roll_inode(&args->trans, args->dp); return error; } xfsprogs-5.3.0/libxfs/xfs_attr_leaf.h0000644000175000017500000000675413435336036017547 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_ATTR_LEAF_H__ #define __XFS_ATTR_LEAF_H__ struct attrlist; struct attrlist_cursor_kern; struct xfs_attr_list_context; struct xfs_da_args; struct xfs_da_state; struct xfs_da_state_blk; struct xfs_inode; struct xfs_trans; /* * Used to keep a list of "remote value" extents when unlinking an inode. */ typedef struct xfs_attr_inactive_list { xfs_dablk_t valueblk; /* block number of value bytes */ int valuelen; /* number of bytes in value */ } xfs_attr_inactive_list_t; /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Internal routines when attribute fork size < XFS_LITINO(mp). */ void xfs_attr_shortform_create(struct xfs_da_args *args); void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); int xfs_attr_shortform_lookup(struct xfs_da_args *args); int xfs_attr_shortform_getvalue(struct xfs_da_args *args); int xfs_attr_shortform_to_leaf(struct xfs_da_args *args, struct xfs_buf **leaf_bp); int xfs_attr_shortform_remove(struct xfs_da_args *args); int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip); void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); /* * Internal routines when attribute fork size == XFS_LBSIZE(mp). */ int xfs_attr3_leaf_to_node(struct xfs_da_args *args); int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp, struct xfs_da_args *args, int forkoff); int xfs_attr3_leaf_clearflag(struct xfs_da_args *args); int xfs_attr3_leaf_setflag(struct xfs_da_args *args); int xfs_attr3_leaf_flipflags(struct xfs_da_args *args); /* * Routines used for growing the Btree. */ int xfs_attr3_leaf_split(struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); int xfs_attr3_leaf_lookup_int(struct xfs_buf *leaf, struct xfs_da_args *args); int xfs_attr3_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args); int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer, struct xfs_da_args *args); int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer, struct xfs_da_args *args); void xfs_attr3_leaf_list_int(struct xfs_buf *bp, struct xfs_attr_list_context *context); /* * Routines used for shrinking the Btree. */ int xfs_attr3_leaf_toosmall(struct xfs_da_state *state, int *retval); void xfs_attr3_leaf_unbalance(struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk); /* * Utility routines. */ xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_buf *bp, int *count); int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp, struct xfs_buf *leaf2_bp); int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local); int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp); void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo, struct xfs_attr3_icleaf_hdr *to, struct xfs_attr_leafblock *from); void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo, struct xfs_attr_leafblock *to, struct xfs_attr3_icleaf_hdr *from); #endif /* __XFS_ATTR_LEAF_H__ */ xfsprogs-5.3.0/libxfs/xfs_attr_remote.c0000644000175000017500000003553713570057155020131 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_trace.h" #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ /* * Each contiguous block has a header, so it is not just a simple attribute * length to FSB conversion. */ int xfs_attr3_rmt_blocks( struct xfs_mount *mp, int attrlen) { if (xfs_sb_version_hascrc(&mp->m_sb)) { int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); return (attrlen + buflen - 1) / buflen; } return XFS_B_TO_FSB(mp, attrlen); } /* * Checking of the remote attribute header is split into two parts. The verifier * does CRC, location and bounds checking, the unpacking function checks the * attribute parameters and owner. */ static xfs_failaddr_t xfs_attr3_rmt_hdr_ok( void *ptr, xfs_ino_t ino, uint32_t offset, uint32_t size, xfs_daddr_t bno) { struct xfs_attr3_rmt_hdr *rmt = ptr; if (bno != be64_to_cpu(rmt->rm_blkno)) return __this_address; if (offset != be32_to_cpu(rmt->rm_offset)) return __this_address; if (size != be32_to_cpu(rmt->rm_bytes)) return __this_address; if (ino != be64_to_cpu(rmt->rm_owner)) return __this_address; /* ok */ return NULL; } static xfs_failaddr_t xfs_attr3_rmt_verify( struct xfs_mount *mp, struct xfs_buf *bp, void *ptr, int fsbsize, xfs_daddr_t bno) { struct xfs_attr3_rmt_hdr *rmt = ptr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return __this_address; if (!xfs_verify_magic(bp, rmt->rm_magic)) return __this_address; if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (be64_to_cpu(rmt->rm_blkno) != bno) return __this_address; if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt)) return __this_address; if (be32_to_cpu(rmt->rm_offset) + be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX) return __this_address; if (rmt->rm_owner == 0) return __this_address; return NULL; } static int __xfs_attr3_rmt_read_verify( struct xfs_buf *bp, bool check_crc, xfs_failaddr_t *failaddr) { struct xfs_mount *mp = bp->b_mount; char *ptr; int len; xfs_daddr_t bno; int blksize = mp->m_attr_geo->blksize; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return 0; ptr = bp->b_addr; bno = bp->b_bn; len = BBTOB(bp->b_length); ASSERT(len >= blksize); while (len > 0) { if (check_crc && !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) { *failaddr = __this_address; return -EFSBADCRC; } *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno); if (*failaddr) return -EFSCORRUPTED; len -= blksize; ptr += blksize; bno += BTOBB(blksize); } if (len != 0) { *failaddr = __this_address; return -EFSCORRUPTED; } return 0; } static void xfs_attr3_rmt_read_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; int error; error = __xfs_attr3_rmt_read_verify(bp, true, &fa); if (error) xfs_verifier_error(bp, error, fa); } static xfs_failaddr_t xfs_attr3_rmt_verify_struct( struct xfs_buf *bp) { xfs_failaddr_t fa; int error; error = __xfs_attr3_rmt_read_verify(bp, false, &fa); return error ? fa : NULL; } static void xfs_attr3_rmt_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; int blksize = mp->m_attr_geo->blksize; char *ptr; int len; xfs_daddr_t bno; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; ptr = bp->b_addr; bno = bp->b_bn; len = BBTOB(bp->b_length); ASSERT(len >= blksize); while (len > 0) { struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr; fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } /* * Ensure we aren't writing bogus LSNs to disk. See * xfs_attr3_rmt_hdr_set() for the explanation. */ if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) { xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); return; } xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF); len -= blksize; ptr += blksize; bno += BTOBB(blksize); } if (len != 0) xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); } const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { .name = "xfs_attr3_rmt", .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) }, .verify_read = xfs_attr3_rmt_read_verify, .verify_write = xfs_attr3_rmt_write_verify, .verify_struct = xfs_attr3_rmt_verify_struct, }; STATIC int xfs_attr3_rmt_hdr_set( struct xfs_mount *mp, void *ptr, xfs_ino_t ino, uint32_t offset, uint32_t size, xfs_daddr_t bno) { struct xfs_attr3_rmt_hdr *rmt = ptr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return 0; rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC); rmt->rm_offset = cpu_to_be32(offset); rmt->rm_bytes = cpu_to_be32(size); uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid); rmt->rm_owner = cpu_to_be64(ino); rmt->rm_blkno = cpu_to_be64(bno); /* * Remote attribute blocks are written synchronously, so we don't * have an LSN that we can stamp in them that makes any sense to log * recovery. To ensure that log recovery handles overwrites of these * blocks sanely (i.e. once they've been freed and reallocated as some * other type of metadata) we need to ensure that the LSN has a value * that tells log recovery to ignore the LSN and overwrite the buffer * with whatever is in it's log. To do this, we use the magic * NULLCOMMITLSN to indicate that the LSN is invalid. */ rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN); return sizeof(struct xfs_attr3_rmt_hdr); } /* * Helper functions to copy attribute data in and out of the one disk extents */ STATIC int xfs_attr_rmtval_copyout( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino, int *offset, int *valuelen, uint8_t **dst) { char *src = bp->b_addr; xfs_daddr_t bno = bp->b_bn; int len = BBTOB(bp->b_length); int blksize = mp->m_attr_geo->blksize; ASSERT(len >= blksize); while (len > 0 && *valuelen > 0) { int hdr_size = 0; int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); byte_cnt = min(*valuelen, byte_cnt); if (xfs_sb_version_hascrc(&mp->m_sb)) { if (xfs_attr3_rmt_hdr_ok(src, ino, *offset, byte_cnt, bno)) { xfs_alert(mp, "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", bno, *offset, byte_cnt, ino); return -EFSCORRUPTED; } hdr_size = sizeof(struct xfs_attr3_rmt_hdr); } memcpy(*dst, src + hdr_size, byte_cnt); /* roll buffer forwards */ len -= blksize; src += blksize; bno += BTOBB(blksize); /* roll attribute data forwards */ *valuelen -= byte_cnt; *dst += byte_cnt; *offset += byte_cnt; } return 0; } STATIC void xfs_attr_rmtval_copyin( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino, int *offset, int *valuelen, uint8_t **src) { char *dst = bp->b_addr; xfs_daddr_t bno = bp->b_bn; int len = BBTOB(bp->b_length); int blksize = mp->m_attr_geo->blksize; ASSERT(len >= blksize); while (len > 0 && *valuelen > 0) { int hdr_size; int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); byte_cnt = min(*valuelen, byte_cnt); hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset, byte_cnt, bno); memcpy(dst + hdr_size, *src, byte_cnt); /* * If this is the last block, zero the remainder of it. * Check that we are actually the last block, too. */ if (byte_cnt + hdr_size < blksize) { ASSERT(*valuelen - byte_cnt == 0); ASSERT(len == blksize); memset(dst + hdr_size + byte_cnt, 0, blksize - hdr_size - byte_cnt); } /* roll buffer forwards */ len -= blksize; dst += blksize; bno += BTOBB(blksize); /* roll attribute data forwards */ *valuelen -= byte_cnt; *src += byte_cnt; *offset += byte_cnt; } } /* * Read the value associated with an attribute from the out-of-line buffer * that we stored it in. */ int xfs_attr_rmtval_get( struct xfs_da_args *args) { struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; struct xfs_mount *mp = args->dp->i_mount; struct xfs_buf *bp; xfs_dablk_t lblkno = args->rmtblkno; uint8_t *dst = args->value; int valuelen; int nmap; int error; int blkcnt = args->rmtblkcnt; int i; int offset = 0; trace_xfs_attr_rmtval_get(args); ASSERT(!(args->flags & ATTR_KERNOVAL)); ASSERT(args->rmtvaluelen == args->valuelen); valuelen = args->rmtvaluelen; while (valuelen > 0) { nmap = ATTR_RMTVALUE_MAPSIZE; error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, blkcnt, map, &nmap, XFS_BMAPI_ATTRFORK); if (error) return error; ASSERT(nmap >= 1); for (i = 0; (i < nmap) && (valuelen > 0); i++) { xfs_daddr_t dblkno; int dblkcnt; ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && (map[i].br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); error = xfs_trans_read_buf(mp, args->trans, mp->m_ddev_targp, dblkno, dblkcnt, 0, &bp, &xfs_attr3_rmt_buf_ops); if (error) return error; error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, &offset, &valuelen, &dst); xfs_trans_brelse(args->trans, bp); if (error) return error; /* roll attribute extent map forwards */ lblkno += map[i].br_blockcount; blkcnt -= map[i].br_blockcount; } } ASSERT(valuelen == 0); return 0; } /* * Write the value associated with an attribute into the out-of-line buffer * that we have defined for it. */ int xfs_attr_rmtval_set( struct xfs_da_args *args) { struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_bmbt_irec map; xfs_dablk_t lblkno; xfs_fileoff_t lfileoff = 0; uint8_t *src = args->value; int blkcnt; int valuelen; int nmap; int error; int offset = 0; trace_xfs_attr_rmtval_set(args); /* * Find a "hole" in the attribute address space large enough for * us to drop the new attribute's value into. Because CRC enable * attributes have headers, we can't just do a straight byte to FSB * conversion and have to take the header space into account. */ blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, XFS_ATTR_FORK); if (error) return error; args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; args->rmtblkcnt = blkcnt; /* * Roll through the "value", allocating blocks on disk as required. */ while (blkcnt > 0) { /* * Allocate a single extent, up to the size of the value. * * Note that we have to consider this a data allocation as we * write the remote attribute without logging the contents. * Hence we must ensure that we aren't using blocks that are on * the busy list so that we don't overwrite blocks which have * recently been freed but their transactions are not yet * committed to disk. If we overwrite the contents of a busy * extent and then crash then the block may not contain the * correct metadata after log recovery occurs. */ nmap = 1; error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno, blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map, &nmap); if (error) return error; error = xfs_defer_finish(&args->trans); if (error) return error; ASSERT(nmap == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); lblkno += map.br_blockcount; blkcnt -= map.br_blockcount; /* * Start the next trans in the chain. */ error = xfs_trans_roll_inode(&args->trans, dp); if (error) return error; } /* * Roll through the "value", copying the attribute value to the * already-allocated blocks. Blocks are written synchronously * so that we can know they are all on disk before we turn off * the INCOMPLETE flag. */ lblkno = args->rmtblkno; blkcnt = args->rmtblkcnt; valuelen = args->rmtvaluelen; while (valuelen > 0) { struct xfs_buf *bp; xfs_daddr_t dblkno; int dblkcnt; ASSERT(blkcnt > 0); nmap = 1; error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); if (error) return error; ASSERT(nmap == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt); if (!bp) return -ENOMEM; bp->b_ops = &xfs_attr3_rmt_buf_ops; xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, &valuelen, &src); error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ xfs_buf_relse(bp); if (error) return error; /* roll attribute extent map forwards */ lblkno += map.br_blockcount; blkcnt -= map.br_blockcount; } ASSERT(valuelen == 0); return 0; } /* * Remove the value associated with an attribute by deleting the * out-of-line buffer that it is stored on. */ int xfs_attr_rmtval_remove( struct xfs_da_args *args) { struct xfs_mount *mp = args->dp->i_mount; xfs_dablk_t lblkno; int blkcnt; int error; int done; trace_xfs_attr_rmtval_remove(args); /* * Roll through the "value", invalidating the attribute value's blocks. */ lblkno = args->rmtblkno; blkcnt = args->rmtblkcnt; while (blkcnt > 0) { struct xfs_bmbt_irec map; struct xfs_buf *bp; xfs_daddr_t dblkno; int dblkcnt; int nmap; /* * Try to remember where we decided to put the value. */ nmap = 1; error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); if (error) return error; ASSERT(nmap == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); /* * If the "remote" value is in the cache, remove it. */ bp = xfs_buf_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK); if (bp) { xfs_buf_stale(bp); xfs_buf_relse(bp); bp = NULL; } lblkno += map.br_blockcount; blkcnt -= map.br_blockcount; } /* * Keep de-allocating extents until the remote-value region is gone. */ lblkno = args->rmtblkno; blkcnt = args->rmtblkcnt; done = 0; while (!done) { error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, XFS_BMAPI_ATTRFORK, 1, &done); if (error) return error; error = xfs_defer_finish(&args->trans); if (error) return error; /* * Close out trans and start the next one in the chain. */ error = xfs_trans_roll_inode(&args->trans, args->dp); if (error) return error; } return 0; } xfsprogs-5.3.0/libxfs/xfs_attr_remote.h0000644000175000017500000000064213435336036020121 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_ATTR_REMOTE_H__ #define __XFS_ATTR_REMOTE_H__ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen); int xfs_attr_rmtval_get(struct xfs_da_args *args); int xfs_attr_rmtval_set(struct xfs_da_args *args); int xfs_attr_rmtval_remove(struct xfs_da_args *args); #endif /* __XFS_ATTR_REMOTE_H__ */ xfsprogs-5.3.0/libxfs/xfs_attr_sf.h0000644000175000017500000000311513435336036017234 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_ATTR_SF_H__ #define __XFS_ATTR_SF_H__ /* * Attribute storage when stored inside the inode. * * Small attribute lists are packed as tightly as possible so as * to fit into the literal area of the inode. */ typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t; typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t; /* * We generate this then sort it, attr_list() must return things in hash-order. */ typedef struct xfs_attr_sf_sort { uint8_t entno; /* entry number in original list */ uint8_t namelen; /* length of name value (no null) */ uint8_t valuelen; /* length of value */ uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ xfs_dahash_t hash; /* this entry's hash value */ unsigned char *name; /* name value, pointer into buffer */ } xfs_attr_sf_sort_t; #define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ (((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen))) #define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ ((1 << (NBBY*(int)sizeof(uint8_t))) - 1) #define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \ ((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen) #define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ ((xfs_attr_sf_entry_t *)((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep))) #define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \ (be16_to_cpu(((xfs_attr_shortform_t *) \ ((dp)->i_afp->if_u1.if_data))->hdr.totsize)) #endif /* __XFS_ATTR_SF_H__ */ xfsprogs-5.3.0/libxfs/xfs_bit.c0000644000175000017500000000425413570057155016352 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_log_format.h" /* * XFS bit manipulation routines, used in non-realtime code. */ /* * Return whether bitmap is empty. * Size is number of words in the bitmap, which is padded to word boundary * Returns 1 for empty, 0 for non-empty. */ int xfs_bitmap_empty(uint *map, uint size) { uint i; for (i = 0; i < size; i++) { if (map[i] != 0) return 0; } return 1; } /* * Count the number of contiguous bits set in the bitmap starting with bit * start_bit. Size is the size of the bitmap in words. */ int xfs_contig_bits(uint *map, uint size, uint start_bit) { uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); uint result = 0; uint tmp; size <<= BIT_TO_WORD_SHIFT; ASSERT(start_bit < size); size -= start_bit & ~(NBWORD - 1); start_bit &= (NBWORD - 1); if (start_bit) { tmp = *p++; /* set to one first offset bits prior to start */ tmp |= (~0U >> (NBWORD-start_bit)); if (tmp != ~0U) goto found; result += NBWORD; size -= NBWORD; } while (size) { if ((tmp = *p++) != ~0U) goto found; result += NBWORD; size -= NBWORD; } return result - start_bit; found: return result + ffz(tmp) - start_bit; } /* * This takes the bit number to start looking from and * returns the next set bit from there. It returns -1 * if there are no more bits set or the start bit is * beyond the end of the bitmap. * * Size is the number of words, not bytes, in the bitmap. */ int xfs_next_bit(uint *map, uint size, uint start_bit) { uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); uint result = start_bit & ~(NBWORD - 1); uint tmp; size <<= BIT_TO_WORD_SHIFT; if (start_bit >= size) return -1; size -= result; start_bit &= (NBWORD - 1); if (start_bit) { tmp = *p++; /* set to zero first offset bits prior to start */ tmp &= (~0U << start_bit); if (tmp != 0U) goto found; result += NBWORD; size -= NBWORD; } while (size) { if ((tmp = *p++) != 0U) goto found; result += NBWORD; size -= NBWORD; } return -1; found: return result + ffs(tmp) - 1; } xfsprogs-5.3.0/libxfs/xfs_bit.h0000644000175000017500000000304613435336036016353 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_BIT_H__ #define __XFS_BIT_H__ /* * XFS bit manipulation routines. */ /* * masks with n high/low bits set, 64-bit values */ static inline uint64_t xfs_mask64hi(int n) { return (uint64_t)-1 << (64 - (n)); } static inline uint32_t xfs_mask32lo(int n) { return ((uint32_t)1 << (n)) - 1; } static inline uint64_t xfs_mask64lo(int n) { return ((uint64_t)1 << (n)) - 1; } /* Get high bit set out of 32-bit argument, -1 if none set */ static inline int xfs_highbit32(uint32_t v) { return fls(v) - 1; } /* Get high bit set out of 64-bit argument, -1 if none set */ static inline int xfs_highbit64(uint64_t v) { return fls64(v) - 1; } /* Get low bit set out of 32-bit argument, -1 if none set */ static inline int xfs_lowbit32(uint32_t v) { return ffs(v) - 1; } /* Get low bit set out of 64-bit argument, -1 if none set */ static inline int xfs_lowbit64(uint64_t v) { uint32_t w = (uint32_t)v; int n = 0; if (w) { /* lower bits */ n = ffs(w); } else { /* upper bits */ w = (uint32_t)(v >> 32); if (w) { n = ffs(w); if (n) n += 32; } } return n - 1; } /* Return whether bitmap is empty (1 == empty) */ extern int xfs_bitmap_empty(uint *map, uint size); /* Count continuous one bits in map starting with start_bit */ extern int xfs_contig_bits(uint *map, uint size, uint start_bit); /* Find next set bit in map */ extern int xfs_next_bit(uint *map, uint size, uint start_bit); #endif /* __XFS_BIT_H__ */ xfsprogs-5.3.0/libxfs/xfs_bmap.c0000644000175000017500000052164713570057155016525 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_dir2.h" #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_trans_space.h" #include "xfs_trace.h" #include "xfs_attr_leaf.h" #include "xfs_quota_defs.h" #include "xfs_rmap.h" #include "xfs_ag_resv.h" #include "xfs_refcount.h" kmem_zone_t *xfs_bmap_free_item_zone; /* * Miscellaneous helper functions */ /* * Compute and fill in the value of the maximum depth of a bmap btree * in this filesystem. Done once, during mount. */ void xfs_bmap_compute_maxlevels( xfs_mount_t *mp, /* file system mount structure */ int whichfork) /* data or attr fork */ { int level; /* btree level */ uint maxblocks; /* max blocks at this level */ uint maxleafents; /* max leaf entries possible */ int maxrootrecs; /* max records in root block */ int minleafrecs; /* min records in leaf block */ int minnoderecs; /* min records in node block */ int sz; /* root block size */ /* * The maximum number of extents in a file, hence the maximum * number of leaf entries, is controlled by the type of di_nextents * (a signed 32-bit number, xfs_extnum_t), or by di_anextents * (a signed 16-bit number, xfs_aextnum_t). * * Note that we can no longer assume that if we are in ATTR1 that * the fork offset of all the inodes will be * (xfs_default_attroffset(ip) >> 3) because we could have mounted * with ATTR2 and then mounted back with ATTR1, keeping the * di_forkoff's fixed but probably at various positions. Therefore, * for both ATTR1 and ATTR2 we have to assume the worst case scenario * of a minimum size available. */ if (whichfork == XFS_DATA_FORK) { maxleafents = MAXEXTNUM; sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS); } else { maxleafents = MAXAEXTNUM; sz = XFS_BMDR_SPACE_CALC(MINABTPTRS); } maxrootrecs = xfs_bmdr_maxrecs(sz, 0); minleafrecs = mp->m_bmap_dmnr[0]; minnoderecs = mp->m_bmap_dmnr[1]; maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; for (level = 1; maxblocks > 1; level++) { if (maxblocks <= maxrootrecs) maxblocks = 1; else maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; } mp->m_bm_maxlevels[whichfork] = level; } STATIC int /* error */ xfs_bmbt_lookup_eq( struct xfs_btree_cur *cur, struct xfs_bmbt_irec *irec, int *stat) /* success/failure */ { cur->bc_rec.b = *irec; return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); } STATIC int /* error */ xfs_bmbt_lookup_first( struct xfs_btree_cur *cur, int *stat) /* success/failure */ { cur->bc_rec.b.br_startoff = 0; cur->bc_rec.b.br_startblock = 0; cur->bc_rec.b.br_blockcount = 0; return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); } /* * Check if the inode needs to be converted to btree format. */ static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork) { return whichfork != XFS_COW_FORK && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && XFS_IFORK_NEXTENTS(ip, whichfork) > XFS_IFORK_MAXEXT(ip, whichfork); } /* * Check if the inode should be converted to extent format. */ static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork) { return whichfork != XFS_COW_FORK && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && XFS_IFORK_NEXTENTS(ip, whichfork) <= XFS_IFORK_MAXEXT(ip, whichfork); } /* * Update the record referred to by cur to the value given by irec * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int xfs_bmbt_update( struct xfs_btree_cur *cur, struct xfs_bmbt_irec *irec) { union xfs_btree_rec rec; xfs_bmbt_disk_set_all(&rec.bmbt, irec); return xfs_btree_update(cur, &rec); } /* * Compute the worst-case number of indirect blocks that will be used * for ip's delayed extent of length "len". */ STATIC xfs_filblks_t xfs_bmap_worst_indlen( xfs_inode_t *ip, /* incore inode pointer */ xfs_filblks_t len) /* delayed extent length */ { int level; /* btree level number */ int maxrecs; /* maximum record count at this level */ xfs_mount_t *mp; /* mount structure */ xfs_filblks_t rval; /* return value */ mp = ip->i_mount; maxrecs = mp->m_bmap_dmxr[0]; for (level = 0, rval = 0; level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); level++) { len += maxrecs - 1; do_div(len, maxrecs); rval += len; if (len == 1) return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - level - 1; if (level == 0) maxrecs = mp->m_bmap_dmxr[1]; } return rval; } /* * Calculate the default attribute fork offset for newly created inodes. */ uint xfs_default_attroffset( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; uint offset; if (mp->m_sb.sb_inodesize == 256) { offset = XFS_LITINO(mp, ip->i_d.di_version) - XFS_BMDR_SPACE_CALC(MINABTPTRS); } else { offset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS); } ASSERT(offset < XFS_LITINO(mp, ip->i_d.di_version)); return offset; } /* * Helper routine to reset inode di_forkoff field when switching * attribute fork from local to extent format - we reset it where * possible to make space available for inline data fork extents. */ STATIC void xfs_bmap_forkoff_reset( xfs_inode_t *ip, int whichfork) { if (whichfork == XFS_ATTR_FORK && ip->i_d.di_format != XFS_DINODE_FMT_DEV && ip->i_d.di_format != XFS_DINODE_FMT_BTREE) { uint dfl_forkoff = xfs_default_attroffset(ip) >> 3; if (dfl_forkoff > ip->i_d.di_forkoff) ip->i_d.di_forkoff = dfl_forkoff; } } #ifdef DEBUG STATIC struct xfs_buf * xfs_bmap_get_bp( struct xfs_btree_cur *cur, xfs_fsblock_t bno) { struct xfs_log_item *lip; int i; if (!cur) return NULL; for (i = 0; i < XFS_BTREE_MAXLEVELS; i++) { if (!cur->bc_bufs[i]) break; if (XFS_BUF_ADDR(cur->bc_bufs[i]) == bno) return cur->bc_bufs[i]; } /* Chase down all the log items to see if the bp is there */ list_for_each_entry(lip, &cur->bc_tp->t_items, li_trans) { struct xfs_buf_log_item *bip = (struct xfs_buf_log_item *)lip; if (bip->bli_item.li_type == XFS_LI_BUF && XFS_BUF_ADDR(bip->bli_buf) == bno) return bip->bli_buf; } return NULL; } STATIC void xfs_check_block( struct xfs_btree_block *block, xfs_mount_t *mp, int root, short sz) { int i, j, dmxr; __be64 *pp, *thispa; /* pointer to block address */ xfs_bmbt_key_t *prevp, *keyp; ASSERT(be16_to_cpu(block->bb_level) > 0); prevp = NULL; for( i = 1; i <= xfs_btree_get_numrecs(block); i++) { dmxr = mp->m_bmap_dmxr[0]; keyp = XFS_BMBT_KEY_ADDR(mp, block, i); if (prevp) { ASSERT(be64_to_cpu(prevp->br_startoff) < be64_to_cpu(keyp->br_startoff)); } prevp = keyp; /* * Compare the block numbers to see if there are dups. */ if (root) pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, i, sz); else pp = XFS_BMBT_PTR_ADDR(mp, block, i, dmxr); for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) { if (root) thispa = XFS_BMAP_BROOT_PTR_ADDR(mp, block, j, sz); else thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr); if (*thispa == *pp) { xfs_warn(mp, "%s: thispa(%d) == pp(%d) %Ld", __func__, j, i, (unsigned long long)be64_to_cpu(*thispa)); xfs_err(mp, "%s: ptrs are equal in node\n", __func__); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); } } } } /* * Check that the extents for the inode ip are in the right order in all * btree leaves. THis becomes prohibitively expensive for large extent count * files, so don't bother with inodes that have more than 10,000 extents in * them. The btree record ordering checks will still be done, so for such large * bmapbt constructs that is going to catch most corruptions. */ STATIC void xfs_bmap_check_leaf_extents( xfs_btree_cur_t *cur, /* btree cursor or null */ xfs_inode_t *ip, /* incore inode pointer */ int whichfork) /* data or attr fork */ { struct xfs_btree_block *block; /* current btree block */ xfs_fsblock_t bno; /* block # of "block" */ xfs_buf_t *bp; /* buffer for "block" */ int error; /* error return value */ xfs_extnum_t i=0, j; /* index into the extents list */ struct xfs_ifork *ifp; /* fork structure */ int level; /* btree level, for checking */ xfs_mount_t *mp; /* file system mount structure */ __be64 *pp; /* pointer to block address */ xfs_bmbt_rec_t *ep; /* pointer to current extent */ xfs_bmbt_rec_t last = {0, 0}; /* last extent in prev block */ xfs_bmbt_rec_t *nextp; /* pointer to next extent */ int bp_release = 0; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) { return; } /* skip large extent count inodes */ if (ip->i_d.di_nextents > 10000) return; bno = NULLFSBLOCK; mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); block = ifp->if_broot; /* * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. */ level = be16_to_cpu(block->bb_level); ASSERT(level > 0); xfs_check_block(block, mp, 1, ifp->if_broot_bytes); pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); bno = be64_to_cpu(*pp); ASSERT(bno != NULLFSBLOCK); ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); /* * Go down the tree until leaf level is reached, following the first * pointer (leftmost) at each level. */ while (level-- > 0) { /* See if buf is in cur first */ bp_release = 0; bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); if (!bp) { bp_release = 1; error = xfs_btree_read_bufl(mp, NULL, bno, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) goto error_norelse; } block = XFS_BUF_TO_BLOCK(bp); if (level == 0) break; /* * Check this block for basic sanity (increasing keys and * no duplicate blocks). */ xfs_check_block(block, mp, 0, 0); pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); XFS_WANT_CORRUPTED_GOTO(mp, xfs_verify_fsbno(mp, bno), error0); if (bp_release) { bp_release = 0; xfs_trans_brelse(NULL, bp); } } /* * Here with bp and block set to the leftmost leaf node in the tree. */ i = 0; /* * Loop over all leaf nodes checking that all extents are in the right order. */ for (;;) { xfs_fsblock_t nextbno; xfs_extnum_t num_recs; num_recs = xfs_btree_get_numrecs(block); /* * Read-ahead the next leaf block, if any. */ nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); /* * Check all the extents to make sure they are OK. * If we had a previous block, the last entry should * conform with the first entry in this one. */ ep = XFS_BMBT_REC_ADDR(mp, block, 1); if (i) { ASSERT(xfs_bmbt_disk_get_startoff(&last) + xfs_bmbt_disk_get_blockcount(&last) <= xfs_bmbt_disk_get_startoff(ep)); } for (j = 1; j < num_recs; j++) { nextp = XFS_BMBT_REC_ADDR(mp, block, j + 1); ASSERT(xfs_bmbt_disk_get_startoff(ep) + xfs_bmbt_disk_get_blockcount(ep) <= xfs_bmbt_disk_get_startoff(nextp)); ep = nextp; } last = *ep; i += num_recs; if (bp_release) { bp_release = 0; xfs_trans_brelse(NULL, bp); } bno = nextbno; /* * If we've reached the end, stop. */ if (bno == NULLFSBLOCK) break; bp_release = 0; bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); if (!bp) { bp_release = 1; error = xfs_btree_read_bufl(mp, NULL, bno, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) goto error_norelse; } block = XFS_BUF_TO_BLOCK(bp); } return; error0: xfs_warn(mp, "%s: at error0", __func__); if (bp_release) xfs_trans_brelse(NULL, bp); error_norelse: xfs_warn(mp, "%s: BAD after btree leaves for %d extents", __func__, i); xfs_err(mp, "%s: CORRUPTED BTREE OR SOMETHING", __func__); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); return; } /* * Validate that the bmbt_irecs being returned from bmapi are valid * given the caller's original parameters. Specifically check the * ranges of the returned irecs to ensure that they only extend beyond * the given parameters if the XFS_BMAPI_ENTIRE flag was set. */ STATIC void xfs_bmap_validate_ret( xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_bmbt_irec_t *mval, int nmap, int ret_nmap) { int i; /* index to map values */ ASSERT(ret_nmap <= nmap); for (i = 0; i < ret_nmap; i++) { ASSERT(mval[i].br_blockcount > 0); if (!(flags & XFS_BMAPI_ENTIRE)) { ASSERT(mval[i].br_startoff >= bno); ASSERT(mval[i].br_blockcount <= len); ASSERT(mval[i].br_startoff + mval[i].br_blockcount <= bno + len); } else { ASSERT(mval[i].br_startoff < bno + len); ASSERT(mval[i].br_startoff + mval[i].br_blockcount > bno); } ASSERT(i == 0 || mval[i - 1].br_startoff + mval[i - 1].br_blockcount == mval[i].br_startoff); ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK && mval[i].br_startblock != HOLESTARTBLOCK); ASSERT(mval[i].br_state == XFS_EXT_NORM || mval[i].br_state == XFS_EXT_UNWRITTEN); } } #else #define xfs_bmap_check_leaf_extents(cur, ip, whichfork) do { } while (0) #define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) do { } while (0) #endif /* DEBUG */ /* * bmap free list manipulation functions */ /* * Add the extent to the list of extents to be free at transaction end. * The list is maintained sorted (by block number). */ void __xfs_bmap_add_free( struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, const struct xfs_owner_info *oinfo, bool skip_discard) { struct xfs_extent_free_item *new; /* new element */ #ifdef DEBUG struct xfs_mount *mp = tp->t_mountp; xfs_agnumber_t agno; xfs_agblock_t agbno; ASSERT(bno != NULLFSBLOCK); ASSERT(len > 0); ASSERT(len <= MAXEXTLEN); ASSERT(!isnullstartblock(bno)); agno = XFS_FSB_TO_AGNO(mp, bno); agbno = XFS_FSB_TO_AGBNO(mp, bno); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno < mp->m_sb.sb_agblocks); ASSERT(len < mp->m_sb.sb_agblocks); ASSERT(agbno + len <= mp->m_sb.sb_agblocks); #endif ASSERT(xfs_bmap_free_item_zone != NULL); new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); new->xefi_startblock = bno; new->xefi_blockcount = (xfs_extlen_t)len; if (oinfo) new->xefi_oinfo = *oinfo; else new->xefi_oinfo = XFS_RMAP_OINFO_SKIP_UPDATE; new->xefi_skip_discard = skip_discard; trace_xfs_bmap_free_defer(tp->t_mountp, XFS_FSB_TO_AGNO(tp->t_mountp, bno), 0, XFS_FSB_TO_AGBNO(tp->t_mountp, bno), len); xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &new->xefi_list); } /* * Inode fork format manipulation functions */ /* * Convert the inode format to extent format if it currently is in btree format, * but the extent list is small enough that it fits into the extent format. * * Since the extents are already in-core, all we have to do is give up the space * for the btree root and pitch the leaf block. */ STATIC int /* error */ xfs_bmap_btree_to_extents( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode pointer */ struct xfs_btree_cur *cur, /* btree cursor */ int *logflagsp, /* inode logging flags */ int whichfork) /* data or attr fork */ { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_mount *mp = ip->i_mount; struct xfs_btree_block *rblock = ifp->if_broot; struct xfs_btree_block *cblock;/* child btree block */ xfs_fsblock_t cbno; /* child block number */ xfs_buf_t *cbp; /* child block's buffer */ int error; /* error return value */ __be64 *pp; /* ptr to block address */ struct xfs_owner_info oinfo; /* check if we actually need the extent format first: */ if (!xfs_bmap_wants_extents(ip, whichfork)) return 0; ASSERT(cur); ASSERT(whichfork != XFS_COW_FORK); ASSERT(ifp->if_flags & XFS_IFEXTENTS); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); ASSERT(be16_to_cpu(rblock->bb_level) == 1); ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1); ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1); pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes); cbno = be64_to_cpu(*pp); #ifdef DEBUG XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, xfs_btree_check_lptr(cur, cbno, 1)); #endif error = xfs_btree_read_bufl(mp, tp, cbno, &cbp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) return error; cblock = XFS_BUF_TO_BLOCK(cbp); if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) return error; xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork); xfs_bmap_add_free(cur->bc_tp, cbno, 1, &oinfo); ip->i_d.di_nblocks--; xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); xfs_trans_binval(tp, cbp); if (cur->bc_bufs[0] == cbp) cur->bc_bufs[0] = NULL; xfs_iroot_realloc(ip, -1, whichfork); ASSERT(ifp->if_broot == NULL); ASSERT((ifp->if_flags & XFS_IFBROOT) == 0); XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); *logflagsp |= XFS_ILOG_CORE | xfs_ilog_fext(whichfork); return 0; } /* * Convert an extents-format file into a btree-format file. * The new file will have a root block (in the inode) and a single child block. */ STATIC int /* error */ xfs_bmap_extents_to_btree( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode pointer */ struct xfs_btree_cur **curp, /* cursor returned to caller */ int wasdel, /* converting a delayed alloc */ int *logflagsp, /* inode logging flags */ int whichfork) /* data or attr fork */ { struct xfs_btree_block *ablock; /* allocated (child) bt block */ struct xfs_buf *abp; /* buffer for ablock */ struct xfs_alloc_arg args; /* allocation arguments */ struct xfs_bmbt_rec *arp; /* child record pointer */ struct xfs_btree_block *block; /* btree root block */ struct xfs_btree_cur *cur; /* bmap btree cursor */ int error; /* error return value */ struct xfs_ifork *ifp; /* inode fork pointer */ struct xfs_bmbt_key *kp; /* root block key pointer */ struct xfs_mount *mp; /* mount structure */ xfs_bmbt_ptr_t *pp; /* root block address pointer */ struct xfs_iext_cursor icur; struct xfs_bmbt_irec rec; xfs_extnum_t cnt = 0; mp = ip->i_mount; ASSERT(whichfork != XFS_COW_FORK); ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); /* * Make space in the inode incore. This needs to be undone if we fail * to expand the root. */ xfs_iroot_realloc(ip, 1, whichfork); ifp->if_flags |= XFS_IFBROOT; /* * Fill in the root. */ block = ifp->if_broot; xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL, XFS_BTNUM_BMAP, 1, 1, ip->i_ino, XFS_BTREE_LONG_PTRS); /* * Need a cursor. Can't allocate until bb_level is filled in. */ cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; /* * Convert to a btree with two levels, one record in root. */ XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = mp; xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork); if (tp->t_firstblock == NULLFSBLOCK) { args.type = XFS_ALLOCTYPE_START_BNO; args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); } else if (tp->t_flags & XFS_TRANS_LOWMODE) { args.type = XFS_ALLOCTYPE_START_BNO; args.fsbno = tp->t_firstblock; } else { args.type = XFS_ALLOCTYPE_NEAR_BNO; args.fsbno = tp->t_firstblock; } args.minlen = args.maxlen = args.prod = 1; args.wasdel = wasdel; *logflagsp = 0; error = xfs_alloc_vextent(&args); if (error) goto out_root_realloc; if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) { error = -ENOSPC; goto out_root_realloc; } /* * Allocation can't fail, the space was reserved. */ ASSERT(tp->t_firstblock == NULLFSBLOCK || args.agno >= XFS_FSB_TO_AGNO(mp, tp->t_firstblock)); tp->t_firstblock = args.fsbno; cur->bc_private.b.allocated++; ip->i_d.di_nblocks++; xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); abp = xfs_btree_get_bufl(mp, tp, args.fsbno); if (!abp) { error = -EFSCORRUPTED; goto out_unreserve_dquot; } /* * Fill in the child block. */ abp->b_ops = &xfs_bmbt_buf_ops; ablock = XFS_BUF_TO_BLOCK(abp); xfs_btree_init_block_int(mp, ablock, abp->b_bn, XFS_BTNUM_BMAP, 0, 0, ip->i_ino, XFS_BTREE_LONG_PTRS); for_each_xfs_iext(ifp, &icur, &rec) { if (isnullstartblock(rec.br_startblock)) continue; arp = XFS_BMBT_REC_ADDR(mp, ablock, 1 + cnt); xfs_bmbt_disk_set_all(arp, &rec); cnt++; } ASSERT(cnt == XFS_IFORK_NEXTENTS(ip, whichfork)); xfs_btree_set_numrecs(ablock, cnt); /* * Fill in the root key and pointer. */ kp = XFS_BMBT_KEY_ADDR(mp, block, 1); arp = XFS_BMBT_REC_ADDR(mp, ablock, 1); kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp)); pp = XFS_BMBT_PTR_ADDR(mp, block, 1, xfs_bmbt_get_maxrecs(cur, be16_to_cpu(block->bb_level))); *pp = cpu_to_be64(args.fsbno); /* * Do all this logging at the end so that * the root is at the right level. */ xfs_btree_log_block(cur, abp, XFS_BB_ALL_BITS); xfs_btree_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs)); ASSERT(*curp == NULL); *curp = cur; *logflagsp = XFS_ILOG_CORE | xfs_ilog_fbroot(whichfork); return 0; out_unreserve_dquot: xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); out_root_realloc: xfs_iroot_realloc(ip, -1, whichfork); XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); ASSERT(ifp->if_broot == NULL); xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Convert a local file to an extents file. * This code is out of bounds for data forks of regular files, * since the file data needs to get logged so things will stay consistent. * (The bmap-level manipulations are ok, though). */ void xfs_bmap_local_to_extents_empty( struct xfs_inode *ip, int whichfork) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(whichfork != XFS_COW_FORK); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); ASSERT(ifp->if_bytes == 0); ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); xfs_bmap_forkoff_reset(ip, whichfork); ifp->if_flags &= ~XFS_IFINLINE; ifp->if_flags |= XFS_IFEXTENTS; ifp->if_u1.if_root = NULL; ifp->if_height = 0; XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); } STATIC int /* error */ xfs_bmap_local_to_extents( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_extlen_t total, /* total blocks needed by transaction */ int *logflagsp, /* inode logging flags */ int whichfork, void (*init_fn)(struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp)) { int error = 0; int flags; /* logging flags returned */ struct xfs_ifork *ifp; /* inode fork pointer */ xfs_alloc_arg_t args; /* allocation arguments */ xfs_buf_t *bp; /* buffer for extent block */ struct xfs_bmbt_irec rec; struct xfs_iext_cursor icur; /* * We don't want to deal with the case of keeping inode data inline yet. * So sending the data fork of a regular inode is invalid. */ ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK)); ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); if (!ifp->if_bytes) { xfs_bmap_local_to_extents_empty(ip, whichfork); flags = XFS_ILOG_CORE; goto done; } flags = 0; error = 0; ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS)) == XFS_IFINLINE); memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = ip->i_mount; xfs_rmap_ino_owner(&args.oinfo, ip->i_ino, whichfork, 0); /* * Allocate a block. We know we need only one, since the * file currently fits in an inode. */ if (tp->t_firstblock == NULLFSBLOCK) { args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); args.type = XFS_ALLOCTYPE_START_BNO; } else { args.fsbno = tp->t_firstblock; args.type = XFS_ALLOCTYPE_NEAR_BNO; } args.total = total; args.minlen = args.maxlen = args.prod = 1; error = xfs_alloc_vextent(&args); if (error) goto done; /* Can't fail, the space was reserved. */ ASSERT(args.fsbno != NULLFSBLOCK); ASSERT(args.len == 1); tp->t_firstblock = args.fsbno; bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno); /* * Initialize the block, copy the data and log the remote buffer. * * The callout is responsible for logging because the remote format * might differ from the local format and thus we don't know how much to * log here. Note that init_fn must also set the buffer log item type * correctly. */ init_fn(tp, bp, ip, ifp); /* account for the change in fork size */ xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); xfs_bmap_local_to_extents_empty(ip, whichfork); flags |= XFS_ILOG_CORE; ifp->if_u1.if_root = NULL; ifp->if_height = 0; rec.br_startoff = 0; rec.br_startblock = args.fsbno; rec.br_blockcount = 1; rec.br_state = XFS_EXT_NORM; xfs_iext_first(ifp, &icur); xfs_iext_insert(ip, &icur, &rec, 0); XFS_IFORK_NEXT_SET(ip, whichfork, 1); ip->i_d.di_nblocks = 1; xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); flags |= xfs_ilog_fext(whichfork); done: *logflagsp = flags; return error; } /* * Called from xfs_bmap_add_attrfork to handle btree format files. */ STATIC int /* error */ xfs_bmap_add_attrfork_btree( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ int *flags) /* inode logging flags */ { xfs_btree_cur_t *cur; /* btree cursor */ int error; /* error return value */ xfs_mount_t *mp; /* file system mount struct */ int stat; /* newroot status */ mp = ip->i_mount; if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip)) *flags |= XFS_ILOG_DBROOT; else { cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK); error = xfs_bmbt_lookup_first(cur, &stat); if (error) goto error0; /* must be at least one entry */ XFS_WANT_CORRUPTED_GOTO(mp, stat == 1, error0); if ((error = xfs_btree_new_iroot(cur, flags, &stat))) goto error0; if (stat == 0) { xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return -ENOSPC; } cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); } return 0; error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Called from xfs_bmap_add_attrfork to handle extents format files. */ STATIC int /* error */ xfs_bmap_add_attrfork_extents( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode pointer */ int *flags) /* inode logging flags */ { xfs_btree_cur_t *cur; /* bmap btree cursor */ int error; /* error return value */ if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip)) return 0; cur = NULL; error = xfs_bmap_extents_to_btree(tp, ip, &cur, 0, flags, XFS_DATA_FORK); if (cur) { cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, error); } return error; } /* * Called from xfs_bmap_add_attrfork to handle local format files. Each * different data fork content type needs a different callout to do the * conversion. Some are basic and only require special block initialisation * callouts for the data formating, others (directories) are so specialised they * handle everything themselves. * * XXX (dgc): investigate whether directory conversion can use the generic * formatting callout. It should be possible - it's just a very complex * formatter. */ STATIC int /* error */ xfs_bmap_add_attrfork_local( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode pointer */ int *flags) /* inode logging flags */ { struct xfs_da_args dargs; /* args for dir/attr code */ if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) return 0; if (S_ISDIR(VFS_I(ip)->i_mode)) { memset(&dargs, 0, sizeof(dargs)); dargs.geo = ip->i_mount->m_dir_geo; dargs.dp = ip; dargs.total = dargs.geo->fsbcount; dargs.whichfork = XFS_DATA_FORK; dargs.trans = tp; return xfs_dir2_sf_to_block(&dargs); } if (S_ISLNK(VFS_I(ip)->i_mode)) return xfs_bmap_local_to_extents(tp, ip, 1, flags, XFS_DATA_FORK, xfs_symlink_local_to_remote); /* should only be called for types that support local format data */ ASSERT(0); return -EFSCORRUPTED; } /* Set an inode attr fork off based on the format */ int xfs_bmap_set_attrforkoff( struct xfs_inode *ip, int size, int *version) { switch (ip->i_d.di_format) { case XFS_DINODE_FMT_DEV: ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; break; case XFS_DINODE_FMT_LOCAL: case XFS_DINODE_FMT_EXTENTS: case XFS_DINODE_FMT_BTREE: ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); if (!ip->i_d.di_forkoff) ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version) *version = 2; break; default: ASSERT(0); return -EINVAL; } return 0; } /* * Convert inode from non-attributed to attributed. * Must not be in a transaction, ip must not be locked. */ int /* error code */ xfs_bmap_add_attrfork( xfs_inode_t *ip, /* incore inode pointer */ int size, /* space new attribute needs */ int rsvd) /* xact may use reserved blks */ { xfs_mount_t *mp; /* mount structure */ xfs_trans_t *tp; /* transaction pointer */ int blks; /* space reservation */ int version = 1; /* superblock attr version */ int logflags; /* logging flags */ int error; /* error return value */ ASSERT(XFS_IFORK_Q(ip) == 0); mp = ip->i_mount; ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); blks = XFS_ADDAFORK_SPACE_RES(mp); error = xfs_trans_alloc(mp, &M_RES(mp)->tr_addafork, blks, 0, rsvd ? XFS_TRANS_RESERVE : 0, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : XFS_QMOPT_RES_REGBLKS); if (error) goto trans_cancel; if (XFS_IFORK_Q(ip)) goto trans_cancel; if (ip->i_d.di_anextents != 0) { error = -EFSCORRUPTED; goto trans_cancel; } if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { /* * For inodes coming from pre-6.2 filesystems. */ ASSERT(ip->i_d.di_aformat == 0); ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; } xfs_trans_ijoin(tp, ip, 0); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_bmap_set_attrforkoff(ip, size, &version); if (error) goto trans_cancel; ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); ip->i_afp->if_flags = XFS_IFEXTENTS; logflags = 0; switch (ip->i_d.di_format) { case XFS_DINODE_FMT_LOCAL: error = xfs_bmap_add_attrfork_local(tp, ip, &logflags); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_bmap_add_attrfork_extents(tp, ip, &logflags); break; case XFS_DINODE_FMT_BTREE: error = xfs_bmap_add_attrfork_btree(tp, ip, &logflags); break; default: error = 0; break; } if (logflags) xfs_trans_log_inode(tp, ip, logflags); if (error) goto trans_cancel; if (!xfs_sb_version_hasattr(&mp->m_sb) || (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) { bool log_sb = false; spin_lock(&mp->m_sb_lock); if (!xfs_sb_version_hasattr(&mp->m_sb)) { xfs_sb_version_addattr(&mp->m_sb); log_sb = true; } if (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2) { xfs_sb_version_addattr2(&mp->m_sb); log_sb = true; } spin_unlock(&mp->m_sb_lock); if (log_sb) xfs_log_sb(tp); } error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; trans_cancel: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; } /* * Internal and external extent tree search functions. */ /* * Read in extents from a btree-format inode. */ int xfs_iread_extents( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork) { struct xfs_mount *mp = ip->i_mount; int state = xfs_bmap_fork_to_state(whichfork); struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); xfs_extnum_t nextents = XFS_IFORK_NEXTENTS(ip, whichfork); struct xfs_btree_block *block = ifp->if_broot; struct xfs_iext_cursor icur; struct xfs_bmbt_irec new; xfs_fsblock_t bno; struct xfs_buf *bp; xfs_extnum_t i, j; int level; __be64 *pp; int error; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } /* * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. */ level = be16_to_cpu(block->bb_level); if (unlikely(level == 0)) { XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); bno = be64_to_cpu(*pp); /* * Go down the tree until leaf level is reached, following the first * pointer (leftmost) at each level. */ while (level-- > 0) { error = xfs_btree_read_bufl(mp, tp, bno, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) goto out; block = XFS_BUF_TO_BLOCK(bp); if (level == 0) break; pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); XFS_WANT_CORRUPTED_GOTO(mp, xfs_verify_fsbno(mp, bno), out_brelse); xfs_trans_brelse(tp, bp); } /* * Here with bp and block set to the leftmost leaf node in the tree. */ i = 0; xfs_iext_first(ifp, &icur); /* * Loop over all leaf nodes. Copy information to the extent records. */ for (;;) { xfs_bmbt_rec_t *frp; xfs_fsblock_t nextbno; xfs_extnum_t num_recs; num_recs = xfs_btree_get_numrecs(block); if (unlikely(i + num_recs > nextents)) { xfs_warn(ip->i_mount, "corrupt dinode %Lu, (btree extents).", (unsigned long long) ip->i_ino); xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block, sizeof(*block), __this_address); error = -EFSCORRUPTED; goto out_brelse; } /* * Read-ahead the next leaf block, if any. */ nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); if (nextbno != NULLFSBLOCK) xfs_btree_reada_bufl(mp, nextbno, 1, &xfs_bmbt_buf_ops); /* * Copy records into the extent records. */ frp = XFS_BMBT_REC_ADDR(mp, block, 1); for (j = 0; j < num_recs; j++, frp++, i++) { xfs_failaddr_t fa; xfs_bmbt_disk_get_all(frp, &new); fa = xfs_bmap_validate_extent(ip, whichfork, &new); if (fa) { error = -EFSCORRUPTED; xfs_inode_verifier_error(ip, error, "xfs_iread_extents(2)", frp, sizeof(*frp), fa); goto out_brelse; } xfs_iext_insert(ip, &icur, &new, state); trace_xfs_read_extent(ip, &icur, state, _THIS_IP_); xfs_iext_next(ifp, &icur); } xfs_trans_brelse(tp, bp); bno = nextbno; /* * If we've reached the end, stop. */ if (bno == NULLFSBLOCK) break; error = xfs_btree_read_bufl(mp, tp, bno, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) goto out; block = XFS_BUF_TO_BLOCK(bp); } if (i != XFS_IFORK_NEXTENTS(ip, whichfork)) { error = -EFSCORRUPTED; goto out; } ASSERT(i == xfs_iext_count(ifp)); ifp->if_flags |= XFS_IFEXTENTS; return 0; out_brelse: xfs_trans_brelse(tp, bp); out: xfs_iext_destroy(ifp); return error; } /* * Returns the relative block number of the first unused block(s) in the given * fork with at least "len" logically contiguous blocks free. This is the * lowest-address hole if the fork has holes, else the first block past the end * of fork. Return 0 if the fork is currently local (in-inode). */ int /* error */ xfs_bmap_first_unused( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_extlen_t len, /* size of hole to find */ xfs_fileoff_t *first_unused, /* unused block */ int whichfork) /* data or attr fork */ { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_bmbt_irec got; struct xfs_iext_cursor icur; xfs_fileoff_t lastaddr = 0; xfs_fileoff_t lowest, max; int error; ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE || XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS || XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { *first_unused = 0; return 0; } if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } lowest = max = *first_unused; for_each_xfs_iext(ifp, &icur, &got) { /* * See if the hole before this extent will work. */ if (got.br_startoff >= lowest + len && got.br_startoff - max >= len) break; lastaddr = got.br_startoff + got.br_blockcount; max = XFS_FILEOFF_MAX(lastaddr, lowest); } *first_unused = max; return 0; } /* * Returns the file-relative block number of the last block - 1 before * last_block (input value) in the file. * This is not based on i_size, it is based on the extent records. * Returns 0 for local files, as they do not have extent records. */ int /* error */ xfs_bmap_last_before( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t *last_block, /* last block */ int whichfork) /* data or attr fork */ { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_bmbt_irec got; struct xfs_iext_cursor icur; int error; switch (XFS_IFORK_FORMAT(ip, whichfork)) { case XFS_DINODE_FMT_LOCAL: *last_block = 0; return 0; case XFS_DINODE_FMT_BTREE: case XFS_DINODE_FMT_EXTENTS: break; default: return -EIO; } if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } if (!xfs_iext_lookup_extent_before(ip, ifp, last_block, &icur, &got)) *last_block = 0; return 0; } int xfs_bmap_last_extent( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *rec, int *is_empty) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_iext_cursor icur; int error; if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } xfs_iext_last(ifp, &icur); if (!xfs_iext_get_extent(ifp, &icur, rec)) *is_empty = 1; else *is_empty = 0; return 0; } /* * Check the last inode extent to determine whether this allocation will result * in blocks being allocated at the end of the file. When we allocate new data * blocks at the end of the file which do not start at the previous data block, * we will try to align the new blocks at stripe unit boundaries. * * Returns 1 in bma->aeof if the file (fork) is empty as any new write will be * at, or past the EOF. */ STATIC int xfs_bmap_isaeof( struct xfs_bmalloca *bma, int whichfork) { struct xfs_bmbt_irec rec; int is_empty; int error; bma->aeof = false; error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec, &is_empty); if (error) return error; if (is_empty) { bma->aeof = true; return 0; } /* * Check if we are allocation or past the last extent, or at least into * the last delayed allocated extent. */ bma->aeof = bma->offset >= rec.br_startoff + rec.br_blockcount || (bma->offset >= rec.br_startoff && isnullstartblock(rec.br_startblock)); return 0; } /* * Returns the file-relative block number of the first block past eof in * the file. This is not based on i_size, it is based on the extent records. * Returns 0 for local files, as they do not have extent records. */ int xfs_bmap_last_offset( struct xfs_inode *ip, xfs_fileoff_t *last_block, int whichfork) { struct xfs_bmbt_irec rec; int is_empty; int error; *last_block = 0; if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) return 0; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) return -EIO; error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty); if (error || is_empty) return error; *last_block = rec.br_startoff + rec.br_blockcount; return 0; } /* * Returns whether the selected fork of the inode has exactly one * block or not. For the data fork we check this matches di_size, * implying the file's range is 0..bsize-1. */ int /* 1=>1 block, 0=>otherwise */ xfs_bmap_one_block( xfs_inode_t *ip, /* incore inode */ int whichfork) /* data or attr fork */ { struct xfs_ifork *ifp; /* inode fork pointer */ int rval; /* return value */ xfs_bmbt_irec_t s; /* internal version of extent */ struct xfs_iext_cursor icur; #ifndef DEBUG if (whichfork == XFS_DATA_FORK) return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize; #endif /* !DEBUG */ if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) return 0; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) return 0; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(ifp->if_flags & XFS_IFEXTENTS); xfs_iext_first(ifp, &icur); xfs_iext_get_extent(ifp, &icur, &s); rval = s.br_startoff == 0 && s.br_blockcount == 1; if (rval && whichfork == XFS_DATA_FORK) ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize); return rval; } /* * Extent tree manipulation functions used during allocation. */ /* * Convert a delayed allocation to a real allocation. */ STATIC int /* error */ xfs_bmap_add_extent_delay_real( struct xfs_bmalloca *bma, int whichfork) { struct xfs_bmbt_irec *new = &bma->got; int error; /* error return value */ int i; /* temp state */ struct xfs_ifork *ifp; /* inode fork pointer */ xfs_fileoff_t new_endoff; /* end offset of new entry */ xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ /* left is 0, right is 1, prev is 2 */ int rval=0; /* return value (logging flags) */ int state = xfs_bmap_fork_to_state(whichfork); xfs_filblks_t da_new; /* new count del alloc blocks used */ xfs_filblks_t da_old; /* old count del alloc blocks used */ xfs_filblks_t temp=0; /* value for da_new calculations */ int tmp_rval; /* partial logging flags */ struct xfs_mount *mp; xfs_extnum_t *nextents; struct xfs_bmbt_irec old; mp = bma->ip->i_mount; ifp = XFS_IFORK_PTR(bma->ip, whichfork); ASSERT(whichfork != XFS_ATTR_FORK); nextents = (whichfork == XFS_COW_FORK ? &bma->ip->i_cnextents : &bma->ip->i_d.di_nextents); ASSERT(!isnullstartblock(new->br_startblock)); ASSERT(!bma->cur || (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); XFS_STATS_INC(mp, xs_add_exlist); #define LEFT r[0] #define RIGHT r[1] #define PREV r[2] /* * Set up a bunch of variables to make the tests simpler. */ xfs_iext_get_extent(ifp, &bma->icur, &PREV); new_endoff = new->br_startoff + new->br_blockcount; ASSERT(isnullstartblock(PREV.br_startblock)); ASSERT(PREV.br_startoff <= new->br_startoff); ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); da_old = startblockval(PREV.br_startblock); da_new = 0; /* * Set flags determining what part of the previous delayed allocation * extent is being replaced by a real allocation. */ if (PREV.br_startoff == new->br_startoff) state |= BMAP_LEFT_FILLING; if (PREV.br_startoff + PREV.br_blockcount == new_endoff) state |= BMAP_RIGHT_FILLING; /* * Check and set flags if this segment has a left neighbor. * Don't set contiguous if the combined extent would be too large. */ if (xfs_iext_peek_prev_extent(ifp, &bma->icur, &LEFT)) { state |= BMAP_LEFT_VALID; if (isnullstartblock(LEFT.br_startblock)) state |= BMAP_LEFT_DELAY; } if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && LEFT.br_state == new->br_state && LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; /* * Check and set flags if this segment has a right neighbor. * Don't set contiguous if the combined extent would be too large. * Also check for all-three-contiguous being too large. */ if (xfs_iext_peek_next_extent(ifp, &bma->icur, &RIGHT)) { state |= BMAP_RIGHT_VALID; if (isnullstartblock(RIGHT.br_startblock)) state |= BMAP_RIGHT_DELAY; } if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && new_endoff == RIGHT.br_startoff && new->br_startblock + new->br_blockcount == RIGHT.br_startblock && new->br_state == RIGHT.br_state && new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) != (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING) || LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN)) state |= BMAP_RIGHT_CONTIG; error = 0; /* * Switch out based on the FILLING and CONTIG state bits. */ switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Filling in all of a previously delayed allocation extent. * The left and right neighbors are both contiguous with new. */ LEFT.br_blockcount += PREV.br_blockcount + RIGHT.br_blockcount; xfs_iext_remove(bma->ip, &bma->icur, state); xfs_iext_remove(bma->ip, &bma->icur, state); xfs_iext_prev(ifp, &bma->icur); xfs_iext_update_extent(bma->ip, state, &bma->icur, &LEFT); (*nextents)--; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, &RIGHT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_delete(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(bma->cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, &LEFT); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: /* * Filling in all of a previously delayed allocation extent. * The left neighbor is contiguous, the right is not. */ old = LEFT; LEFT.br_blockcount += PREV.br_blockcount; xfs_iext_remove(bma->ip, &bma->icur, state); xfs_iext_prev(ifp, &bma->icur); xfs_iext_update_extent(bma->ip, state, &bma->icur, &LEFT); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, &LEFT); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Filling in all of a previously delayed allocation extent. * The right neighbor is contiguous, the left is not. Take care * with delay -> unwritten extent allocation here because the * delalloc record we are overwriting is always written. */ PREV.br_startblock = new->br_startblock; PREV.br_blockcount += RIGHT.br_blockcount; PREV.br_state = new->br_state; xfs_iext_next(ifp, &bma->icur); xfs_iext_remove(bma->ip, &bma->icur, state); xfs_iext_prev(ifp, &bma->icur); xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, &RIGHT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, &PREV); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Filling in all of a previously delayed allocation extent. * Neither the left nor right neighbors are contiguous with * the new one. */ PREV.br_startblock = new->br_startblock; PREV.br_state = new->br_state; xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV); (*nextents)++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: /* * Filling in the first part of a previous delayed allocation. * The left neighbor is contiguous. */ old = LEFT; temp = PREV.br_blockcount - new->br_blockcount; da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock)); LEFT.br_blockcount += new->br_blockcount; PREV.br_blockcount = temp; PREV.br_startoff += new->br_blockcount; PREV.br_startblock = nullstartblock(da_new); xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV); xfs_iext_prev(ifp, &bma->icur); xfs_iext_update_extent(bma->ip, state, &bma->icur, &LEFT); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, &LEFT); if (error) goto done; } break; case BMAP_LEFT_FILLING: /* * Filling in the first part of a previous delayed allocation. * The left neighbor is not contiguous. */ xfs_iext_update_extent(bma->ip, state, &bma->icur, new); (*nextents)++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (xfs_bmap_needs_btree(bma->ip, whichfork)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, &bma->cur, 1, &tmp_rval, whichfork); rval |= tmp_rval; if (error) goto done; } temp = PREV.br_blockcount - new->br_blockcount; da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock) - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); PREV.br_startoff = new_endoff; PREV.br_blockcount = temp; PREV.br_startblock = nullstartblock(da_new); xfs_iext_next(ifp, &bma->icur); xfs_iext_insert(bma->ip, &bma->icur, &PREV, state); xfs_iext_prev(ifp, &bma->icur); break; case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Filling in the last part of a previous delayed allocation. * The right neighbor is contiguous with the new allocation. */ old = RIGHT; RIGHT.br_startoff = new->br_startoff; RIGHT.br_startblock = new->br_startblock; RIGHT.br_blockcount += new->br_blockcount; if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, &RIGHT); if (error) goto done; } temp = PREV.br_blockcount - new->br_blockcount; da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock)); PREV.br_blockcount = temp; PREV.br_startblock = nullstartblock(da_new); xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV); xfs_iext_next(ifp, &bma->icur); xfs_iext_update_extent(bma->ip, state, &bma->icur, &RIGHT); break; case BMAP_RIGHT_FILLING: /* * Filling in the last part of a previous delayed allocation. * The right neighbor is not contiguous. */ xfs_iext_update_extent(bma->ip, state, &bma->icur, new); (*nextents)++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (xfs_bmap_needs_btree(bma->ip, whichfork)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, &bma->cur, 1, &tmp_rval, whichfork); rval |= tmp_rval; if (error) goto done; } temp = PREV.br_blockcount - new->br_blockcount; da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock) - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); PREV.br_startblock = nullstartblock(da_new); PREV.br_blockcount = temp; xfs_iext_insert(bma->ip, &bma->icur, &PREV, state); xfs_iext_next(ifp, &bma->icur); break; case 0: /* * Filling in the middle part of a previous delayed allocation. * Contiguity is impossible here. * This case is avoided almost all the time. * * We start with a delayed allocation: * * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+ * PREV @ idx * * and we are allocating: * +rrrrrrrrrrrrrrrrr+ * new * * and we set it up for insertion as: * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+ * new * PREV @ idx LEFT RIGHT * inserted at idx + 1 */ old = PREV; /* LEFT is the new middle */ LEFT = *new; /* RIGHT is the new right */ RIGHT.br_state = PREV.br_state; RIGHT.br_startoff = new_endoff; RIGHT.br_blockcount = PREV.br_startoff + PREV.br_blockcount - new_endoff; RIGHT.br_startblock = nullstartblock(xfs_bmap_worst_indlen(bma->ip, RIGHT.br_blockcount)); /* truncate PREV */ PREV.br_blockcount = new->br_startoff - PREV.br_startoff; PREV.br_startblock = nullstartblock(xfs_bmap_worst_indlen(bma->ip, PREV.br_blockcount)); xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV); xfs_iext_next(ifp, &bma->icur); xfs_iext_insert(bma->ip, &bma->icur, &RIGHT, state); xfs_iext_insert(bma->ip, &bma->icur, &LEFT, state); (*nextents)++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (xfs_bmap_needs_btree(bma->ip, whichfork)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, &bma->cur, 1, &tmp_rval, whichfork); rval |= tmp_rval; if (error) goto done; } da_new = startblockval(PREV.br_startblock) + startblockval(RIGHT.br_startblock); break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_CONTIG: case BMAP_RIGHT_CONTIG: /* * These cases are all impossible. */ ASSERT(0); } /* add reverse mapping unless caller opted out */ if (!(bma->flags & XFS_BMAPI_NORMAP)) { error = xfs_rmap_map_extent(bma->tp, bma->ip, whichfork, new); if (error) goto done; } /* convert to a btree if necessary */ if (xfs_bmap_needs_btree(bma->ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(bma->cur == NULL); error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, &bma->cur, da_old > 0, &tmp_logflags, whichfork); bma->logflags |= tmp_logflags; if (error) goto done; } if (da_new != da_old) xfs_mod_delalloc(mp, (int64_t)da_new - da_old); if (bma->cur) { da_new += bma->cur->bc_private.b.allocated; bma->cur->bc_private.b.allocated = 0; } /* adjust for changes in reserved delayed indirect blocks */ if (da_new != da_old) { ASSERT(state == 0 || da_new < da_old); error = xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false); } xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork); done: if (whichfork != XFS_COW_FORK) bma->logflags |= rval; return error; #undef LEFT #undef RIGHT #undef PREV } /* * Convert an unwritten allocation to a real allocation or vice versa. */ int /* error */ xfs_bmap_add_extent_unwritten_real( struct xfs_trans *tp, xfs_inode_t *ip, /* incore inode pointer */ int whichfork, struct xfs_iext_cursor *icur, xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ xfs_bmbt_irec_t *new, /* new data to add to file extents */ int *logflagsp) /* inode logging flags */ { xfs_btree_cur_t *cur; /* btree cursor */ int error; /* error return value */ int i; /* temp state */ struct xfs_ifork *ifp; /* inode fork pointer */ xfs_fileoff_t new_endoff; /* end offset of new entry */ xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ /* left is 0, right is 1, prev is 2 */ int rval=0; /* return value (logging flags) */ int state = xfs_bmap_fork_to_state(whichfork); struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec old; *logflagsp = 0; cur = *curp; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(!isnullstartblock(new->br_startblock)); XFS_STATS_INC(mp, xs_add_exlist); #define LEFT r[0] #define RIGHT r[1] #define PREV r[2] /* * Set up a bunch of variables to make the tests simpler. */ error = 0; xfs_iext_get_extent(ifp, icur, &PREV); ASSERT(new->br_state != PREV.br_state); new_endoff = new->br_startoff + new->br_blockcount; ASSERT(PREV.br_startoff <= new->br_startoff); ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); /* * Set flags determining what part of the previous oldext allocation * extent is being replaced by a newext allocation. */ if (PREV.br_startoff == new->br_startoff) state |= BMAP_LEFT_FILLING; if (PREV.br_startoff + PREV.br_blockcount == new_endoff) state |= BMAP_RIGHT_FILLING; /* * Check and set flags if this segment has a left neighbor. * Don't set contiguous if the combined extent would be too large. */ if (xfs_iext_peek_prev_extent(ifp, icur, &LEFT)) { state |= BMAP_LEFT_VALID; if (isnullstartblock(LEFT.br_startblock)) state |= BMAP_LEFT_DELAY; } if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && LEFT.br_state == new->br_state && LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; /* * Check and set flags if this segment has a right neighbor. * Don't set contiguous if the combined extent would be too large. * Also check for all-three-contiguous being too large. */ if (xfs_iext_peek_next_extent(ifp, icur, &RIGHT)) { state |= BMAP_RIGHT_VALID; if (isnullstartblock(RIGHT.br_startblock)) state |= BMAP_RIGHT_DELAY; } if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && new_endoff == RIGHT.br_startoff && new->br_startblock + new->br_blockcount == RIGHT.br_startblock && new->br_state == RIGHT.br_state && new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) != (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING) || LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN)) state |= BMAP_RIGHT_CONTIG; /* * Switch out based on the FILLING and CONTIG state bits. */ switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left and right neighbors are both contiguous with new. */ LEFT.br_blockcount += PREV.br_blockcount + RIGHT.br_blockcount; xfs_iext_remove(ip, icur, state); xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &LEFT); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 2); if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &RIGHT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &LEFT); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left neighbor is contiguous, the right is not. */ LEFT.br_blockcount += PREV.br_blockcount; xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &LEFT); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &PREV, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &LEFT); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The right neighbor is contiguous, the left is not. */ PREV.br_blockcount += RIGHT.br_blockcount; PREV.br_state = new->br_state; xfs_iext_next(ifp, icur); xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &PREV); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &RIGHT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &PREV); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Setting all of a previous oldext extent to newext. * Neither the left nor right neighbors are contiguous with * the new one. */ PREV.br_state = new->br_state; xfs_iext_update_extent(ip, state, icur, &PREV); if (cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &PREV); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is contiguous. */ LEFT.br_blockcount += new->br_blockcount; old = PREV; PREV.br_startoff += new->br_blockcount; PREV.br_startblock += new->br_blockcount; PREV.br_blockcount -= new->br_blockcount; xfs_iext_update_extent(ip, state, icur, &PREV); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &LEFT); if (cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &PREV); if (error) goto done; error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; error = xfs_bmbt_update(cur, &LEFT); if (error) goto done; } break; case BMAP_LEFT_FILLING: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is not contiguous. */ old = PREV; PREV.br_startoff += new->br_blockcount; PREV.br_startblock += new->br_blockcount; PREV.br_blockcount -= new->br_blockcount; xfs_iext_update_extent(ip, state, icur, &PREV); xfs_iext_insert(ip, icur, new, state); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &PREV); if (error) goto done; cur->bc_rec.b = *new; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is contiguous with the new allocation. */ old = PREV; PREV.br_blockcount -= new->br_blockcount; RIGHT.br_startoff = new->br_startoff; RIGHT.br_startblock = new->br_startblock; RIGHT.br_blockcount += new->br_blockcount; xfs_iext_update_extent(ip, state, icur, &PREV); xfs_iext_next(ifp, icur); xfs_iext_update_extent(ip, state, icur, &RIGHT); if (cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &PREV); if (error) goto done; error = xfs_btree_increment(cur, 0, &i); if (error) goto done; error = xfs_bmbt_update(cur, &RIGHT); if (error) goto done; } break; case BMAP_RIGHT_FILLING: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is not contiguous. */ old = PREV; PREV.br_blockcount -= new->br_blockcount; xfs_iext_update_extent(ip, state, icur, &PREV); xfs_iext_next(ifp, icur); xfs_iext_insert(ip, icur, new, state); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &PREV); if (error) goto done; error = xfs_bmbt_lookup_eq(cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case 0: /* * Setting the middle part of a previous oldext extent to * newext. Contiguity is impossible here. * One extent becomes three extents. */ old = PREV; PREV.br_blockcount = new->br_startoff - PREV.br_startoff; r[0] = *new; r[1].br_startoff = new_endoff; r[1].br_blockcount = old.br_startoff + old.br_blockcount - new_endoff; r[1].br_startblock = new->br_startblock + new->br_blockcount; r[1].br_state = PREV.br_state; xfs_iext_update_extent(ip, state, icur, &PREV); xfs_iext_next(ifp, icur); xfs_iext_insert(ip, icur, &r[1], state); xfs_iext_insert(ip, icur, &r[0], state); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 2); if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* new right extent - oldext */ error = xfs_bmbt_update(cur, &r[1]); if (error) goto done; /* new left extent - oldext */ cur->bc_rec.b = PREV; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* * Reset the cursor to the position of the new extent * we are about to insert as we can't trust it after * the previous insert. */ error = xfs_bmbt_lookup_eq(cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); /* new middle extent - newext */ if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_CONTIG: case BMAP_RIGHT_CONTIG: /* * These cases are all impossible. */ ASSERT(0); } /* update reverse mappings */ error = xfs_rmap_convert_extent(mp, tp, ip, whichfork, new); if (error) goto done; /* convert to a btree if necessary */ if (xfs_bmap_needs_btree(ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, &cur, 0, &tmp_logflags, whichfork); *logflagsp |= tmp_logflags; if (error) goto done; } /* clear out the allocated field, done with it now in any case. */ if (cur) { cur->bc_private.b.allocated = 0; *curp = cur; } xfs_bmap_check_leaf_extents(*curp, ip, whichfork); done: *logflagsp |= rval; return error; #undef LEFT #undef RIGHT #undef PREV } /* * Convert a hole to a delayed allocation. */ STATIC void xfs_bmap_add_extent_hole_delay( xfs_inode_t *ip, /* incore inode pointer */ int whichfork, struct xfs_iext_cursor *icur, xfs_bmbt_irec_t *new) /* new data to add to file extents */ { struct xfs_ifork *ifp; /* inode fork pointer */ xfs_bmbt_irec_t left; /* left neighbor extent entry */ xfs_filblks_t newlen=0; /* new indirect size */ xfs_filblks_t oldlen=0; /* old indirect size */ xfs_bmbt_irec_t right; /* right neighbor extent entry */ int state = xfs_bmap_fork_to_state(whichfork); xfs_filblks_t temp; /* temp for indirect calculations */ ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(isnullstartblock(new->br_startblock)); /* * Check and set flags if this segment has a left neighbor */ if (xfs_iext_peek_prev_extent(ifp, icur, &left)) { state |= BMAP_LEFT_VALID; if (isnullstartblock(left.br_startblock)) state |= BMAP_LEFT_DELAY; } /* * Check and set flags if the current (right) segment exists. * If it doesn't exist, we're converting the hole at end-of-file. */ if (xfs_iext_get_extent(ifp, icur, &right)) { state |= BMAP_RIGHT_VALID; if (isnullstartblock(right.br_startblock)) state |= BMAP_RIGHT_DELAY; } /* * Set contiguity flags on the left and right neighbors. * Don't let extents get too large, even if the pieces are contiguous. */ if ((state & BMAP_LEFT_VALID) && (state & BMAP_LEFT_DELAY) && left.br_startoff + left.br_blockcount == new->br_startoff && left.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; if ((state & BMAP_RIGHT_VALID) && (state & BMAP_RIGHT_DELAY) && new->br_startoff + new->br_blockcount == right.br_startoff && new->br_blockcount + right.br_blockcount <= MAXEXTLEN && (!(state & BMAP_LEFT_CONTIG) || (left.br_blockcount + new->br_blockcount + right.br_blockcount <= MAXEXTLEN))) state |= BMAP_RIGHT_CONTIG; /* * Switch out based on the contiguity flags. */ switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with delayed allocations * on the left and on the right. * Merge all three into a single extent record. */ temp = left.br_blockcount + new->br_blockcount + right.br_blockcount; oldlen = startblockval(left.br_startblock) + startblockval(new->br_startblock) + startblockval(right.br_startblock); newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), oldlen); left.br_startblock = nullstartblock(newlen); left.br_blockcount = temp; xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &left); break; case BMAP_LEFT_CONTIG: /* * New allocation is contiguous with a delayed allocation * on the left. * Merge the new allocation with the left neighbor. */ temp = left.br_blockcount + new->br_blockcount; oldlen = startblockval(left.br_startblock) + startblockval(new->br_startblock); newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), oldlen); left.br_blockcount = temp; left.br_startblock = nullstartblock(newlen); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &left); break; case BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with a delayed allocation * on the right. * Merge the new allocation with the right neighbor. */ temp = new->br_blockcount + right.br_blockcount; oldlen = startblockval(new->br_startblock) + startblockval(right.br_startblock); newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), oldlen); right.br_startoff = new->br_startoff; right.br_startblock = nullstartblock(newlen); right.br_blockcount = temp; xfs_iext_update_extent(ip, state, icur, &right); break; case 0: /* * New allocation is not contiguous with another * delayed allocation. * Insert a new entry. */ oldlen = newlen = 0; xfs_iext_insert(ip, icur, new, state); break; } if (oldlen != newlen) { ASSERT(oldlen > newlen); xfs_mod_fdblocks(ip->i_mount, (int64_t)(oldlen - newlen), false); /* * Nothing to do for disk quota accounting here. */ xfs_mod_delalloc(ip->i_mount, (int64_t)newlen - oldlen); } } /* * Convert a hole to a real allocation. */ STATIC int /* error */ xfs_bmap_add_extent_hole_real( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_iext_cursor *icur, struct xfs_btree_cur **curp, struct xfs_bmbt_irec *new, int *logflagsp, int flags) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_mount *mp = ip->i_mount; struct xfs_btree_cur *cur = *curp; int error; /* error return value */ int i; /* temp state */ xfs_bmbt_irec_t left; /* left neighbor extent entry */ xfs_bmbt_irec_t right; /* right neighbor extent entry */ int rval=0; /* return value (logging flags) */ int state = xfs_bmap_fork_to_state(whichfork); struct xfs_bmbt_irec old; ASSERT(!isnullstartblock(new->br_startblock)); ASSERT(!cur || !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); XFS_STATS_INC(mp, xs_add_exlist); /* * Check and set flags if this segment has a left neighbor. */ if (xfs_iext_peek_prev_extent(ifp, icur, &left)) { state |= BMAP_LEFT_VALID; if (isnullstartblock(left.br_startblock)) state |= BMAP_LEFT_DELAY; } /* * Check and set flags if this segment has a current value. * Not true if we're inserting into the "hole" at eof. */ if (xfs_iext_get_extent(ifp, icur, &right)) { state |= BMAP_RIGHT_VALID; if (isnullstartblock(right.br_startblock)) state |= BMAP_RIGHT_DELAY; } /* * We're inserting a real allocation between "left" and "right". * Set the contiguity flags. Don't let extents get too large. */ if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && left.br_startoff + left.br_blockcount == new->br_startoff && left.br_startblock + left.br_blockcount == new->br_startblock && left.br_state == new->br_state && left.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && new->br_startoff + new->br_blockcount == right.br_startoff && new->br_startblock + new->br_blockcount == right.br_startblock && new->br_state == right.br_state && new->br_blockcount + right.br_blockcount <= MAXEXTLEN && (!(state & BMAP_LEFT_CONTIG) || left.br_blockcount + new->br_blockcount + right.br_blockcount <= MAXEXTLEN)) state |= BMAP_RIGHT_CONTIG; error = 0; /* * Select which case we're in here, and implement it. */ switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with real allocations on the * left and on the right. * Merge all three into a single extent record. */ left.br_blockcount += new->br_blockcount + right.br_blockcount; xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &left); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); if (cur == NULL) { rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); } else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, &right, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_delete(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &left); if (error) goto done; } break; case BMAP_LEFT_CONTIG: /* * New allocation is contiguous with a real allocation * on the left. * Merge the new allocation with the left neighbor. */ old = left; left.br_blockcount += new->br_blockcount; xfs_iext_prev(ifp, icur); xfs_iext_update_extent(ip, state, icur, &left); if (cur == NULL) { rval = xfs_ilog_fext(whichfork); } else { rval = 0; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &left); if (error) goto done; } break; case BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with a real allocation * on the right. * Merge the new allocation with the right neighbor. */ old = right; right.br_startoff = new->br_startoff; right.br_startblock = new->br_startblock; right.br_blockcount += new->br_blockcount; xfs_iext_update_extent(ip, state, icur, &right); if (cur == NULL) { rval = xfs_ilog_fext(whichfork); } else { rval = 0; error = xfs_bmbt_lookup_eq(cur, &old, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(cur, &right); if (error) goto done; } break; case 0: /* * New allocation is not contiguous with another * real allocation. * Insert a new entry. */ xfs_iext_insert(ip, icur, new, state); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); if (cur == NULL) { rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); } else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(cur, new, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); error = xfs_btree_insert(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; } /* add reverse mapping unless caller opted out */ if (!(flags & XFS_BMAPI_NORMAP)) { error = xfs_rmap_map_extent(tp, ip, whichfork, new); if (error) goto done; } /* convert to a btree if necessary */ if (xfs_bmap_needs_btree(ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, curp, 0, &tmp_logflags, whichfork); *logflagsp |= tmp_logflags; cur = *curp; if (error) goto done; } /* clear out the allocated field, done with it now in any case. */ if (cur) cur->bc_private.b.allocated = 0; xfs_bmap_check_leaf_extents(cur, ip, whichfork); done: *logflagsp |= rval; return error; } /* * Functions used in the extent read, allocate and remove paths */ /* * Adjust the size of the new extent based on di_extsize and rt extsize. */ int xfs_bmap_extsize_align( xfs_mount_t *mp, xfs_bmbt_irec_t *gotp, /* next extent pointer */ xfs_bmbt_irec_t *prevp, /* previous extent pointer */ xfs_extlen_t extsz, /* align to this extent size */ int rt, /* is this a realtime inode? */ int eof, /* is extent at end-of-file? */ int delay, /* creating delalloc extent? */ int convert, /* overwriting unwritten extent? */ xfs_fileoff_t *offp, /* in/out: aligned offset */ xfs_extlen_t *lenp) /* in/out: aligned length */ { xfs_fileoff_t orig_off; /* original offset */ xfs_extlen_t orig_alen; /* original length */ xfs_fileoff_t orig_end; /* original off+len */ xfs_fileoff_t nexto; /* next file offset */ xfs_fileoff_t prevo; /* previous file offset */ xfs_fileoff_t align_off; /* temp for offset */ xfs_extlen_t align_alen; /* temp for length */ xfs_extlen_t temp; /* temp for calculations */ if (convert) return 0; orig_off = align_off = *offp; orig_alen = align_alen = *lenp; orig_end = orig_off + orig_alen; /* * If this request overlaps an existing extent, then don't * attempt to perform any additional alignment. */ if (!delay && !eof && (orig_off >= gotp->br_startoff) && (orig_end <= gotp->br_startoff + gotp->br_blockcount)) { return 0; } /* * If the file offset is unaligned vs. the extent size * we need to align it. This will be possible unless * the file was previously written with a kernel that didn't * perform this alignment, or if a truncate shot us in the * foot. */ div_u64_rem(orig_off, extsz, &temp); if (temp) { align_alen += temp; align_off -= temp; } /* Same adjustment for the end of the requested area. */ temp = (align_alen % extsz); if (temp) align_alen += extsz - temp; /* * For large extent hint sizes, the aligned extent might be larger than * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls * the length back under MAXEXTLEN. The outer allocation loops handle * short allocation just fine, so it is safe to do this. We only want to * do it when we are forced to, though, because it means more allocation * operations are required. */ while (align_alen > MAXEXTLEN) align_alen -= extsz; ASSERT(align_alen <= MAXEXTLEN); /* * If the previous block overlaps with this proposed allocation * then move the start forward without adjusting the length. */ if (prevp->br_startoff != NULLFILEOFF) { if (prevp->br_startblock == HOLESTARTBLOCK) prevo = prevp->br_startoff; else prevo = prevp->br_startoff + prevp->br_blockcount; } else prevo = 0; if (align_off != orig_off && align_off < prevo) align_off = prevo; /* * If the next block overlaps with this proposed allocation * then move the start back without adjusting the length, * but not before offset 0. * This may of course make the start overlap previous block, * and if we hit the offset 0 limit then the next block * can still overlap too. */ if (!eof && gotp->br_startoff != NULLFILEOFF) { if ((delay && gotp->br_startblock == HOLESTARTBLOCK) || (!delay && gotp->br_startblock == DELAYSTARTBLOCK)) nexto = gotp->br_startoff + gotp->br_blockcount; else nexto = gotp->br_startoff; } else nexto = NULLFILEOFF; if (!eof && align_off + align_alen != orig_end && align_off + align_alen > nexto) align_off = nexto > align_alen ? nexto - align_alen : 0; /* * If we're now overlapping the next or previous extent that * means we can't fit an extsz piece in this hole. Just move * the start forward to the first valid spot and set * the length so we hit the end. */ if (align_off != orig_off && align_off < prevo) align_off = prevo; if (align_off + align_alen != orig_end && align_off + align_alen > nexto && nexto != NULLFILEOFF) { ASSERT(nexto > prevo); align_alen = nexto - align_off; } /* * If realtime, and the result isn't a multiple of the realtime * extent size we need to remove blocks until it is. */ if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) { /* * We're not covering the original request, or * we won't be able to once we fix the length. */ if (orig_off < align_off || orig_end > align_off + align_alen || align_alen - temp < orig_alen) return -EINVAL; /* * Try to fix it by moving the start up. */ if (align_off + temp <= orig_off) { align_alen -= temp; align_off += temp; } /* * Try to fix it by moving the end in. */ else if (align_off + align_alen - temp >= orig_end) align_alen -= temp; /* * Set the start to the minimum then trim the length. */ else { align_alen -= orig_off - align_off; align_off = orig_off; align_alen -= align_alen % mp->m_sb.sb_rextsize; } /* * Result doesn't cover the request, fail it. */ if (orig_off < align_off || orig_end > align_off + align_alen) return -EINVAL; } else { ASSERT(orig_off >= align_off); /* see MAXEXTLEN handling above */ ASSERT(orig_end <= align_off + align_alen || align_alen + extsz > MAXEXTLEN); } #ifdef DEBUG if (!eof && gotp->br_startoff != NULLFILEOFF) ASSERT(align_off + align_alen <= gotp->br_startoff); if (prevp->br_startoff != NULLFILEOFF) ASSERT(align_off >= prevp->br_startoff + prevp->br_blockcount); #endif *lenp = align_alen; *offp = align_off; return 0; } #define XFS_ALLOC_GAP_UNITS 4 void xfs_bmap_adjacent( struct xfs_bmalloca *ap) /* bmap alloc argument struct */ { xfs_fsblock_t adjust; /* adjustment to block numbers */ xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ xfs_mount_t *mp; /* mount point structure */ int nullfb; /* true if ap->firstblock isn't set */ int rt; /* true if inode is realtime */ #define ISVALID(x,y) \ (rt ? \ (x) < mp->m_sb.sb_rblocks : \ XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \ XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) mp = ap->ip->i_mount; nullfb = ap->tp->t_firstblock == NULLFSBLOCK; rt = XFS_IS_REALTIME_INODE(ap->ip) && xfs_alloc_is_userdata(ap->datatype); fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->tp->t_firstblock); /* * If allocating at eof, and there's a previous real block, * try to use its last block as our starting point. */ if (ap->eof && ap->prev.br_startoff != NULLFILEOFF && !isnullstartblock(ap->prev.br_startblock) && ISVALID(ap->prev.br_startblock + ap->prev.br_blockcount, ap->prev.br_startblock)) { ap->blkno = ap->prev.br_startblock + ap->prev.br_blockcount; /* * Adjust for the gap between prevp and us. */ adjust = ap->offset - (ap->prev.br_startoff + ap->prev.br_blockcount); if (adjust && ISVALID(ap->blkno + adjust, ap->prev.br_startblock)) ap->blkno += adjust; } /* * If not at eof, then compare the two neighbor blocks. * Figure out whether either one gives us a good starting point, * and pick the better one. */ else if (!ap->eof) { xfs_fsblock_t gotbno; /* right side block number */ xfs_fsblock_t gotdiff=0; /* right side difference */ xfs_fsblock_t prevbno; /* left side block number */ xfs_fsblock_t prevdiff=0; /* left side difference */ /* * If there's a previous (left) block, select a requested * start block based on it. */ if (ap->prev.br_startoff != NULLFILEOFF && !isnullstartblock(ap->prev.br_startblock) && (prevbno = ap->prev.br_startblock + ap->prev.br_blockcount) && ISVALID(prevbno, ap->prev.br_startblock)) { /* * Calculate gap to end of previous block. */ adjust = prevdiff = ap->offset - (ap->prev.br_startoff + ap->prev.br_blockcount); /* * Figure the startblock based on the previous block's * end and the gap size. * Heuristic! * If the gap is large relative to the piece we're * allocating, or using it gives us an invalid block * number, then just use the end of the previous block. */ if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->length && ISVALID(prevbno + prevdiff, ap->prev.br_startblock)) prevbno += adjust; else prevdiff += adjust; /* * If the firstblock forbids it, can't use it, * must use default. */ if (!rt && !nullfb && XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno) prevbno = NULLFSBLOCK; } /* * No previous block or can't follow it, just default. */ else prevbno = NULLFSBLOCK; /* * If there's a following (right) block, select a requested * start block based on it. */ if (!isnullstartblock(ap->got.br_startblock)) { /* * Calculate gap to start of next block. */ adjust = gotdiff = ap->got.br_startoff - ap->offset; /* * Figure the startblock based on the next block's * start and the gap size. */ gotbno = ap->got.br_startblock; /* * Heuristic! * If the gap is large relative to the piece we're * allocating, or using it gives us an invalid block * number, then just use the start of the next block * offset by our length. */ if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->length && ISVALID(gotbno - gotdiff, gotbno)) gotbno -= adjust; else if (ISVALID(gotbno - ap->length, gotbno)) { gotbno -= ap->length; gotdiff += adjust - ap->length; } else gotdiff += adjust; /* * If the firstblock forbids it, can't use it, * must use default. */ if (!rt && !nullfb && XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno) gotbno = NULLFSBLOCK; } /* * No next block, just default. */ else gotbno = NULLFSBLOCK; /* * If both valid, pick the better one, else the only good * one, else ap->blkno is already set (to 0 or the inode block). */ if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK) ap->blkno = prevdiff <= gotdiff ? prevbno : gotbno; else if (prevbno != NULLFSBLOCK) ap->blkno = prevbno; else if (gotbno != NULLFSBLOCK) ap->blkno = gotbno; } #undef ISVALID } static int xfs_bmap_longest_free_extent( struct xfs_trans *tp, xfs_agnumber_t ag, xfs_extlen_t *blen, int *notinit) { struct xfs_mount *mp = tp->t_mountp; struct xfs_perag *pag; xfs_extlen_t longest; int error = 0; pag = xfs_perag_get(mp, ag); if (!pag->pagf_init) { error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK); if (error) goto out; if (!pag->pagf_init) { *notinit = 1; goto out; } } longest = xfs_alloc_longest_free_extent(pag, xfs_alloc_min_freelist(mp, pag), xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE)); if (*blen < longest) *blen = longest; out: xfs_perag_put(pag); return error; } static void xfs_bmap_select_minlen( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args, xfs_extlen_t *blen, int notinit) { if (notinit || *blen < ap->minlen) { /* * Since we did a BUF_TRYLOCK above, it is possible that * there is space for this request. */ args->minlen = ap->minlen; } else if (*blen < args->maxlen) { /* * If the best seen length is less than the request length, * use the best as the minimum. */ args->minlen = *blen; } else { /* * Otherwise we've seen an extent as big as maxlen, use that * as the minimum. */ args->minlen = args->maxlen; } } STATIC int xfs_bmap_btalloc_nullfb( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args, xfs_extlen_t *blen) { struct xfs_mount *mp = ap->ip->i_mount; xfs_agnumber_t ag, startag; int notinit = 0; int error; args->type = XFS_ALLOCTYPE_START_BNO; args->total = ap->total; startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); if (startag == NULLAGNUMBER) startag = ag = 0; while (*blen < args->maxlen) { error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); if (error) return error; if (++ag == mp->m_sb.sb_agcount) ag = 0; if (ag == startag) break; } xfs_bmap_select_minlen(ap, args, blen, notinit); return 0; } STATIC int xfs_bmap_btalloc_filestreams( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args, xfs_extlen_t *blen) { struct xfs_mount *mp = ap->ip->i_mount; xfs_agnumber_t ag; int notinit = 0; int error; args->type = XFS_ALLOCTYPE_NEAR_BNO; args->total = ap->total; ag = XFS_FSB_TO_AGNO(mp, args->fsbno); if (ag == NULLAGNUMBER) ag = 0; error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); if (error) return error; if (*blen < args->maxlen) { error = xfs_filestream_new_ag(ap, &ag); if (error) return error; error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); if (error) return error; } xfs_bmap_select_minlen(ap, args, blen, notinit); /* * Set the failure fallback case to look in the selected AG as stream * may have moved. */ ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); return 0; } /* Update all inode and quota accounting for the allocation we just did. */ static void xfs_bmap_btalloc_accounting( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args) { if (ap->flags & XFS_BMAPI_COWFORK) { /* * COW fork blocks are in-core only and thus are treated as * in-core quota reservation (like delalloc blocks) even when * converted to real blocks. The quota reservation is not * accounted to disk until blocks are remapped to the data * fork. So if these blocks were previously delalloc, we * already have quota reservation and there's nothing to do * yet. */ if (ap->wasdel) { xfs_mod_delalloc(ap->ip->i_mount, -(int64_t)args->len); return; } /* * Otherwise, we've allocated blocks in a hole. The transaction * has acquired in-core quota reservation for this extent. * Rather than account these as real blocks, however, we reduce * the transaction quota reservation based on the allocation. * This essentially transfers the transaction quota reservation * to that of a delalloc extent. */ ap->ip->i_delayed_blks += args->len; xfs_trans_mod_dquot_byino(ap->tp, ap->ip, XFS_TRANS_DQ_RES_BLKS, -(long)args->len); return; } /* data/attr fork only */ ap->ip->i_d.di_nblocks += args->len; xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); if (ap->wasdel) { ap->ip->i_delayed_blks -= args->len; xfs_mod_delalloc(ap->ip->i_mount, -(int64_t)args->len); } xfs_trans_mod_dquot_byino(ap->tp, ap->ip, ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT : XFS_TRANS_DQ_BCOUNT, args->len); } STATIC int xfs_bmap_btalloc( struct xfs_bmalloca *ap) /* bmap alloc argument struct */ { xfs_mount_t *mp; /* mount point structure */ xfs_alloctype_t atype = 0; /* type for allocation routines */ xfs_extlen_t align = 0; /* minimum allocation alignment */ xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ xfs_agnumber_t ag; xfs_alloc_arg_t args; xfs_fileoff_t orig_offset; xfs_extlen_t orig_length; xfs_extlen_t blen; xfs_extlen_t nextminlen = 0; int nullfb; /* true if ap->firstblock isn't set */ int isaligned; int tryagain; int error; int stripe_align; ASSERT(ap->length); orig_offset = ap->offset; orig_length = ap->length; mp = ap->ip->i_mount; /* stripe alignment for allocation is determined by mount parameters */ stripe_align = 0; if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) stripe_align = mp->m_swidth; else if (mp->m_dalign) stripe_align = mp->m_dalign; if (ap->flags & XFS_BMAPI_COWFORK) align = xfs_get_cowextsz_hint(ap->ip); else if (xfs_alloc_is_userdata(ap->datatype)) align = xfs_get_extsz_hint(ap->ip); if (align) { error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, align, 0, ap->eof, 0, ap->conv, &ap->offset, &ap->length); ASSERT(!error); ASSERT(ap->length); } nullfb = ap->tp->t_firstblock == NULLFSBLOCK; fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->tp->t_firstblock); if (nullfb) { if (xfs_alloc_is_userdata(ap->datatype) && xfs_inode_is_filestream(ap->ip)) { ag = xfs_filestream_lookup_ag(ap->ip); ag = (ag != NULLAGNUMBER) ? ag : 0; ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0); } else { ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino); } } else ap->blkno = ap->tp->t_firstblock; xfs_bmap_adjacent(ap); /* * If allowed, use ap->blkno; otherwise must use firstblock since * it's in the right allocation group. */ if (nullfb || XFS_FSB_TO_AGNO(mp, ap->blkno) == fb_agno) ; else ap->blkno = ap->tp->t_firstblock; /* * Normal allocation, done through xfs_alloc_vextent. */ tryagain = isaligned = 0; memset(&args, 0, sizeof(args)); args.tp = ap->tp; args.mp = mp; args.fsbno = ap->blkno; args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE; /* Trim the allocation back to the maximum an AG can fit. */ args.maxlen = min(ap->length, mp->m_ag_max_usable); blen = 0; if (nullfb) { /* * Search for an allocation group with a single extent large * enough for the request. If one isn't found, then adjust * the minimum allocation size to the largest space found. */ if (xfs_alloc_is_userdata(ap->datatype) && xfs_inode_is_filestream(ap->ip)) error = xfs_bmap_btalloc_filestreams(ap, &args, &blen); else error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); if (error) return error; } else if (ap->tp->t_flags & XFS_TRANS_LOWMODE) { if (xfs_inode_is_filestream(ap->ip)) args.type = XFS_ALLOCTYPE_FIRST_AG; else args.type = XFS_ALLOCTYPE_START_BNO; args.total = args.minlen = ap->minlen; } else { args.type = XFS_ALLOCTYPE_NEAR_BNO; args.total = ap->total; args.minlen = ap->minlen; } /* apply extent size hints if obtained earlier */ if (align) { args.prod = align; div_u64_rem(ap->offset, args.prod, &args.mod); if (args.mod) args.mod = args.prod - args.mod; } else if (mp->m_sb.sb_blocksize >= PAGE_SIZE) { args.prod = 1; args.mod = 0; } else { args.prod = PAGE_SIZE >> mp->m_sb.sb_blocklog; div_u64_rem(ap->offset, args.prod, &args.mod); if (args.mod) args.mod = args.prod - args.mod; } /* * If we are not low on available data blocks, and the * underlying logical volume manager is a stripe, and * the file offset is zero then try to allocate data * blocks on stripe unit boundary. * NOTE: ap->aeof is only set if the allocation length * is >= the stripe unit and the allocation offset is * at the end of file. */ if (!(ap->tp->t_flags & XFS_TRANS_LOWMODE) && ap->aeof) { if (!ap->offset) { args.alignment = stripe_align; atype = args.type; isaligned = 1; /* * Adjust for alignment */ if (blen > args.alignment && blen <= args.maxlen) args.minlen = blen - args.alignment; args.minalignslop = 0; } else { /* * First try an exact bno allocation. * If it fails then do a near or start bno * allocation with alignment turned on. */ atype = args.type; tryagain = 1; args.type = XFS_ALLOCTYPE_THIS_BNO; args.alignment = 1; /* * Compute the minlen+alignment for the * next case. Set slop so that the value * of minlen+alignment+slop doesn't go up * between the calls. */ if (blen > stripe_align && blen <= args.maxlen) nextminlen = blen - stripe_align; else nextminlen = args.minlen; if (nextminlen + stripe_align > args.minlen + 1) args.minalignslop = nextminlen + stripe_align - args.minlen - 1; else args.minalignslop = 0; } } else { args.alignment = 1; args.minalignslop = 0; } args.minleft = ap->minleft; args.wasdel = ap->wasdel; args.resv = XFS_AG_RESV_NONE; args.datatype = ap->datatype; if (ap->datatype & XFS_ALLOC_USERDATA_ZERO) args.ip = ap->ip; error = xfs_alloc_vextent(&args); if (error) return error; if (tryagain && args.fsbno == NULLFSBLOCK) { /* * Exact allocation failed. Now try with alignment * turned on. */ args.type = atype; args.fsbno = ap->blkno; args.alignment = stripe_align; args.minlen = nextminlen; args.minalignslop = 0; isaligned = 1; if ((error = xfs_alloc_vextent(&args))) return error; } if (isaligned && args.fsbno == NULLFSBLOCK) { /* * allocation failed, so turn off alignment and * try again. */ args.type = atype; args.fsbno = ap->blkno; args.alignment = 0; if ((error = xfs_alloc_vextent(&args))) return error; } if (args.fsbno == NULLFSBLOCK && nullfb && args.minlen > ap->minlen) { args.minlen = ap->minlen; args.type = XFS_ALLOCTYPE_START_BNO; args.fsbno = ap->blkno; if ((error = xfs_alloc_vextent(&args))) return error; } if (args.fsbno == NULLFSBLOCK && nullfb) { args.fsbno = 0; args.type = XFS_ALLOCTYPE_FIRST_AG; args.total = ap->minlen; if ((error = xfs_alloc_vextent(&args))) return error; ap->tp->t_flags |= XFS_TRANS_LOWMODE; } if (args.fsbno != NULLFSBLOCK) { /* * check the allocation happened at the same or higher AG than * the first block that was allocated. */ ASSERT(ap->tp->t_firstblock == NULLFSBLOCK || XFS_FSB_TO_AGNO(mp, ap->tp->t_firstblock) <= XFS_FSB_TO_AGNO(mp, args.fsbno)); ap->blkno = args.fsbno; if (ap->tp->t_firstblock == NULLFSBLOCK) ap->tp->t_firstblock = args.fsbno; ASSERT(nullfb || fb_agno <= args.agno); ap->length = args.len; /* * If the extent size hint is active, we tried to round the * caller's allocation request offset down to extsz and the * length up to another extsz boundary. If we found a free * extent we mapped it in starting at this new offset. If the * newly mapped space isn't long enough to cover any of the * range of offsets that was originally requested, move the * mapping up so that we can fill as much of the caller's * original request as possible. Free space is apparently * very fragmented so we're unlikely to be able to satisfy the * hints anyway. */ if (ap->length <= orig_length) ap->offset = orig_offset; else if (ap->offset + ap->length < orig_offset + orig_length) ap->offset = orig_offset + orig_length - ap->length; xfs_bmap_btalloc_accounting(ap, &args); } else { ap->blkno = NULLFSBLOCK; ap->length = 0; } return 0; } /* * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. * It figures out where to ask the underlying allocator to put the new extent. */ STATIC int xfs_bmap_alloc( struct xfs_bmalloca *ap) /* bmap alloc argument struct */ { if (XFS_IS_REALTIME_INODE(ap->ip) && xfs_alloc_is_userdata(ap->datatype)) return xfs_bmap_rtalloc(ap); return xfs_bmap_btalloc(ap); } /* Trim extent to fit a logical block range. */ void xfs_trim_extent( struct xfs_bmbt_irec *irec, xfs_fileoff_t bno, xfs_filblks_t len) { xfs_fileoff_t distance; xfs_fileoff_t end = bno + len; if (irec->br_startoff + irec->br_blockcount <= bno || irec->br_startoff >= end) { irec->br_blockcount = 0; return; } if (irec->br_startoff < bno) { distance = bno - irec->br_startoff; if (isnullstartblock(irec->br_startblock)) irec->br_startblock = DELAYSTARTBLOCK; if (irec->br_startblock != DELAYSTARTBLOCK && irec->br_startblock != HOLESTARTBLOCK) irec->br_startblock += distance; irec->br_startoff += distance; irec->br_blockcount -= distance; } if (end < irec->br_startoff + irec->br_blockcount) { distance = irec->br_startoff + irec->br_blockcount - end; irec->br_blockcount -= distance; } } /* * Trim the returned map to the required bounds */ STATIC void xfs_bmapi_trim_map( struct xfs_bmbt_irec *mval, struct xfs_bmbt_irec *got, xfs_fileoff_t *bno, xfs_filblks_t len, xfs_fileoff_t obno, xfs_fileoff_t end, int n, int flags) { if ((flags & XFS_BMAPI_ENTIRE) || got->br_startoff + got->br_blockcount <= obno) { *mval = *got; if (isnullstartblock(got->br_startblock)) mval->br_startblock = DELAYSTARTBLOCK; return; } if (obno > *bno) *bno = obno; ASSERT((*bno >= obno) || (n == 0)); ASSERT(*bno < end); mval->br_startoff = *bno; if (isnullstartblock(got->br_startblock)) mval->br_startblock = DELAYSTARTBLOCK; else mval->br_startblock = got->br_startblock + (*bno - got->br_startoff); /* * Return the minimum of what we got and what we asked for for * the length. We can use the len variable here because it is * modified below and we could have been there before coming * here if the first part of the allocation didn't overlap what * was asked for. */ mval->br_blockcount = XFS_FILBLKS_MIN(end - *bno, got->br_blockcount - (*bno - got->br_startoff)); mval->br_state = got->br_state; ASSERT(mval->br_blockcount <= len); return; } /* * Update and validate the extent map to return */ STATIC void xfs_bmapi_update_map( struct xfs_bmbt_irec **map, xfs_fileoff_t *bno, xfs_filblks_t *len, xfs_fileoff_t obno, xfs_fileoff_t end, int *n, int flags) { xfs_bmbt_irec_t *mval = *map; ASSERT((flags & XFS_BMAPI_ENTIRE) || ((mval->br_startoff + mval->br_blockcount) <= end)); ASSERT((flags & XFS_BMAPI_ENTIRE) || (mval->br_blockcount <= *len) || (mval->br_startoff < obno)); *bno = mval->br_startoff + mval->br_blockcount; *len = end - *bno; if (*n > 0 && mval->br_startoff == mval[-1].br_startoff) { /* update previous map with new information */ ASSERT(mval->br_startblock == mval[-1].br_startblock); ASSERT(mval->br_blockcount > mval[-1].br_blockcount); ASSERT(mval->br_state == mval[-1].br_state); mval[-1].br_blockcount = mval->br_blockcount; mval[-1].br_state = mval->br_state; } else if (*n > 0 && mval->br_startblock != DELAYSTARTBLOCK && mval[-1].br_startblock != DELAYSTARTBLOCK && mval[-1].br_startblock != HOLESTARTBLOCK && mval->br_startblock == mval[-1].br_startblock + mval[-1].br_blockcount && mval[-1].br_state == mval->br_state) { ASSERT(mval->br_startoff == mval[-1].br_startoff + mval[-1].br_blockcount); mval[-1].br_blockcount += mval->br_blockcount; } else if (*n > 0 && mval->br_startblock == DELAYSTARTBLOCK && mval[-1].br_startblock == DELAYSTARTBLOCK && mval->br_startoff == mval[-1].br_startoff + mval[-1].br_blockcount) { mval[-1].br_blockcount += mval->br_blockcount; mval[-1].br_state = mval->br_state; } else if (!((*n == 0) && ((mval->br_startoff + mval->br_blockcount) <= obno))) { mval++; (*n)++; } *map = mval; } /* * Map file blocks to filesystem blocks without allocation. */ int xfs_bmapi_read( struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, struct xfs_bmbt_irec *mval, int *nmap, int flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; struct xfs_bmbt_irec got; xfs_fileoff_t obno; xfs_fileoff_t end; struct xfs_iext_cursor icur; int error; bool eof = false; int n = 0; int whichfork = xfs_bmapi_whichfork(flags); ASSERT(*nmap >= 1); ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE| XFS_BMAPI_COWFORK))); ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)); if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; XFS_STATS_INC(mp, xs_blk_mapr); ifp = XFS_IFORK_PTR(ip, whichfork); if (!ifp) { /* No CoW fork? Return a hole. */ if (whichfork == XFS_COW_FORK) { mval->br_startoff = bno; mval->br_startblock = HOLESTARTBLOCK; mval->br_blockcount = len; mval->br_state = XFS_EXT_NORM; *nmap = 1; return 0; } /* * A missing attr ifork implies that the inode says we're in * extents or btree format but failed to pass the inode fork * verifier while trying to load it. Treat that as a file * corruption too. */ #ifdef DEBUG xfs_alert(mp, "%s: inode %llu missing fork %d", __func__, ip->i_ino, whichfork); #endif /* DEBUG */ return -EFSCORRUPTED; } if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(NULL, ip, whichfork); if (error) return error; } if (!xfs_iext_lookup_extent(ip, ifp, bno, &icur, &got)) eof = true; end = bno + len; obno = bno; while (bno < end && n < *nmap) { /* Reading past eof, act as though there's a hole up to end. */ if (eof) got.br_startoff = end; if (got.br_startoff > bno) { /* Reading in a hole. */ mval->br_startoff = bno; mval->br_startblock = HOLESTARTBLOCK; mval->br_blockcount = XFS_FILBLKS_MIN(len, got.br_startoff - bno); mval->br_state = XFS_EXT_NORM; bno += mval->br_blockcount; len -= mval->br_blockcount; mval++; n++; continue; } /* set up the extent map to return. */ xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags); xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); /* If we're done, stop now. */ if (bno >= end || n >= *nmap) break; /* Else go on to the next record. */ if (!xfs_iext_next_extent(ifp, &icur, &got)) eof = true; } *nmap = n; return 0; } /* * Add a delayed allocation extent to an inode. Blocks are reserved from the * global pool and the extent inserted into the inode in-core extent tree. * * On entry, got refers to the first extent beyond the offset of the extent to * allocate or eof is specified if no such extent exists. On return, got refers * to the extent record that was inserted to the inode fork. * * Note that the allocated extent may have been merged with contiguous extents * during insertion into the inode fork. Thus, got does not reflect the current * state of the inode fork on return. If necessary, the caller can use lastx to * look up the updated record in the inode fork. */ int xfs_bmapi_reserve_delalloc( struct xfs_inode *ip, int whichfork, xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc, struct xfs_bmbt_irec *got, struct xfs_iext_cursor *icur, int eof) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); xfs_extlen_t alen; xfs_extlen_t indlen; int error; xfs_fileoff_t aoff = off; /* * Cap the alloc length. Keep track of prealloc so we know whether to * tag the inode before we return. */ alen = XFS_FILBLKS_MIN(len + prealloc, MAXEXTLEN); if (!eof) alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff); if (prealloc && alen >= len) prealloc = alen - len; /* Figure out the extent size, adjust alen */ if (whichfork == XFS_COW_FORK) { struct xfs_bmbt_irec prev; xfs_extlen_t extsz = xfs_get_cowextsz_hint(ip); if (!xfs_iext_peek_prev_extent(ifp, icur, &prev)) prev.br_startoff = NULLFILEOFF; error = xfs_bmap_extsize_align(mp, got, &prev, extsz, 0, eof, 1, 0, &aoff, &alen); ASSERT(!error); } /* * Make a transaction-less quota reservation for delayed allocation * blocks. This number gets adjusted later. We return if we haven't * allocated blocks already inside this loop. */ error = xfs_trans_reserve_quota_nblks(NULL, ip, (long)alen, 0, XFS_QMOPT_RES_REGBLKS); if (error) return error; /* * Split changing sb for alen and indlen since they could be coming * from different places. */ indlen = (xfs_extlen_t)xfs_bmap_worst_indlen(ip, alen); ASSERT(indlen > 0); error = xfs_mod_fdblocks(mp, -((int64_t)alen), false); if (error) goto out_unreserve_quota; error = xfs_mod_fdblocks(mp, -((int64_t)indlen), false); if (error) goto out_unreserve_blocks; ip->i_delayed_blks += alen; xfs_mod_delalloc(ip->i_mount, alen + indlen); got->br_startoff = aoff; got->br_startblock = nullstartblock(indlen); got->br_blockcount = alen; got->br_state = XFS_EXT_NORM; xfs_bmap_add_extent_hole_delay(ip, whichfork, icur, got); /* * Tag the inode if blocks were preallocated. Note that COW fork * preallocation can occur at the start or end of the extent, even when * prealloc == 0, so we must also check the aligned offset and length. */ if (whichfork == XFS_DATA_FORK && prealloc) xfs_inode_set_eofblocks_tag(ip); if (whichfork == XFS_COW_FORK && (prealloc || aoff < off || alen > len)) xfs_inode_set_cowblocks_tag(ip); return 0; out_unreserve_blocks: xfs_mod_fdblocks(mp, alen, false); out_unreserve_quota: if (XFS_IS_QUOTA_ON(mp)) xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0, XFS_QMOPT_RES_REGBLKS); return error; } static int xfs_bmapi_allocate( struct xfs_bmalloca *bma) { struct xfs_mount *mp = bma->ip->i_mount; int whichfork = xfs_bmapi_whichfork(bma->flags); struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); int tmp_logflags = 0; int error; ASSERT(bma->length > 0); /* * For the wasdelay case, we could also just allocate the stuff asked * for in this bmap call but that wouldn't be as good. */ if (bma->wasdel) { bma->length = (xfs_extlen_t)bma->got.br_blockcount; bma->offset = bma->got.br_startoff; xfs_iext_peek_prev_extent(ifp, &bma->icur, &bma->prev); } else { bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN); if (!bma->eof) bma->length = XFS_FILBLKS_MIN(bma->length, bma->got.br_startoff - bma->offset); } /* * Set the data type being allocated. For the data fork, the first data * in the file is treated differently to all other allocations. For the * attribute fork, we only need to ensure the allocated range is not on * the busy list. */ if (!(bma->flags & XFS_BMAPI_METADATA)) { bma->datatype = XFS_ALLOC_NOBUSY; if (whichfork == XFS_DATA_FORK) { if (bma->offset == 0) bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA; else bma->datatype |= XFS_ALLOC_USERDATA; } if (bma->flags & XFS_BMAPI_ZERO) bma->datatype |= XFS_ALLOC_USERDATA_ZERO; } bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1; /* * Only want to do the alignment at the eof if it is userdata and * allocation length is larger than a stripe unit. */ if (mp->m_dalign && bma->length >= mp->m_dalign && !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { error = xfs_bmap_isaeof(bma, whichfork); if (error) return error; } error = xfs_bmap_alloc(bma); if (error) return error; if (bma->blkno == NULLFSBLOCK) return 0; if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork); /* * Bump the number of extents we've allocated * in this call. */ bma->nallocs++; if (bma->cur) bma->cur->bc_private.b.flags = bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; bma->got.br_startoff = bma->offset; bma->got.br_startblock = bma->blkno; bma->got.br_blockcount = bma->length; bma->got.br_state = XFS_EXT_NORM; /* * In the data fork, a wasdelay extent has been initialized, so * shouldn't be flagged as unwritten. * * For the cow fork, however, we convert delalloc reservations * (extents allocated for speculative preallocation) to * allocated unwritten extents, and only convert the unwritten * extents to real extents when we're about to write the data. */ if ((!bma->wasdel || (bma->flags & XFS_BMAPI_COWFORK)) && (bma->flags & XFS_BMAPI_PREALLOC)) bma->got.br_state = XFS_EXT_UNWRITTEN; if (bma->wasdel) error = xfs_bmap_add_extent_delay_real(bma, whichfork); else error = xfs_bmap_add_extent_hole_real(bma->tp, bma->ip, whichfork, &bma->icur, &bma->cur, &bma->got, &bma->logflags, bma->flags); bma->logflags |= tmp_logflags; if (error) return error; /* * Update our extent pointer, given that xfs_bmap_add_extent_delay_real * or xfs_bmap_add_extent_hole_real might have merged it into one of * the neighbouring ones. */ xfs_iext_get_extent(ifp, &bma->icur, &bma->got); ASSERT(bma->got.br_startoff <= bma->offset); ASSERT(bma->got.br_startoff + bma->got.br_blockcount >= bma->offset + bma->length); ASSERT(bma->got.br_state == XFS_EXT_NORM || bma->got.br_state == XFS_EXT_UNWRITTEN); return 0; } STATIC int xfs_bmapi_convert_unwritten( struct xfs_bmalloca *bma, struct xfs_bmbt_irec *mval, xfs_filblks_t len, int flags) { int whichfork = xfs_bmapi_whichfork(flags); struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); int tmp_logflags = 0; int error; /* check if we need to do unwritten->real conversion */ if (mval->br_state == XFS_EXT_UNWRITTEN && (flags & XFS_BMAPI_PREALLOC)) return 0; /* check if we need to do real->unwritten conversion */ if (mval->br_state == XFS_EXT_NORM && (flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) != (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) return 0; /* * Modify (by adding) the state flag, if writing. */ ASSERT(mval->br_blockcount <= len); if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) { bma->cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp, bma->ip, whichfork); } mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; /* * Before insertion into the bmbt, zero the range being converted * if required. */ if (flags & XFS_BMAPI_ZERO) { error = xfs_zero_extent(bma->ip, mval->br_startblock, mval->br_blockcount); if (error) return error; } error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, whichfork, &bma->icur, &bma->cur, mval, &tmp_logflags); /* * Log the inode core unconditionally in the unwritten extent conversion * path because the conversion might not have done so (e.g., if the * extent count hasn't changed). We need to make sure the inode is dirty * in the transaction for the sake of fsync(), even if nothing has * changed, because fsync() will not force the log for this transaction * unless it sees the inode pinned. * * Note: If we're only converting cow fork extents, there aren't * any on-disk updates to make, so we don't need to log anything. */ if (whichfork != XFS_COW_FORK) bma->logflags |= tmp_logflags | XFS_ILOG_CORE; if (error) return error; /* * Update our extent pointer, given that * xfs_bmap_add_extent_unwritten_real might have merged it into one * of the neighbouring ones. */ xfs_iext_get_extent(ifp, &bma->icur, &bma->got); /* * We may have combined previously unwritten space with written space, * so generate another request. */ if (mval->br_blockcount < len) return -EAGAIN; return 0; } static inline xfs_extlen_t xfs_bmapi_minleft( struct xfs_trans *tp, struct xfs_inode *ip, int fork) { if (tp && tp->t_firstblock != NULLFSBLOCK) return 0; if (XFS_IFORK_FORMAT(ip, fork) != XFS_DINODE_FMT_BTREE) return 1; return be16_to_cpu(XFS_IFORK_PTR(ip, fork)->if_broot->bb_level) + 1; } /* * Log whatever the flags say, even if error. Otherwise we might miss detecting * a case where the data is changed, there's an error, and it's not logged so we * don't shutdown when we should. Don't bother logging extents/btree changes if * we converted to the other format. */ static void xfs_bmapi_finish( struct xfs_bmalloca *bma, int whichfork, int error) { if ((bma->logflags & xfs_ilog_fext(whichfork)) && XFS_IFORK_FORMAT(bma->ip, whichfork) != XFS_DINODE_FMT_EXTENTS) bma->logflags &= ~xfs_ilog_fext(whichfork); else if ((bma->logflags & xfs_ilog_fbroot(whichfork)) && XFS_IFORK_FORMAT(bma->ip, whichfork) != XFS_DINODE_FMT_BTREE) bma->logflags &= ~xfs_ilog_fbroot(whichfork); if (bma->logflags) xfs_trans_log_inode(bma->tp, bma->ip, bma->logflags); if (bma->cur) xfs_btree_del_cursor(bma->cur, error); } /* * Map file blocks to filesystem blocks, and allocate blocks or convert the * extent state if necessary. Details behaviour is controlled by the flags * parameter. Only allocates blocks from a single allocation group, to avoid * locking problems. */ int xfs_bmapi_write( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t bno, /* starting file offs. mapped */ xfs_filblks_t len, /* length to map in file */ int flags, /* XFS_BMAPI_... */ xfs_extlen_t total, /* total blocks needed */ struct xfs_bmbt_irec *mval, /* output: map values */ int *nmap) /* i/o: mval size/count */ { struct xfs_bmalloca bma = { .tp = tp, .ip = ip, .total = total, }; struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; xfs_fileoff_t end; /* end of mapped file region */ bool eof = false; /* after the end of extents */ int error; /* error return */ int n; /* current extent index */ xfs_fileoff_t obno; /* old block number (offset) */ int whichfork; /* data or attr fork */ #ifdef DEBUG xfs_fileoff_t orig_bno; /* original block number value */ int orig_flags; /* original flags arg value */ xfs_filblks_t orig_len; /* original value of len arg */ struct xfs_bmbt_irec *orig_mval; /* original value of mval */ int orig_nmap; /* original value of *nmap */ orig_bno = bno; orig_len = len; orig_flags = flags; orig_mval = mval; orig_nmap = *nmap; #endif whichfork = xfs_bmapi_whichfork(flags); ASSERT(*nmap >= 1); ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); ASSERT(tp != NULL); ASSERT(len > 0); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(!(flags & XFS_BMAPI_REMAP)); /* zeroing is for currently only for data extents, not metadata */ ASSERT((flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)) != (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)); /* * we can allocate unwritten extents or pre-zero allocated blocks, * but it makes no sense to do both at once. This would result in * zeroing the unwritten extent twice, but it still being an * unwritten extent.... */ ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) != (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)); if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ifp = XFS_IFORK_PTR(ip, whichfork); XFS_STATS_INC(mp, xs_blk_mapw); if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) goto error0; } if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.icur, &bma.got)) eof = true; if (!xfs_iext_peek_prev_extent(ifp, &bma.icur, &bma.prev)) bma.prev.br_startoff = NULLFILEOFF; bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork); n = 0; end = bno + len; obno = bno; while (bno < end && n < *nmap) { bool need_alloc = false, wasdelay = false; /* in hole or beyond EOF? */ if (eof || bma.got.br_startoff > bno) { /* * CoW fork conversions should /never/ hit EOF or * holes. There should always be something for us * to work on. */ ASSERT(!((flags & XFS_BMAPI_CONVERT) && (flags & XFS_BMAPI_COWFORK))); need_alloc = true; } else if (isnullstartblock(bma.got.br_startblock)) { wasdelay = true; } /* * First, deal with the hole before the allocated space * that we found, if any. */ if (need_alloc || wasdelay) { bma.eof = eof; bma.conv = !!(flags & XFS_BMAPI_CONVERT); bma.wasdel = wasdelay; bma.offset = bno; bma.flags = flags; /* * There's a 32/64 bit type mismatch between the * allocation length request (which can be 64 bits in * length) and the bma length request, which is * xfs_extlen_t and therefore 32 bits. Hence we have to * check for 32-bit overflows and handle them here. */ if (len > (xfs_filblks_t)MAXEXTLEN) bma.length = MAXEXTLEN; else bma.length = len; ASSERT(len > 0); ASSERT(bma.length > 0); error = xfs_bmapi_allocate(&bma); if (error) goto error0; if (bma.blkno == NULLFSBLOCK) break; /* * If this is a CoW allocation, record the data in * the refcount btree for orphan recovery. */ if (whichfork == XFS_COW_FORK) { error = xfs_refcount_alloc_cow_extent(tp, bma.blkno, bma.length); if (error) goto error0; } } /* Deal with the allocated space we found. */ xfs_bmapi_trim_map(mval, &bma.got, &bno, len, obno, end, n, flags); /* Execute unwritten extent conversion if necessary */ error = xfs_bmapi_convert_unwritten(&bma, mval, len, flags); if (error == -EAGAIN) continue; if (error) goto error0; /* update the extent map to return */ xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); /* * If we're done, stop now. Stop when we've allocated * XFS_BMAP_MAX_NMAP extents no matter what. Otherwise * the transaction may get too big. */ if (bno >= end || n >= *nmap || bma.nallocs >= *nmap) break; /* Else go on to the next record. */ bma.prev = bma.got; if (!xfs_iext_next_extent(ifp, &bma.icur, &bma.got)) eof = true; } *nmap = n; error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &bma.logflags, whichfork); if (error) goto error0; ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || XFS_IFORK_NEXTENTS(ip, whichfork) > XFS_IFORK_MAXEXT(ip, whichfork)); xfs_bmapi_finish(&bma, whichfork, 0); xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, orig_nmap, *nmap); return 0; error0: xfs_bmapi_finish(&bma, whichfork, error); return error; } /* * Convert an existing delalloc extent to real blocks based on file offset. This * attempts to allocate the entire delalloc extent and may require multiple * invocations to allocate the target offset if a large enough physical extent * is not available. */ int xfs_bmapi_convert_delalloc( struct xfs_inode *ip, int whichfork, xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap, unsigned int *seq) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_mount *mp = ip->i_mount; struct xfs_bmalloca bma = { NULL }; struct xfs_trans *tp; int error; /* * Space for the extent and indirect blocks was reserved when the * delalloc extent was created so there's no need to do so here. */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, XFS_TRANS_RESERVE, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &bma.icur, &bma.got) || bma.got.br_startoff > offset_fsb) { /* * No extent found in the range we are trying to convert. This * should only happen for the COW fork, where another thread * might have moved the extent to the data fork in the meantime. */ WARN_ON_ONCE(whichfork != XFS_COW_FORK); error = -EAGAIN; goto out_trans_cancel; } /* * If we find a real extent here we raced with another thread converting * the extent. Just return the real extent at this offset. */ if (!isnullstartblock(bma.got.br_startblock)) { *imap = bma.got; *seq = READ_ONCE(ifp->if_seq); goto out_trans_cancel; } bma.tp = tp; bma.ip = ip; bma.wasdel = true; bma.offset = bma.got.br_startoff; bma.length = max_t(xfs_filblks_t, bma.got.br_blockcount, MAXEXTLEN); bma.total = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK); bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork); if (whichfork == XFS_COW_FORK) bma.flags = XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC; if (!xfs_iext_peek_prev_extent(ifp, &bma.icur, &bma.prev)) bma.prev.br_startoff = NULLFILEOFF; error = xfs_bmapi_allocate(&bma); if (error) goto out_finish; error = -ENOSPC; if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) goto out_finish; error = -EFSCORRUPTED; if (WARN_ON_ONCE(!bma.got.br_startblock && !XFS_IS_REALTIME_INODE(ip))) goto out_finish; XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length)); XFS_STATS_INC(mp, xs_xstrat_quick); ASSERT(!isnullstartblock(bma.got.br_startblock)); *imap = bma.got; *seq = READ_ONCE(ifp->if_seq); if (whichfork == XFS_COW_FORK) { error = xfs_refcount_alloc_cow_extent(tp, bma.blkno, bma.length); if (error) goto out_finish; } error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &bma.logflags, whichfork); if (error) goto out_finish; xfs_bmapi_finish(&bma, whichfork, 0); error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; out_finish: xfs_bmapi_finish(&bma, whichfork, error); out_trans_cancel: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; } int xfs_bmapi_remap( struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, xfs_fsblock_t startblock, int flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; struct xfs_btree_cur *cur = NULL; struct xfs_bmbt_irec got; struct xfs_iext_cursor icur; int whichfork = xfs_bmapi_whichfork(flags); int logflags = 0, error; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(len > 0); ASSERT(len <= (xfs_filblks_t)MAXEXTLEN); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC | XFS_BMAPI_NORMAP))); ASSERT((flags & (XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC)) != (XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC)); if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmapi_remap", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } if (xfs_iext_lookup_extent(ip, ifp, bno, &icur, &got)) { /* make sure we only reflink into a hole. */ ASSERT(got.br_startoff > bno); ASSERT(got.br_startoff - bno >= len); } ip->i_d.di_nblocks += len; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (ifp->if_flags & XFS_IFBROOT) { cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.flags = 0; } got.br_startoff = bno; got.br_startblock = startblock; got.br_blockcount = len; if (flags & XFS_BMAPI_PREALLOC) got.br_state = XFS_EXT_UNWRITTEN; else got.br_state = XFS_EXT_NORM; error = xfs_bmap_add_extent_hole_real(tp, ip, whichfork, &icur, &cur, &got, &logflags, flags); if (error) goto error0; error = xfs_bmap_btree_to_extents(tp, ip, cur, &logflags, whichfork); error0: if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) logflags &= ~XFS_ILOG_DEXT; else if (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) logflags &= ~XFS_ILOG_DBROOT; if (logflags) xfs_trans_log_inode(tp, ip, logflags); if (cur) xfs_btree_del_cursor(cur, error); return error; } /* * When a delalloc extent is split (e.g., due to a hole punch), the original * indlen reservation must be shared across the two new extents that are left * behind. * * Given the original reservation and the worst case indlen for the two new * extents (as calculated by xfs_bmap_worst_indlen()), split the original * reservation fairly across the two new extents. If necessary, steal available * blocks from a deleted extent to make up a reservation deficiency (e.g., if * ores == 1). The number of stolen blocks is returned. The availability and * subsequent accounting of stolen blocks is the responsibility of the caller. */ static xfs_filblks_t xfs_bmap_split_indlen( xfs_filblks_t ores, /* original res. */ xfs_filblks_t *indlen1, /* ext1 worst indlen */ xfs_filblks_t *indlen2, /* ext2 worst indlen */ xfs_filblks_t avail) /* stealable blocks */ { xfs_filblks_t len1 = *indlen1; xfs_filblks_t len2 = *indlen2; xfs_filblks_t nres = len1 + len2; /* new total res. */ xfs_filblks_t stolen = 0; xfs_filblks_t resfactor; /* * Steal as many blocks as we can to try and satisfy the worst case * indlen for both new extents. */ if (ores < nres && avail) stolen = XFS_FILBLKS_MIN(nres - ores, avail); ores += stolen; /* nothing else to do if we've satisfied the new reservation */ if (ores >= nres) return stolen; /* * We can't meet the total required reservation for the two extents. * Calculate the percent of the overall shortage between both extents * and apply this percentage to each of the requested indlen values. * This distributes the shortage fairly and reduces the chances that one * of the two extents is left with nothing when extents are repeatedly * split. */ resfactor = (ores * 100); do_div(resfactor, nres); len1 *= resfactor; do_div(len1, 100); len2 *= resfactor; do_div(len2, 100); ASSERT(len1 + len2 <= ores); ASSERT(len1 < *indlen1 && len2 < *indlen2); /* * Hand out the remainder to each extent. If one of the two reservations * is zero, we want to make sure that one gets a block first. The loop * below starts with len1, so hand len2 a block right off the bat if it * is zero. */ ores -= (len1 + len2); ASSERT((*indlen1 - len1) + (*indlen2 - len2) >= ores); if (ores && !len2 && *indlen2) { len2++; ores--; } while (ores) { if (len1 < *indlen1) { len1++; ores--; } if (!ores) break; if (len2 < *indlen2) { len2++; ores--; } } *indlen1 = len1; *indlen2 = len2; return stolen; } int xfs_bmap_del_extent_delay( struct xfs_inode *ip, int whichfork, struct xfs_iext_cursor *icur, struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_bmbt_irec new; int64_t da_old, da_new, da_diff = 0; xfs_fileoff_t del_endoff, got_endoff; xfs_filblks_t got_indlen, new_indlen, stolen; int state = xfs_bmap_fork_to_state(whichfork); int error = 0; bool isrt; XFS_STATS_INC(mp, xs_del_exlist); isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); del_endoff = del->br_startoff + del->br_blockcount; got_endoff = got->br_startoff + got->br_blockcount; da_old = startblockval(got->br_startblock); da_new = 0; ASSERT(del->br_blockcount > 0); ASSERT(got->br_startoff <= del->br_startoff); ASSERT(got_endoff >= del_endoff); if (isrt) { uint64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount); do_div(rtexts, mp->m_sb.sb_rextsize); xfs_mod_frextents(mp, rtexts); } /* * Update the inode delalloc counter now and wait to update the * sb counters as we might have to borrow some blocks for the * indirect block accounting. */ error = xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del->br_blockcount), 0, isrt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); if (error) return error; ip->i_delayed_blks -= del->br_blockcount; if (got->br_startoff == del->br_startoff) state |= BMAP_LEFT_FILLING; if (got_endoff == del_endoff) state |= BMAP_RIGHT_FILLING; switch (state & (BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) { case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Matches the whole extent. Delete the entry. */ xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); break; case BMAP_LEFT_FILLING: /* * Deleting the first part of the extent. */ got->br_startoff = del_endoff; got->br_blockcount -= del->br_blockcount; da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, got->br_blockcount), da_old); got->br_startblock = nullstartblock((int)da_new); xfs_iext_update_extent(ip, state, icur, got); break; case BMAP_RIGHT_FILLING: /* * Deleting the last part of the extent. */ got->br_blockcount = got->br_blockcount - del->br_blockcount; da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, got->br_blockcount), da_old); got->br_startblock = nullstartblock((int)da_new); xfs_iext_update_extent(ip, state, icur, got); break; case 0: /* * Deleting the middle of the extent. * * Distribute the original indlen reservation across the two new * extents. Steal blocks from the deleted extent if necessary. * Stealing blocks simply fudges the fdblocks accounting below. * Warn if either of the new indlen reservations is zero as this * can lead to delalloc problems. */ got->br_blockcount = del->br_startoff - got->br_startoff; got_indlen = xfs_bmap_worst_indlen(ip, got->br_blockcount); new.br_blockcount = got_endoff - del_endoff; new_indlen = xfs_bmap_worst_indlen(ip, new.br_blockcount); WARN_ON_ONCE(!got_indlen || !new_indlen); stolen = xfs_bmap_split_indlen(da_old, &got_indlen, &new_indlen, del->br_blockcount); got->br_startblock = nullstartblock((int)got_indlen); new.br_startoff = del_endoff; new.br_state = got->br_state; new.br_startblock = nullstartblock((int)new_indlen); xfs_iext_update_extent(ip, state, icur, got); xfs_iext_next(ifp, icur); xfs_iext_insert(ip, icur, &new, state); da_new = got_indlen + new_indlen - stolen; del->br_blockcount -= stolen; break; } ASSERT(da_old >= da_new); da_diff = da_old - da_new; if (!isrt) da_diff += del->br_blockcount; if (da_diff) { xfs_mod_fdblocks(mp, da_diff, false); xfs_mod_delalloc(mp, -da_diff); } return error; } void xfs_bmap_del_extent_cow( struct xfs_inode *ip, struct xfs_iext_cursor *icur, struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); struct xfs_bmbt_irec new; xfs_fileoff_t del_endoff, got_endoff; int state = BMAP_COWFORK; XFS_STATS_INC(mp, xs_del_exlist); del_endoff = del->br_startoff + del->br_blockcount; got_endoff = got->br_startoff + got->br_blockcount; ASSERT(del->br_blockcount > 0); ASSERT(got->br_startoff <= del->br_startoff); ASSERT(got_endoff >= del_endoff); ASSERT(!isnullstartblock(got->br_startblock)); if (got->br_startoff == del->br_startoff) state |= BMAP_LEFT_FILLING; if (got_endoff == del_endoff) state |= BMAP_RIGHT_FILLING; switch (state & (BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) { case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Matches the whole extent. Delete the entry. */ xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); break; case BMAP_LEFT_FILLING: /* * Deleting the first part of the extent. */ got->br_startoff = del_endoff; got->br_blockcount -= del->br_blockcount; got->br_startblock = del->br_startblock + del->br_blockcount; xfs_iext_update_extent(ip, state, icur, got); break; case BMAP_RIGHT_FILLING: /* * Deleting the last part of the extent. */ got->br_blockcount -= del->br_blockcount; xfs_iext_update_extent(ip, state, icur, got); break; case 0: /* * Deleting the middle of the extent. */ got->br_blockcount = del->br_startoff - got->br_startoff; new.br_startoff = del_endoff; new.br_blockcount = got_endoff - del_endoff; new.br_state = got->br_state; new.br_startblock = del->br_startblock + del->br_blockcount; xfs_iext_update_extent(ip, state, icur, got); xfs_iext_next(ifp, icur); xfs_iext_insert(ip, icur, &new, state); break; } ip->i_delayed_blks -= del->br_blockcount; } /* * Called by xfs_bmapi to update file extent records and the btree * after removing space. */ STATIC int /* error */ xfs_bmap_del_extent_real( xfs_inode_t *ip, /* incore inode pointer */ xfs_trans_t *tp, /* current transaction pointer */ struct xfs_iext_cursor *icur, xfs_btree_cur_t *cur, /* if null, not a btree */ xfs_bmbt_irec_t *del, /* data to remove from extents */ int *logflagsp, /* inode logging flags */ int whichfork, /* data or attr fork */ int bflags) /* bmapi flags */ { xfs_fsblock_t del_endblock=0; /* first block past del */ xfs_fileoff_t del_endoff; /* first offset past del */ int do_fx; /* free extent at end of routine */ int error; /* error return value */ int flags = 0;/* inode logging flags */ struct xfs_bmbt_irec got; /* current extent entry */ xfs_fileoff_t got_endoff; /* first offset past got */ int i; /* temp state */ struct xfs_ifork *ifp; /* inode fork pointer */ xfs_mount_t *mp; /* mount structure */ xfs_filblks_t nblks; /* quota/sb block count */ xfs_bmbt_irec_t new; /* new record to be inserted */ /* REFERENCED */ uint qfield; /* quota field to update */ int state = xfs_bmap_fork_to_state(whichfork); struct xfs_bmbt_irec old; mp = ip->i_mount; XFS_STATS_INC(mp, xs_del_exlist); ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(del->br_blockcount > 0); xfs_iext_get_extent(ifp, icur, &got); ASSERT(got.br_startoff <= del->br_startoff); del_endoff = del->br_startoff + del->br_blockcount; got_endoff = got.br_startoff + got.br_blockcount; ASSERT(got_endoff >= del_endoff); ASSERT(!isnullstartblock(got.br_startblock)); qfield = 0; error = 0; /* * If it's the case where the directory code is running with no block * reservation, and the deleted block is in the middle of its extent, * and the resulting insert of an extent would cause transformation to * btree format, then reject it. The calling code will then swap blocks * around instead. We have to do this now, rather than waiting for the * conversion to btree format, since the transaction will be dirty then. */ if (tp->t_blk_res == 0 && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && XFS_IFORK_NEXTENTS(ip, whichfork) >= XFS_IFORK_MAXEXT(ip, whichfork) && del->br_startoff > got.br_startoff && del_endoff < got_endoff) return -ENOSPC; flags = XFS_ILOG_CORE; if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) { xfs_fsblock_t bno; xfs_filblks_t len; xfs_extlen_t mod; bno = div_u64_rem(del->br_startblock, mp->m_sb.sb_rextsize, &mod); ASSERT(mod == 0); len = div_u64_rem(del->br_blockcount, mp->m_sb.sb_rextsize, &mod); ASSERT(mod == 0); error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len); if (error) goto done; do_fx = 0; nblks = len * mp->m_sb.sb_rextsize; qfield = XFS_TRANS_DQ_RTBCOUNT; } else { do_fx = 1; nblks = del->br_blockcount; qfield = XFS_TRANS_DQ_BCOUNT; } del_endblock = del->br_startblock + del->br_blockcount; if (cur) { error = xfs_bmbt_lookup_eq(cur, &got, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (got.br_startoff == del->br_startoff) state |= BMAP_LEFT_FILLING; if (got_endoff == del_endoff) state |= BMAP_RIGHT_FILLING; switch (state & (BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) { case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Matches the whole extent. Delete the entry. */ xfs_iext_remove(ip, icur, state); xfs_iext_prev(ifp, icur); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); flags |= XFS_ILOG_CORE; if (!cur) { flags |= xfs_ilog_fext(whichfork); break; } if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); break; case BMAP_LEFT_FILLING: /* * Deleting the first part of the extent. */ got.br_startoff = del_endoff; got.br_startblock = del_endblock; got.br_blockcount -= del->br_blockcount; xfs_iext_update_extent(ip, state, icur, &got); if (!cur) { flags |= xfs_ilog_fext(whichfork); break; } error = xfs_bmbt_update(cur, &got); if (error) goto done; break; case BMAP_RIGHT_FILLING: /* * Deleting the last part of the extent. */ got.br_blockcount -= del->br_blockcount; xfs_iext_update_extent(ip, state, icur, &got); if (!cur) { flags |= xfs_ilog_fext(whichfork); break; } error = xfs_bmbt_update(cur, &got); if (error) goto done; break; case 0: /* * Deleting the middle of the extent. */ old = got; got.br_blockcount = del->br_startoff - got.br_startoff; xfs_iext_update_extent(ip, state, icur, &got); new.br_startoff = del_endoff; new.br_blockcount = got_endoff - del_endoff; new.br_state = got.br_state; new.br_startblock = del_endblock; flags |= XFS_ILOG_CORE; if (cur) { error = xfs_bmbt_update(cur, &got); if (error) goto done; error = xfs_btree_increment(cur, 0, &i); if (error) goto done; cur->bc_rec.b = new; error = xfs_btree_insert(cur, &i); if (error && error != -ENOSPC) goto done; /* * If get no-space back from btree insert, it tried a * split, and we have a zero block reservation. Fix up * our state and return the error. */ if (error == -ENOSPC) { /* * Reset the cursor, don't trust it after any * insert operation. */ error = xfs_bmbt_lookup_eq(cur, &got, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* * Update the btree record back * to the original value. */ error = xfs_bmbt_update(cur, &old); if (error) goto done; /* * Reset the extent record back * to the original value. */ xfs_iext_update_extent(ip, state, icur, &old); flags = 0; error = -ENOSPC; goto done; } XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } else flags |= xfs_ilog_fext(whichfork); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); xfs_iext_next(ifp, icur); xfs_iext_insert(ip, icur, &new, state); break; } /* remove reverse mapping */ error = xfs_rmap_unmap_extent(tp, ip, whichfork, del); if (error) goto done; /* * If we need to, add to list of extents to delete. */ if (do_fx && !(bflags & XFS_BMAPI_REMAP)) { if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) { error = xfs_refcount_decrease_extent(tp, del); if (error) goto done; } else { __xfs_bmap_add_free(tp, del->br_startblock, del->br_blockcount, NULL, (bflags & XFS_BMAPI_NODISCARD) || del->br_state == XFS_EXT_UNWRITTEN); } } /* * Adjust inode # blocks in the file. */ if (nblks) ip->i_d.di_nblocks -= nblks; /* * Adjust quota data. */ if (qfield && !(bflags & XFS_BMAPI_REMAP)) xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); done: *logflagsp = flags; return error; } /* * Unmap (remove) blocks from a file. * If nexts is nonzero then the number of extents to remove is limited to * that value. If not all extents in the block range can be removed then * *done is set. */ int /* error */ __xfs_bunmapi( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t start, /* first file offset deleted */ xfs_filblks_t *rlen, /* i/o: amount remaining */ int flags, /* misc flags */ xfs_extnum_t nexts) /* number of extents max */ { struct xfs_btree_cur *cur; /* bmap btree cursor */ struct xfs_bmbt_irec del; /* extent being deleted */ int error; /* error return value */ xfs_extnum_t extno; /* extent number in list */ struct xfs_bmbt_irec got; /* current extent record */ struct xfs_ifork *ifp; /* inode fork pointer */ int isrt; /* freeing in rt area */ int logflags; /* transaction logging flags */ xfs_extlen_t mod; /* rt extent offset */ struct xfs_mount *mp; /* mount structure */ int tmp_logflags; /* partial logging flags */ int wasdel; /* was a delayed alloc extent */ int whichfork; /* data or attribute fork */ xfs_fsblock_t sum; xfs_filblks_t len = *rlen; /* length to unmap in file */ xfs_fileoff_t max_len; xfs_agnumber_t prev_agno = NULLAGNUMBER, agno; xfs_fileoff_t end; struct xfs_iext_cursor icur; bool done = false; trace_xfs_bunmap(ip, start, len, flags, _RET_IP_); whichfork = xfs_bmapi_whichfork(flags); ASSERT(whichfork != XFS_COW_FORK); ifp = XFS_IFORK_PTR(ip, whichfork); if (unlikely( XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW, ip->i_mount); return -EFSCORRUPTED; } mp = ip->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(len > 0); ASSERT(nexts >= 0); /* * Guesstimate how many blocks we can unmap without running the risk of * blowing out the transaction with a mix of EFIs and reflink * adjustments. */ if (tp && xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res)); else max_len = len; if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = xfs_iread_extents(tp, ip, whichfork))) return error; if (xfs_iext_count(ifp) == 0) { *rlen = 0; return 0; } XFS_STATS_INC(mp, xs_blk_unmap); isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); end = start + len; if (!xfs_iext_lookup_extent_before(ip, ifp, &end, &icur, &got)) { *rlen = 0; return 0; } end--; logflags = 0; if (ifp->if_flags & XFS_IFBROOT) { ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.flags = 0; } else cur = NULL; if (isrt) { /* * Synchronize by locking the bitmap inode. */ xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP); xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL); xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM); xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL); } extno = 0; while (end != (xfs_fileoff_t)-1 && end >= start && (nexts == 0 || extno < nexts) && max_len > 0) { /* * Is the found extent after a hole in which end lives? * Just back up to the previous extent, if so. */ if (got.br_startoff > end && !xfs_iext_prev_extent(ifp, &icur, &got)) { done = true; break; } /* * Is the last block of this extent before the range * we're supposed to delete? If so, we're done. */ end = XFS_FILEOFF_MIN(end, got.br_startoff + got.br_blockcount - 1); if (end < start) break; /* * Then deal with the (possibly delayed) allocated space * we found. */ del = got; wasdel = isnullstartblock(del.br_startblock); /* * Make sure we don't touch multiple AGF headers out of order * in a single transaction, as that could cause AB-BA deadlocks. */ if (!wasdel) { agno = XFS_FSB_TO_AGNO(mp, del.br_startblock); if (prev_agno != NULLAGNUMBER && prev_agno > agno) break; prev_agno = agno; } if (got.br_startoff < start) { del.br_startoff = start; del.br_blockcount -= start - got.br_startoff; if (!wasdel) del.br_startblock += start - got.br_startoff; } if (del.br_startoff + del.br_blockcount > end + 1) del.br_blockcount = end + 1 - del.br_startoff; /* How much can we safely unmap? */ if (max_len < del.br_blockcount) { del.br_startoff += del.br_blockcount - max_len; if (!wasdel) del.br_startblock += del.br_blockcount - max_len; del.br_blockcount = max_len; } if (!isrt) goto delete; sum = del.br_startblock + del.br_blockcount; div_u64_rem(sum, mp->m_sb.sb_rextsize, &mod); if (mod) { /* * Realtime extent not lined up at the end. * The extent could have been split into written * and unwritten pieces, or we could just be * unmapping part of it. But we can't really * get rid of part of a realtime extent. */ if (del.br_state == XFS_EXT_UNWRITTEN) { /* * This piece is unwritten, or we're not * using unwritten extents. Skip over it. */ ASSERT(end >= mod); end -= mod > del.br_blockcount ? del.br_blockcount : mod; if (end < got.br_startoff && !xfs_iext_prev_extent(ifp, &icur, &got)) { done = true; break; } continue; } /* * It's written, turn it unwritten. * This is better than zeroing it. */ ASSERT(del.br_state == XFS_EXT_NORM); ASSERT(tp->t_blk_res > 0); /* * If this spans a realtime extent boundary, * chop it back to the start of the one we end at. */ if (del.br_blockcount > mod) { del.br_startoff += del.br_blockcount - mod; del.br_startblock += del.br_blockcount - mod; del.br_blockcount = mod; } del.br_state = XFS_EXT_UNWRITTEN; error = xfs_bmap_add_extent_unwritten_real(tp, ip, whichfork, &icur, &cur, &del, &logflags); if (error) goto error0; goto nodelete; } div_u64_rem(del.br_startblock, mp->m_sb.sb_rextsize, &mod); if (mod) { /* * Realtime extent is lined up at the end but not * at the front. We'll get rid of full extents if * we can. */ mod = mp->m_sb.sb_rextsize - mod; if (del.br_blockcount > mod) { del.br_blockcount -= mod; del.br_startoff += mod; del.br_startblock += mod; } else if (del.br_startoff == start && (del.br_state == XFS_EXT_UNWRITTEN || tp->t_blk_res == 0)) { /* * Can't make it unwritten. There isn't * a full extent here so just skip it. */ ASSERT(end >= del.br_blockcount); end -= del.br_blockcount; if (got.br_startoff > end && !xfs_iext_prev_extent(ifp, &icur, &got)) { done = true; break; } continue; } else if (del.br_state == XFS_EXT_UNWRITTEN) { struct xfs_bmbt_irec prev; /* * This one is already unwritten. * It must have a written left neighbor. * Unwrite the killed part of that one and * try again. */ if (!xfs_iext_prev_extent(ifp, &icur, &prev)) ASSERT(0); ASSERT(prev.br_state == XFS_EXT_NORM); ASSERT(!isnullstartblock(prev.br_startblock)); ASSERT(del.br_startblock == prev.br_startblock + prev.br_blockcount); if (prev.br_startoff < start) { mod = start - prev.br_startoff; prev.br_blockcount -= mod; prev.br_startblock += mod; prev.br_startoff = start; } prev.br_state = XFS_EXT_UNWRITTEN; error = xfs_bmap_add_extent_unwritten_real(tp, ip, whichfork, &icur, &cur, &prev, &logflags); if (error) goto error0; goto nodelete; } else { ASSERT(del.br_state == XFS_EXT_NORM); del.br_state = XFS_EXT_UNWRITTEN; error = xfs_bmap_add_extent_unwritten_real(tp, ip, whichfork, &icur, &cur, &del, &logflags); if (error) goto error0; goto nodelete; } } delete: if (wasdel) { error = xfs_bmap_del_extent_delay(ip, whichfork, &icur, &got, &del); } else { error = xfs_bmap_del_extent_real(ip, tp, &icur, cur, &del, &tmp_logflags, whichfork, flags); logflags |= tmp_logflags; } if (error) goto error0; max_len -= del.br_blockcount; end = del.br_startoff - 1; nodelete: /* * If not done go on to the next (previous) record. */ if (end != (xfs_fileoff_t)-1 && end >= start) { if (!xfs_iext_get_extent(ifp, &icur, &got) || (got.br_startoff > end && !xfs_iext_prev_extent(ifp, &icur, &got))) { done = true; break; } extno++; } } if (done || end == (xfs_fileoff_t)-1 || end < start) *rlen = 0; else *rlen = end - start + 1; /* * Convert to a btree if necessary. */ if (xfs_bmap_needs_btree(ip, whichfork)) { ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, &cur, 0, &tmp_logflags, whichfork); logflags |= tmp_logflags; } else { error = xfs_bmap_btree_to_extents(tp, ip, cur, &logflags, whichfork); } error0: /* * Log everything. Do this after conversion, there's no point in * logging the extent records if we've converted to btree format. */ if ((logflags & xfs_ilog_fext(whichfork)) && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) logflags &= ~xfs_ilog_fext(whichfork); else if ((logflags & xfs_ilog_fbroot(whichfork)) && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) logflags &= ~xfs_ilog_fbroot(whichfork); /* * Log inode even in the error case, if the transaction * is dirty we'll need to shut down the filesystem. */ if (logflags) xfs_trans_log_inode(tp, ip, logflags); if (cur) { if (!error) cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, error); } return error; } /* Unmap a range of a file. */ int xfs_bunmapi( xfs_trans_t *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_extnum_t nexts, int *done) { int error; error = __xfs_bunmapi(tp, ip, bno, &len, flags, nexts); *done = (len == 0); return error; } /* * Determine whether an extent shift can be accomplished by a merge with the * extent that precedes the target hole of the shift. */ STATIC bool xfs_bmse_can_merge( struct xfs_bmbt_irec *left, /* preceding extent */ struct xfs_bmbt_irec *got, /* current extent to shift */ xfs_fileoff_t shift) /* shift fsb */ { xfs_fileoff_t startoff; startoff = got->br_startoff - shift; /* * The extent, once shifted, must be adjacent in-file and on-disk with * the preceding extent. */ if ((left->br_startoff + left->br_blockcount != startoff) || (left->br_startblock + left->br_blockcount != got->br_startblock) || (left->br_state != got->br_state) || (left->br_blockcount + got->br_blockcount > MAXEXTLEN)) return false; return true; } /* * A bmap extent shift adjusts the file offset of an extent to fill a preceding * hole in the file. If an extent shift would result in the extent being fully * adjacent to the extent that currently precedes the hole, we can merge with * the preceding extent rather than do the shift. * * This function assumes the caller has verified a shift-by-merge is possible * with the provided extents via xfs_bmse_can_merge(). */ STATIC int xfs_bmse_merge( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, xfs_fileoff_t shift, /* shift fsb */ struct xfs_iext_cursor *icur, struct xfs_bmbt_irec *got, /* extent to shift */ struct xfs_bmbt_irec *left, /* preceding extent */ struct xfs_btree_cur *cur, int *logflags) /* output */ { struct xfs_bmbt_irec new; xfs_filblks_t blockcount; int error, i; struct xfs_mount *mp = ip->i_mount; blockcount = left->br_blockcount + got->br_blockcount; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(xfs_bmse_can_merge(left, got, shift)); new = *left; new.br_blockcount = blockcount; /* * Update the on-disk extent count, the btree if necessary and log the * inode. */ XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); *logflags |= XFS_ILOG_CORE; if (!cur) { *logflags |= XFS_ILOG_DEXT; goto done; } /* lookup and remove the extent to merge */ error = xfs_bmbt_lookup_eq(cur, got, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); error = xfs_btree_delete(cur, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); /* lookup and update size of the previous extent */ error = xfs_bmbt_lookup_eq(cur, left, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); error = xfs_bmbt_update(cur, &new); if (error) return error; done: xfs_iext_remove(ip, icur, 0); xfs_iext_prev(XFS_IFORK_PTR(ip, whichfork), icur); xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), icur, &new); /* update reverse mapping. rmap functions merge the rmaps for us */ error = xfs_rmap_unmap_extent(tp, ip, whichfork, got); if (error) return error; memcpy(&new, got, sizeof(new)); new.br_startoff = left->br_startoff + left->br_blockcount; return xfs_rmap_map_extent(tp, ip, whichfork, &new); } static int xfs_bmap_shift_update_extent( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_iext_cursor *icur, struct xfs_bmbt_irec *got, struct xfs_btree_cur *cur, int *logflags, xfs_fileoff_t startoff) { struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec prev = *got; int error, i; *logflags |= XFS_ILOG_CORE; got->br_startoff = startoff; if (cur) { error = xfs_bmbt_lookup_eq(cur, &prev, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); error = xfs_bmbt_update(cur, got); if (error) return error; } else { *logflags |= XFS_ILOG_DEXT; } xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), icur, got); /* update reverse mapping */ error = xfs_rmap_unmap_extent(tp, ip, whichfork, &prev); if (error) return error; return xfs_rmap_map_extent(tp, ip, whichfork, got); } int xfs_bmap_collapse_extents( struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, bool *done) { int whichfork = XFS_DATA_FORK; struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_cur *cur = NULL; struct xfs_bmbt_irec got, prev; struct xfs_iext_cursor icur; xfs_fileoff_t new_startoff; int error = 0; int logflags = 0; if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT))) { XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL)); if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } if (ifp->if_flags & XFS_IFBROOT) { cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.flags = 0; } if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &icur, &got)) { *done = true; goto del_cursor; } XFS_WANT_CORRUPTED_GOTO(mp, !isnullstartblock(got.br_startblock), del_cursor); new_startoff = got.br_startoff - offset_shift_fsb; if (xfs_iext_peek_prev_extent(ifp, &icur, &prev)) { if (new_startoff < prev.br_startoff + prev.br_blockcount) { error = -EINVAL; goto del_cursor; } if (xfs_bmse_can_merge(&prev, &got, offset_shift_fsb)) { error = xfs_bmse_merge(tp, ip, whichfork, offset_shift_fsb, &icur, &got, &prev, cur, &logflags); if (error) goto del_cursor; goto done; } } else { if (got.br_startoff < offset_shift_fsb) { error = -EINVAL; goto del_cursor; } } error = xfs_bmap_shift_update_extent(tp, ip, whichfork, &icur, &got, cur, &logflags, new_startoff); if (error) goto del_cursor; done: if (!xfs_iext_next_extent(ifp, &icur, &got)) { *done = true; goto del_cursor; } *next_fsb = got.br_startoff; del_cursor: if (cur) xfs_btree_del_cursor(cur, error); if (logflags) xfs_trans_log_inode(tp, ip, logflags); return error; } /* Make sure we won't be right-shifting an extent past the maximum bound. */ int xfs_bmap_can_insert_extents( struct xfs_inode *ip, xfs_fileoff_t off, xfs_fileoff_t shift) { struct xfs_bmbt_irec got; int is_empty; int error = 0; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_bmap_last_extent(NULL, ip, XFS_DATA_FORK, &got, &is_empty); if (!error && !is_empty && got.br_startoff >= off && ((got.br_startoff + shift) & BMBT_STARTOFF_MASK) < got.br_startoff) error = -EINVAL; xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; } int xfs_bmap_insert_extents( struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, bool *done, xfs_fileoff_t stop_fsb) { int whichfork = XFS_DATA_FORK; struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_cur *cur = NULL; struct xfs_bmbt_irec got, next; struct xfs_iext_cursor icur; xfs_fileoff_t new_startoff; int error = 0; int logflags = 0; if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT))) { XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL)); if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } if (ifp->if_flags & XFS_IFBROOT) { cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.flags = 0; } if (*next_fsb == NULLFSBLOCK) { xfs_iext_last(ifp, &icur); if (!xfs_iext_get_extent(ifp, &icur, &got) || stop_fsb > got.br_startoff) { *done = true; goto del_cursor; } } else { if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &icur, &got)) { *done = true; goto del_cursor; } } XFS_WANT_CORRUPTED_GOTO(mp, !isnullstartblock(got.br_startblock), del_cursor); if (stop_fsb >= got.br_startoff + got.br_blockcount) { error = -EIO; goto del_cursor; } new_startoff = got.br_startoff + offset_shift_fsb; if (xfs_iext_peek_next_extent(ifp, &icur, &next)) { if (new_startoff + got.br_blockcount > next.br_startoff) { error = -EINVAL; goto del_cursor; } /* * Unlike a left shift (which involves a hole punch), a right * shift does not modify extent neighbors in any way. We should * never find mergeable extents in this scenario. Check anyways * and warn if we encounter two extents that could be one. */ if (xfs_bmse_can_merge(&got, &next, offset_shift_fsb)) WARN_ON_ONCE(1); } error = xfs_bmap_shift_update_extent(tp, ip, whichfork, &icur, &got, cur, &logflags, new_startoff); if (error) goto del_cursor; if (!xfs_iext_prev_extent(ifp, &icur, &got) || stop_fsb >= got.br_startoff + got.br_blockcount) { *done = true; goto del_cursor; } *next_fsb = got.br_startoff; del_cursor: if (cur) xfs_btree_del_cursor(cur, error); if (logflags) xfs_trans_log_inode(tp, ip, logflags); return error; } /* * Splits an extent into two extents at split_fsb block such that it is the * first block of the current_ext. @ext is a target extent to be split. * @split_fsb is a block where the extents is split. If split_fsb lies in a * hole or the first block of extents, just return 0. */ STATIC int xfs_bmap_split_extent_at( struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t split_fsb) { int whichfork = XFS_DATA_FORK; struct xfs_btree_cur *cur = NULL; struct xfs_bmbt_irec got; struct xfs_bmbt_irec new; /* split extent */ struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; xfs_fsblock_t gotblkcnt; /* new block count for got */ struct xfs_iext_cursor icur; int error = 0; int logflags = 0; int i = 0; if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmap_split_extent_at", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS)) { /* Read in all the extents */ error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } /* * If there are not extents, or split_fsb lies in a hole we are done. */ if (!xfs_iext_lookup_extent(ip, ifp, split_fsb, &icur, &got) || got.br_startoff >= split_fsb) return 0; gotblkcnt = split_fsb - got.br_startoff; new.br_startoff = split_fsb; new.br_startblock = got.br_startblock + gotblkcnt; new.br_blockcount = got.br_blockcount - gotblkcnt; new.br_state = got.br_state; if (ifp->if_flags & XFS_IFBROOT) { cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.flags = 0; error = xfs_bmbt_lookup_eq(cur, &got, &i); if (error) goto del_cursor; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); } got.br_blockcount = gotblkcnt; xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), &icur, &got); logflags = XFS_ILOG_CORE; if (cur) { error = xfs_bmbt_update(cur, &got); if (error) goto del_cursor; } else logflags |= XFS_ILOG_DEXT; /* Add new extent */ xfs_iext_next(ifp, &icur); xfs_iext_insert(ip, &icur, &new, 0); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); if (cur) { error = xfs_bmbt_lookup_eq(cur, &new, &i); if (error) goto del_cursor; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, del_cursor); error = xfs_btree_insert(cur, &i); if (error) goto del_cursor; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); } /* * Convert to a btree if necessary. */ if (xfs_bmap_needs_btree(ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, &cur, 0, &tmp_logflags, whichfork); logflags |= tmp_logflags; } del_cursor: if (cur) { cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, error); } if (logflags) xfs_trans_log_inode(tp, ip, logflags); return error; } int xfs_bmap_split_extent( struct xfs_inode *ip, xfs_fileoff_t split_fsb) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, 0, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); error = xfs_bmap_split_extent_at(tp, ip, split_fsb); if (error) goto out; return xfs_trans_commit(tp); out: xfs_trans_cancel(tp); return error; } /* Deferred mapping is only for real extents in the data fork. */ static bool xfs_bmap_is_update_needed( struct xfs_bmbt_irec *bmap) { return bmap->br_startblock != HOLESTARTBLOCK && bmap->br_startblock != DELAYSTARTBLOCK; } /* Record a bmap intent. */ static int __xfs_bmap_add( struct xfs_trans *tp, enum xfs_bmap_intent_type type, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *bmap) { struct xfs_bmap_intent *bi; trace_xfs_bmap_defer(tp->t_mountp, XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock), type, XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock), ip->i_ino, whichfork, bmap->br_startoff, bmap->br_blockcount, bmap->br_state); bi = kmem_alloc(sizeof(struct xfs_bmap_intent), KM_SLEEP | KM_NOFS); INIT_LIST_HEAD(&bi->bi_list); bi->bi_type = type; bi->bi_owner = ip; bi->bi_whichfork = whichfork; bi->bi_bmap = *bmap; xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_BMAP, &bi->bi_list); return 0; } /* Map an extent into a file. */ int xfs_bmap_map_extent( struct xfs_trans *tp, struct xfs_inode *ip, struct xfs_bmbt_irec *PREV) { if (!xfs_bmap_is_update_needed(PREV)) return 0; return __xfs_bmap_add(tp, XFS_BMAP_MAP, ip, XFS_DATA_FORK, PREV); } /* Unmap an extent out of a file. */ int xfs_bmap_unmap_extent( struct xfs_trans *tp, struct xfs_inode *ip, struct xfs_bmbt_irec *PREV) { if (!xfs_bmap_is_update_needed(PREV)) return 0; return __xfs_bmap_add(tp, XFS_BMAP_UNMAP, ip, XFS_DATA_FORK, PREV); } /* * Process one of the deferred bmap operations. We pass back the * btree cursor to maintain our lock on the bmapbt between calls. */ int xfs_bmap_finish_one( struct xfs_trans *tp, struct xfs_inode *ip, enum xfs_bmap_intent_type type, int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock, xfs_filblks_t *blockcount, xfs_exntst_t state) { int error = 0; ASSERT(tp->t_firstblock == NULLFSBLOCK); trace_xfs_bmap_deferred(tp->t_mountp, XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type, XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), ip->i_ino, whichfork, startoff, *blockcount, state); if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK)) return -EFSCORRUPTED; if (XFS_TEST_ERROR(false, tp->t_mountp, XFS_ERRTAG_BMAP_FINISH_ONE)) return -EIO; switch (type) { case XFS_BMAP_MAP: error = xfs_bmapi_remap(tp, ip, startoff, *blockcount, startblock, 0); *blockcount = 0; break; case XFS_BMAP_UNMAP: error = __xfs_bunmapi(tp, ip, startoff, blockcount, XFS_BMAPI_REMAP, 1); break; default: ASSERT(0); error = -EFSCORRUPTED; } return error; } /* Check that an inode's extent does not have invalid flags or bad ranges. */ xfs_failaddr_t xfs_bmap_validate_extent( struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *irec) { struct xfs_mount *mp = ip->i_mount; xfs_fsblock_t endfsb; bool isrt; isrt = XFS_IS_REALTIME_INODE(ip); endfsb = irec->br_startblock + irec->br_blockcount - 1; if (isrt) { if (!xfs_verify_rtbno(mp, irec->br_startblock)) return __this_address; if (!xfs_verify_rtbno(mp, endfsb)) return __this_address; } else { if (!xfs_verify_fsbno(mp, irec->br_startblock)) return __this_address; if (!xfs_verify_fsbno(mp, endfsb)) return __this_address; if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) != XFS_FSB_TO_AGNO(mp, endfsb)) return __this_address; } if (irec->br_state != XFS_EXT_NORM && whichfork != XFS_DATA_FORK) return __this_address; return NULL; } xfsprogs-5.3.0/libxfs/xfs_bmap.h0000644000175000017500000002265713570057155016527 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_BMAP_H__ #define __XFS_BMAP_H__ struct getbmap; struct xfs_bmbt_irec; struct xfs_ifork; struct xfs_inode; struct xfs_mount; struct xfs_trans; extern kmem_zone_t *xfs_bmap_free_item_zone; /* * Argument structure for xfs_bmap_alloc. */ struct xfs_bmalloca { struct xfs_trans *tp; /* transaction pointer */ struct xfs_inode *ip; /* incore inode pointer */ struct xfs_bmbt_irec prev; /* extent before the new one */ struct xfs_bmbt_irec got; /* extent after, or delayed */ xfs_fileoff_t offset; /* offset in file filling in */ xfs_extlen_t length; /* i/o length asked/allocated */ xfs_fsblock_t blkno; /* starting block of new extent */ struct xfs_btree_cur *cur; /* btree cursor */ struct xfs_iext_cursor icur; /* incore extent cursor */ int nallocs;/* number of extents alloc'd */ int logflags;/* flags for transaction logging */ xfs_extlen_t total; /* total blocks needed for xaction */ xfs_extlen_t minlen; /* minimum allocation size (blocks) */ xfs_extlen_t minleft; /* amount must be left after alloc */ bool eof; /* set if allocating past last extent */ bool wasdel; /* replacing a delayed allocation */ bool aeof; /* allocated space at eof */ bool conv; /* overwriting unwritten extents */ int datatype;/* data type being allocated */ int flags; }; /* * List of extents to be free "later". * The list is kept sorted on xbf_startblock. */ struct xfs_extent_free_item { xfs_fsblock_t xefi_startblock;/* starting fs block number */ xfs_extlen_t xefi_blockcount;/* number of blocks in extent */ struct list_head xefi_list; struct xfs_owner_info xefi_oinfo; /* extent owner */ bool xefi_skip_discard; }; #define XFS_BMAP_MAX_NMAP 4 /* * Flags for xfs_bmapi_* */ #define XFS_BMAPI_ENTIRE 0x001 /* return entire extent, not trimmed */ #define XFS_BMAPI_METADATA 0x002 /* mapping metadata not user data */ #define XFS_BMAPI_ATTRFORK 0x004 /* use attribute fork not data */ #define XFS_BMAPI_PREALLOC 0x008 /* preallocation op: unwritten space */ #define XFS_BMAPI_CONTIG 0x020 /* must allocate only one extent */ /* * unwritten extent conversion - this needs write cache flushing and no additional * allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts * from written to unwritten, otherwise convert from unwritten to written. */ #define XFS_BMAPI_CONVERT 0x040 /* * allocate zeroed extents - this requires all newly allocated user data extents * to be initialised to zero. It will be ignored if XFS_BMAPI_METADATA is set. * Use in conjunction with XFS_BMAPI_CONVERT to convert unwritten extents found * during the allocation range to zeroed written extents. */ #define XFS_BMAPI_ZERO 0x080 /* * Map the inode offset to the block given in ap->firstblock. Primarily * used for reflink. The range must be in a hole, and this flag cannot be * turned on with PREALLOC or CONVERT, and cannot be used on the attr fork. * * For bunmapi, this flag unmaps the range without adjusting quota, reducing * refcount, or freeing the blocks. */ #define XFS_BMAPI_REMAP 0x100 /* Map something in the CoW fork. */ #define XFS_BMAPI_COWFORK 0x200 /* Skip online discard of freed extents */ #define XFS_BMAPI_NODISCARD 0x1000 /* Do not update the rmap btree. Used for reconstructing bmbt from rmapbt. */ #define XFS_BMAPI_NORMAP 0x2000 #define XFS_BMAPI_FLAGS \ { XFS_BMAPI_ENTIRE, "ENTIRE" }, \ { XFS_BMAPI_METADATA, "METADATA" }, \ { XFS_BMAPI_ATTRFORK, "ATTRFORK" }, \ { XFS_BMAPI_PREALLOC, "PREALLOC" }, \ { XFS_BMAPI_CONTIG, "CONTIG" }, \ { XFS_BMAPI_CONVERT, "CONVERT" }, \ { XFS_BMAPI_ZERO, "ZERO" }, \ { XFS_BMAPI_REMAP, "REMAP" }, \ { XFS_BMAPI_COWFORK, "COWFORK" }, \ { XFS_BMAPI_NODISCARD, "NODISCARD" }, \ { XFS_BMAPI_NORMAP, "NORMAP" } static inline int xfs_bmapi_aflag(int w) { return (w == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : (w == XFS_COW_FORK ? XFS_BMAPI_COWFORK : 0)); } static inline int xfs_bmapi_whichfork(int bmapi_flags) { if (bmapi_flags & XFS_BMAPI_COWFORK) return XFS_COW_FORK; else if (bmapi_flags & XFS_BMAPI_ATTRFORK) return XFS_ATTR_FORK; return XFS_DATA_FORK; } /* * Special values for xfs_bmbt_irec_t br_startblock field. */ #define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL) #define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL) /* * Flags for xfs_bmap_add_extent*. */ #define BMAP_LEFT_CONTIG (1 << 0) #define BMAP_RIGHT_CONTIG (1 << 1) #define BMAP_LEFT_FILLING (1 << 2) #define BMAP_RIGHT_FILLING (1 << 3) #define BMAP_LEFT_DELAY (1 << 4) #define BMAP_RIGHT_DELAY (1 << 5) #define BMAP_LEFT_VALID (1 << 6) #define BMAP_RIGHT_VALID (1 << 7) #define BMAP_ATTRFORK (1 << 8) #define BMAP_COWFORK (1 << 9) #define XFS_BMAP_EXT_FLAGS \ { BMAP_LEFT_CONTIG, "LC" }, \ { BMAP_RIGHT_CONTIG, "RC" }, \ { BMAP_LEFT_FILLING, "LF" }, \ { BMAP_RIGHT_FILLING, "RF" }, \ { BMAP_ATTRFORK, "ATTR" }, \ { BMAP_COWFORK, "COW" } /* * Return true if the extent is a real, allocated extent, or false if it is a * delayed allocation, and unwritten extent or a hole. */ static inline bool xfs_bmap_is_real_extent(struct xfs_bmbt_irec *irec) { return irec->br_state != XFS_EXT_UNWRITTEN && irec->br_startblock != HOLESTARTBLOCK && irec->br_startblock != DELAYSTARTBLOCK && !isnullstartblock(irec->br_startblock); } void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno, xfs_filblks_t len); int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); int xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version); void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); void __xfs_bmap_add_free(struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, const struct xfs_owner_info *oinfo, bool skip_discard); void xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork); int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip, xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork); int xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *last_block, int whichfork); int xfs_bmap_last_offset(struct xfs_inode *ip, xfs_fileoff_t *unused, int whichfork); int xfs_bmap_one_block(struct xfs_inode *ip, int whichfork); int xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, struct xfs_bmbt_irec *mval, int *nmap, int flags); int xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_extlen_t total, struct xfs_bmbt_irec *mval, int *nmap); int __xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t *rlen, int flags, xfs_extnum_t nexts); int xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_extnum_t nexts, int *done); int xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del); void xfs_bmap_del_extent_cow(struct xfs_inode *ip, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del); uint xfs_default_attroffset(struct xfs_inode *ip); int xfs_bmap_collapse_extents(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, bool *done); int xfs_bmap_can_insert_extents(struct xfs_inode *ip, xfs_fileoff_t off, xfs_fileoff_t shift); int xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, bool *done, xfs_fileoff_t stop_fsb); int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc, struct xfs_bmbt_irec *got, struct xfs_iext_cursor *cur, int eof); int xfs_bmapi_convert_delalloc(struct xfs_inode *ip, int whichfork, xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap, unsigned int *seq); int xfs_bmap_add_extent_unwritten_real(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_iext_cursor *icur, struct xfs_btree_cur **curp, struct xfs_bmbt_irec *new, int *logflagsp); static inline void xfs_bmap_add_free( struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, const struct xfs_owner_info *oinfo) { __xfs_bmap_add_free(tp, bno, len, oinfo, false); } enum xfs_bmap_intent_type { XFS_BMAP_MAP = 1, XFS_BMAP_UNMAP, }; struct xfs_bmap_intent { struct list_head bi_list; enum xfs_bmap_intent_type bi_type; struct xfs_inode *bi_owner; int bi_whichfork; struct xfs_bmbt_irec bi_bmap; }; int xfs_bmap_finish_one(struct xfs_trans *tp, struct xfs_inode *ip, enum xfs_bmap_intent_type type, int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock, xfs_filblks_t *blockcount, xfs_exntst_t state); int xfs_bmap_map_extent(struct xfs_trans *tp, struct xfs_inode *ip, struct xfs_bmbt_irec *imap); int xfs_bmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip, struct xfs_bmbt_irec *imap); static inline int xfs_bmap_fork_to_state(int whichfork) { switch (whichfork) { case XFS_ATTR_FORK: return BMAP_ATTRFORK; case XFS_COW_FORK: return BMAP_COWFORK; default: return 0; } } xfs_failaddr_t xfs_bmap_validate_extent(struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *irec); int xfs_bmapi_remap(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, xfs_fsblock_t startblock, int flags); #endif /* __XFS_BMAP_H__ */ xfsprogs-5.3.0/libxfs/xfs_bmap_btree.c0000644000175000017500000004111113570057155017665 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_btree.h" #include "xfs_bmap_btree.h" #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_rmap.h" /* * Convert on-disk form of btree root to in-memory form. */ void xfs_bmdr_to_bmbt( struct xfs_inode *ip, xfs_bmdr_block_t *dblock, int dblocklen, struct xfs_btree_block *rblock, int rblocklen) { struct xfs_mount *mp = ip->i_mount; int dmxr; xfs_bmbt_key_t *fkp; __be64 *fpp; xfs_bmbt_key_t *tkp; __be64 *tpp; xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, XFS_BTNUM_BMAP, 0, 0, ip->i_ino, XFS_BTREE_LONG_PTRS); rblock->bb_level = dblock->bb_level; ASSERT(be16_to_cpu(rblock->bb_level) > 0); rblock->bb_numrecs = dblock->bb_numrecs; dmxr = xfs_bmdr_maxrecs(dblocklen, 0); fkp = XFS_BMDR_KEY_ADDR(dblock, 1); tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); dmxr = be16_to_cpu(dblock->bb_numrecs); memcpy(tkp, fkp, sizeof(*fkp) * dmxr); memcpy(tpp, fpp, sizeof(*fpp) * dmxr); } void xfs_bmbt_disk_get_all( struct xfs_bmbt_rec *rec, struct xfs_bmbt_irec *irec) { uint64_t l0 = get_unaligned_be64(&rec->l0); uint64_t l1 = get_unaligned_be64(&rec->l1); irec->br_startoff = (l0 & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; irec->br_startblock = ((l0 & xfs_mask64lo(9)) << 43) | (l1 >> 21); irec->br_blockcount = l1 & xfs_mask64lo(21); if (l0 >> (64 - BMBT_EXNTFLAG_BITLEN)) irec->br_state = XFS_EXT_UNWRITTEN; else irec->br_state = XFS_EXT_NORM; } /* * Extract the blockcount field from an on disk bmap extent record. */ xfs_filblks_t xfs_bmbt_disk_get_blockcount( xfs_bmbt_rec_t *r) { return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21)); } /* * Extract the startoff field from a disk format bmap extent record. */ xfs_fileoff_t xfs_bmbt_disk_get_startoff( xfs_bmbt_rec_t *r) { return ((xfs_fileoff_t)be64_to_cpu(r->l0) & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; } /* * Set all the fields in a bmap extent record from the uncompressed form. */ void xfs_bmbt_disk_set_all( struct xfs_bmbt_rec *r, struct xfs_bmbt_irec *s) { int extent_flag = (s->br_state != XFS_EXT_NORM); ASSERT(s->br_state == XFS_EXT_NORM || s->br_state == XFS_EXT_UNWRITTEN); ASSERT(!(s->br_startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN))); ASSERT(!(s->br_blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN))); ASSERT(!(s->br_startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN))); put_unaligned_be64( ((xfs_bmbt_rec_base_t)extent_flag << 63) | ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | ((xfs_bmbt_rec_base_t)s->br_startblock >> 43), &r->l0); put_unaligned_be64( ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | ((xfs_bmbt_rec_base_t)s->br_blockcount & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)), &r->l1); } /* * Convert in-memory form of btree root to on-disk form. */ void xfs_bmbt_to_bmdr( struct xfs_mount *mp, struct xfs_btree_block *rblock, int rblocklen, xfs_bmdr_block_t *dblock, int dblocklen) { int dmxr; xfs_bmbt_key_t *fkp; __be64 *fpp; xfs_bmbt_key_t *tkp; __be64 *tpp; if (xfs_sb_version_hascrc(&mp->m_sb)) { ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC)); ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)); ASSERT(rblock->bb_u.l.bb_blkno == cpu_to_be64(XFS_BUF_DADDR_NULL)); } else ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)); ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)); ASSERT(rblock->bb_level != 0); dblock->bb_level = rblock->bb_level; dblock->bb_numrecs = rblock->bb_numrecs; dmxr = xfs_bmdr_maxrecs(dblocklen, 0); fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); tkp = XFS_BMDR_KEY_ADDR(dblock, 1); fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); dmxr = be16_to_cpu(dblock->bb_numrecs); memcpy(tkp, fkp, sizeof(*fkp) * dmxr); memcpy(tpp, fpp, sizeof(*fpp) * dmxr); } STATIC struct xfs_btree_cur * xfs_bmbt_dup_cursor( struct xfs_btree_cur *cur) { struct xfs_btree_cur *new; new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.b.ip, cur->bc_private.b.whichfork); /* * Copy the firstblock, dfops, and flags values, * since init cursor doesn't get them. */ new->bc_private.b.flags = cur->bc_private.b.flags; return new; } STATIC void xfs_bmbt_update_cursor( struct xfs_btree_cur *src, struct xfs_btree_cur *dst) { ASSERT((dst->bc_tp->t_firstblock != NULLFSBLOCK) || (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); dst->bc_private.b.allocated += src->bc_private.b.allocated; dst->bc_tp->t_firstblock = src->bc_tp->t_firstblock; src->bc_private.b.allocated = 0; } STATIC int xfs_bmbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { xfs_alloc_arg_t args; /* block allocation args */ int error; /* error return value */ memset(&args, 0, sizeof(args)); args.tp = cur->bc_tp; args.mp = cur->bc_mp; args.fsbno = cur->bc_tp->t_firstblock; xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_private.b.ip->i_ino, cur->bc_private.b.whichfork); if (args.fsbno == NULLFSBLOCK) { args.fsbno = be64_to_cpu(start->l); args.type = XFS_ALLOCTYPE_START_BNO; /* * Make sure there is sufficient room left in the AG to * complete a full tree split for an extent insert. If * we are converting the middle part of an extent then * we may need space for two tree splits. * * We are relying on the caller to make the correct block * reservation for this operation to succeed. If the * reservation amount is insufficient then we may fail a * block allocation here and corrupt the filesystem. */ args.minleft = args.tp->t_blk_res; } else if (cur->bc_tp->t_flags & XFS_TRANS_LOWMODE) { args.type = XFS_ALLOCTYPE_START_BNO; } else { args.type = XFS_ALLOCTYPE_NEAR_BNO; } args.minlen = args.maxlen = args.prod = 1; args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; if (!args.wasdel && args.tp->t_blk_res == 0) { error = -ENOSPC; goto error0; } error = xfs_alloc_vextent(&args); if (error) goto error0; if (args.fsbno == NULLFSBLOCK && args.minleft) { /* * Could not find an AG with enough free space to satisfy * a full btree split. Try again and if * successful activate the lowspace algorithm. */ args.fsbno = 0; args.type = XFS_ALLOCTYPE_FIRST_AG; error = xfs_alloc_vextent(&args); if (error) goto error0; cur->bc_tp->t_flags |= XFS_TRANS_LOWMODE; } if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) { *stat = 0; return 0; } ASSERT(args.len == 1); cur->bc_tp->t_firstblock = args.fsbno; cur->bc_private.b.allocated++; cur->bc_private.b.ip->i_d.di_nblocks++; xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, XFS_TRANS_DQ_BCOUNT, 1L); new->l = cpu_to_be64(args.fsbno); *stat = 1; return 0; error0: return error; } STATIC int xfs_bmbt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; struct xfs_inode *ip = cur->bc_private.b.ip; struct xfs_trans *tp = cur->bc_tp; xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); struct xfs_owner_info oinfo; xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_private.b.whichfork); xfs_bmap_add_free(cur->bc_tp, fsbno, 1, &oinfo); ip->i_d.di_nblocks--; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); return 0; } STATIC int xfs_bmbt_get_minrecs( struct xfs_btree_cur *cur, int level) { if (level == cur->bc_nlevels - 1) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); return xfs_bmbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, level == 0) / 2; } return cur->bc_mp->m_bmap_dmnr[level != 0]; } int xfs_bmbt_get_maxrecs( struct xfs_btree_cur *cur, int level) { if (level == cur->bc_nlevels - 1) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); return xfs_bmbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, level == 0); } return cur->bc_mp->m_bmap_dmxr[level != 0]; } /* * Get the maximum records we could store in the on-disk format. * * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but * for the root node this checks the available space in the dinode fork * so that we can resize the in-memory buffer to match it. After a * resize to the maximum size this function returns the same value * as xfs_bmbt_get_maxrecs for the root node, too. */ STATIC int xfs_bmbt_get_dmaxrecs( struct xfs_btree_cur *cur, int level) { if (level != cur->bc_nlevels - 1) return cur->bc_mp->m_bmap_dmxr[level != 0]; return xfs_bmdr_maxrecs(cur->bc_private.b.forksize, level == 0); } STATIC void xfs_bmbt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->bmbt.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt)); } STATIC void xfs_bmbt_init_high_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->bmbt.br_startoff = cpu_to_be64( xfs_bmbt_disk_get_startoff(&rec->bmbt) + xfs_bmbt_disk_get_blockcount(&rec->bmbt) - 1); } STATIC void xfs_bmbt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); } STATIC void xfs_bmbt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { ptr->l = 0; } STATIC int64_t xfs_bmbt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { return (int64_t)be64_to_cpu(key->bmbt.br_startoff) - cur->bc_rec.b.br_startoff; } STATIC int64_t xfs_bmbt_diff_two_keys( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return (int64_t)be64_to_cpu(k1->bmbt.br_startoff) - be64_to_cpu(k2->bmbt.br_startoff); } static xfs_failaddr_t xfs_bmbt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_failaddr_t fa; unsigned int level; if (!xfs_verify_magic(bp, block->bb_magic)) return __this_address; if (xfs_sb_version_hascrc(&mp->m_sb)) { /* * XXX: need a better way of verifying the owner here. Right now * just make sure there has been one set. */ fa = xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN); if (fa) return fa; } /* * numrecs and level verification. * * We don't know what fork we belong to, so just verify that the level * is less than the maximum of the two. Later checks will be more * precise. */ level = be16_to_cpu(block->bb_level); if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1])) return __this_address; return xfs_btree_lblock_verify(bp, mp->m_bmap_dmxr[level != 0]); } static void xfs_bmbt_read_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; if (!xfs_btree_lblock_verify_crc(bp)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_bmbt_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } if (bp->b_error) trace_xfs_btree_corrupt(bp, _RET_IP_); } static void xfs_bmbt_write_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_bmbt_verify(bp); if (fa) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } xfs_btree_lblock_calc_crc(bp); } const struct xfs_buf_ops xfs_bmbt_buf_ops = { .name = "xfs_bmbt", .magic = { cpu_to_be32(XFS_BMAP_MAGIC), cpu_to_be32(XFS_BMAP_CRC_MAGIC) }, .verify_read = xfs_bmbt_read_verify, .verify_write = xfs_bmbt_write_verify, .verify_struct = xfs_bmbt_verify, }; STATIC int xfs_bmbt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be64_to_cpu(k1->bmbt.br_startoff) < be64_to_cpu(k2->bmbt.br_startoff); } STATIC int xfs_bmbt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return xfs_bmbt_disk_get_startoff(&r1->bmbt) + xfs_bmbt_disk_get_blockcount(&r1->bmbt) <= xfs_bmbt_disk_get_startoff(&r2->bmbt); } static const struct xfs_btree_ops xfs_bmbt_ops = { .rec_len = sizeof(xfs_bmbt_rec_t), .key_len = sizeof(xfs_bmbt_key_t), .dup_cursor = xfs_bmbt_dup_cursor, .update_cursor = xfs_bmbt_update_cursor, .alloc_block = xfs_bmbt_alloc_block, .free_block = xfs_bmbt_free_block, .get_maxrecs = xfs_bmbt_get_maxrecs, .get_minrecs = xfs_bmbt_get_minrecs, .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, .init_key_from_rec = xfs_bmbt_init_key_from_rec, .init_high_key_from_rec = xfs_bmbt_init_high_key_from_rec, .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, .key_diff = xfs_bmbt_key_diff, .diff_two_keys = xfs_bmbt_diff_two_keys, .buf_ops = &xfs_bmbt_buf_ops, .keys_inorder = xfs_bmbt_keys_inorder, .recs_inorder = xfs_bmbt_recs_inorder, }; /* * Allocate a new bmap btree cursor. */ struct xfs_btree_cur * /* new bmap btree cursor */ xfs_bmbt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* inode owning the btree */ int whichfork) /* data or attr fork */ { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_cur *cur; ASSERT(whichfork != XFS_COW_FORK); cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; cur->bc_btnum = XFS_BTNUM_BMAP; cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_bmbt_2); cur->bc_ops = &xfs_bmbt_ops; cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); cur->bc_private.b.ip = ip; cur->bc_private.b.allocated = 0; cur->bc_private.b.flags = 0; cur->bc_private.b.whichfork = whichfork; return cur; } /* * Calculate number of records in a bmap btree block. */ int xfs_bmbt_maxrecs( struct xfs_mount *mp, int blocklen, int leaf) { blocklen -= XFS_BMBT_BLOCK_LEN(mp); if (leaf) return blocklen / sizeof(xfs_bmbt_rec_t); return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); } /* * Calculate number of records in a bmap btree inode root. */ int xfs_bmdr_maxrecs( int blocklen, int leaf) { blocklen -= sizeof(xfs_bmdr_block_t); if (leaf) return blocklen / sizeof(xfs_bmdr_rec_t); return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); } /* * Change the owner of a btree format fork fo the inode passed in. Change it to * the owner of that is passed in so that we can change owners before or after * we switch forks between inodes. The operation that the caller is doing will * determine whether is needs to change owner before or after the switch. * * For demand paged transactional modification, the fork switch should be done * after reading in all the blocks, modifying them and pinning them in the * transaction. For modification when the buffers are already pinned in memory, * the fork switch can be done before changing the owner as we won't need to * validate the owner until the btree buffers are unpinned and writes can occur * again. * * For recovery based ownership change, there is no transactional context and * so a buffer list must be supplied so that we can record the buffers that we * modified for the caller to issue IO on. */ int xfs_bmbt_change_owner( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, xfs_ino_t new_owner, struct list_head *buffer_list) { struct xfs_btree_cur *cur; int error; ASSERT(tp || buffer_list); ASSERT(!(tp && buffer_list)); if (whichfork == XFS_DATA_FORK) ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE); else ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE); cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork); if (!cur) return -ENOMEM; cur->bc_private.b.flags |= XFS_BTCUR_BPRV_INVALID_OWNER; error = xfs_btree_change_owner(cur, new_owner, buffer_list); xfs_btree_del_cursor(cur, error); return error; } /* Calculate the bmap btree size for some records. */ unsigned long long xfs_bmbt_calc_size( struct xfs_mount *mp, unsigned long long len) { return xfs_btree_calc_size(mp->m_bmap_dmnr, len); } xfsprogs-5.3.0/libxfs/xfs_bmap_btree.h0000644000175000017500000000673713435336036017707 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_BMAP_BTREE_H__ #define __XFS_BMAP_BTREE_H__ struct xfs_btree_cur; struct xfs_btree_block; struct xfs_mount; struct xfs_inode; struct xfs_trans; /* * Btree block header size depends on a superblock flag. */ #define XFS_BMBT_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN) #define XFS_BMBT_REC_ADDR(mp, block, index) \ ((xfs_bmbt_rec_t *) \ ((char *)(block) + \ XFS_BMBT_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_bmbt_rec_t))) #define XFS_BMBT_KEY_ADDR(mp, block, index) \ ((xfs_bmbt_key_t *) \ ((char *)(block) + \ XFS_BMBT_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_bmbt_key_t))) #define XFS_BMBT_PTR_ADDR(mp, block, index, maxrecs) \ ((xfs_bmbt_ptr_t *) \ ((char *)(block) + \ XFS_BMBT_BLOCK_LEN(mp) + \ (maxrecs) * sizeof(xfs_bmbt_key_t) + \ ((index) - 1) * sizeof(xfs_bmbt_ptr_t))) #define XFS_BMDR_REC_ADDR(block, index) \ ((xfs_bmdr_rec_t *) \ ((char *)(block) + \ sizeof(struct xfs_bmdr_block) + \ ((index) - 1) * sizeof(xfs_bmdr_rec_t))) #define XFS_BMDR_KEY_ADDR(block, index) \ ((xfs_bmdr_key_t *) \ ((char *)(block) + \ sizeof(struct xfs_bmdr_block) + \ ((index) - 1) * sizeof(xfs_bmdr_key_t))) #define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \ ((xfs_bmdr_ptr_t *) \ ((char *)(block) + \ sizeof(struct xfs_bmdr_block) + \ (maxrecs) * sizeof(xfs_bmdr_key_t) + \ ((index) - 1) * sizeof(xfs_bmdr_ptr_t))) /* * These are to be used when we know the size of the block and * we don't have a cursor. */ #define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \ XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0)) #define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \ (int)(XFS_BMBT_BLOCK_LEN(mp) + \ ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) #define XFS_BMAP_BROOT_SPACE(mp, bb) \ (XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs))) #define XFS_BMDR_SPACE_CALC(nrecs) \ (int)(sizeof(xfs_bmdr_block_t) + \ ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) #define XFS_BMAP_BMDR_SPACE(bb) \ (XFS_BMDR_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs))) /* * Maximum number of bmap btree levels. */ #define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[(w)]) /* * Prototypes for xfs_bmap.c to call. */ extern void xfs_bmdr_to_bmbt(struct xfs_inode *, xfs_bmdr_block_t *, int, struct xfs_btree_block *, int); void xfs_bmbt_disk_set_all(struct xfs_bmbt_rec *r, struct xfs_bmbt_irec *s); extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int, xfs_bmdr_block_t *, int); extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); extern int xfs_bmdr_maxrecs(int blocklen, int leaf); extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, xfs_ino_t new_owner, struct list_head *buffer_list); extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, struct xfs_trans *, struct xfs_inode *, int); extern unsigned long long xfs_bmbt_calc_size(struct xfs_mount *mp, unsigned long long len); #endif /* __XFS_BMAP_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_btree.c0000644000175000017500000037646113570057155016711 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_btree.h" #include "xfs_trace.h" /* * Cursor allocation zone. */ kmem_zone_t *xfs_btree_cur_zone; /* * Btree magic numbers. */ static const uint32_t xfs_magics[2][XFS_BTNUM_MAX] = { { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, 0, XFS_BMAP_MAGIC, XFS_IBT_MAGIC, XFS_FIBT_MAGIC, 0 }, { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, XFS_RMAP_CRC_MAGIC, XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC, XFS_REFC_CRC_MAGIC } }; uint32_t xfs_btree_magic( int crc, xfs_btnum_t btnum) { uint32_t magic = xfs_magics[crc][btnum]; /* Ensure we asked for crc for crc-only magics. */ ASSERT(magic != 0); return magic; } /* * Check a long btree block header. Return the address of the failing check, * or NULL if everything is ok. */ xfs_failaddr_t __xfs_btree_check_lblock( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; xfs_btnum_t btnum = cur->bc_btnum; int crc = xfs_sb_version_hascrc(&mp->m_sb); if (crc) { if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (block->bb_u.l.bb_blkno != cpu_to_be64(bp ? bp->b_bn : XFS_BUF_DADDR_NULL)) return __this_address; if (block->bb_u.l.bb_pad != cpu_to_be32(0)) return __this_address; } if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(crc, btnum)) return __this_address; if (be16_to_cpu(block->bb_level) != level) return __this_address; if (be16_to_cpu(block->bb_numrecs) > cur->bc_ops->get_maxrecs(cur, level)) return __this_address; if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_leftsib), level + 1)) return __this_address; if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_rightsib), level + 1)) return __this_address; return NULL; } /* Check a long btree block header. */ static int xfs_btree_check_lblock( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; xfs_failaddr_t fa; fa = __xfs_btree_check_lblock(cur, block, level, bp); if (unlikely(XFS_TEST_ERROR(fa != NULL, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK))) { if (bp) trace_xfs_btree_corrupt(bp, _RET_IP_); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } return 0; } /* * Check a short btree block header. Return the address of the failing check, * or NULL if everything is ok. */ xfs_failaddr_t __xfs_btree_check_sblock( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; xfs_btnum_t btnum = cur->bc_btnum; int crc = xfs_sb_version_hascrc(&mp->m_sb); if (crc) { if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (block->bb_u.s.bb_blkno != cpu_to_be64(bp ? bp->b_bn : XFS_BUF_DADDR_NULL)) return __this_address; } if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(crc, btnum)) return __this_address; if (be16_to_cpu(block->bb_level) != level) return __this_address; if (be16_to_cpu(block->bb_numrecs) > cur->bc_ops->get_maxrecs(cur, level)) return __this_address; if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) && !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_leftsib), level + 1)) return __this_address; if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) && !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_rightsib), level + 1)) return __this_address; return NULL; } /* Check a short btree block header. */ STATIC int xfs_btree_check_sblock( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; xfs_failaddr_t fa; fa = __xfs_btree_check_sblock(cur, block, level, bp); if (unlikely(XFS_TEST_ERROR(fa != NULL, mp, XFS_ERRTAG_BTREE_CHECK_SBLOCK))) { if (bp) trace_xfs_btree_corrupt(bp, _RET_IP_); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } return 0; } /* * Debug routine: check that block header is ok. */ int xfs_btree_check_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* generic btree block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp) /* buffer containing block, if any */ { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return xfs_btree_check_lblock(cur, block, level, bp); else return xfs_btree_check_sblock(cur, block, level, bp); } /* Check that this long pointer is valid and points within the fs. */ bool xfs_btree_check_lptr( struct xfs_btree_cur *cur, xfs_fsblock_t fsbno, int level) { if (level <= 0) return false; return xfs_verify_fsbno(cur->bc_mp, fsbno); } /* Check that this short pointer is valid and points within the AG. */ bool xfs_btree_check_sptr( struct xfs_btree_cur *cur, xfs_agblock_t agbno, int level) { if (level <= 0) return false; return xfs_verify_agbno(cur->bc_mp, cur->bc_private.a.agno, agbno); } /* * Check that a given (indexed) btree pointer at a certain level of a * btree is valid and doesn't point past where it should. */ static int xfs_btree_check_ptr( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int index, int level) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (xfs_btree_check_lptr(cur, be64_to_cpu((&ptr->l)[index]), level)) return 0; xfs_err(cur->bc_mp, "Inode %llu fork %d: Corrupt btree %d pointer at level %d index %d.", cur->bc_private.b.ip->i_ino, cur->bc_private.b.whichfork, cur->bc_btnum, level, index); } else { if (xfs_btree_check_sptr(cur, be32_to_cpu((&ptr->s)[index]), level)) return 0; xfs_err(cur->bc_mp, "AG %u: Corrupt btree %d pointer at level %d index %d.", cur->bc_private.a.agno, cur->bc_btnum, level, index); } return -EFSCORRUPTED; } #ifdef DEBUG # define xfs_btree_debug_check_ptr xfs_btree_check_ptr #else # define xfs_btree_debug_check_ptr(...) (0) #endif /* * Calculate CRC on the whole btree block and stuff it into the * long-form btree header. * * Prior to calculting the CRC, pull the LSN out of the buffer log item and put * it into the buffer so recovery knows what the last modification was that made * it to disk. */ void xfs_btree_lblock_calc_crc( struct xfs_buf *bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_buf_log_item *bip = bp->b_log_item; if (!xfs_sb_version_hascrc(&bp->b_mount->m_sb)) return; if (bip) block->bb_u.l.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); } bool xfs_btree_lblock_verify_crc( struct xfs_buf *bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_mount *mp = bp->b_mount; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn))) return false; return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); } return true; } /* * Calculate CRC on the whole btree block and stuff it into the * short-form btree header. * * Prior to calculting the CRC, pull the LSN out of the buffer log item and put * it into the buffer so recovery knows what the last modification was that made * it to disk. */ void xfs_btree_sblock_calc_crc( struct xfs_buf *bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_buf_log_item *bip = bp->b_log_item; if (!xfs_sb_version_hascrc(&bp->b_mount->m_sb)) return; if (bip) block->bb_u.s.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); } bool xfs_btree_sblock_verify_crc( struct xfs_buf *bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_mount *mp = bp->b_mount; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn))) return false; return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); } return true; } static int xfs_btree_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { int error; error = cur->bc_ops->free_block(cur, bp); if (!error) { xfs_trans_binval(cur->bc_tp, bp); XFS_BTREE_STATS_INC(cur, free); } return error; } /* * Delete the btree cursor. */ void xfs_btree_del_cursor( xfs_btree_cur_t *cur, /* btree cursor */ int error) /* del because of error */ { int i; /* btree level */ /* * Clear the buffer pointers, and release the buffers. * If we're doing this in the face of an error, we * need to make sure to inspect all of the entries * in the bc_bufs array for buffers to be unlocked. * This is because some of the btree code works from * level n down to 0, and if we get an error along * the way we won't have initialized all the entries * down to 0. */ for (i = 0; i < cur->bc_nlevels; i++) { if (cur->bc_bufs[i]) xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]); else if (!error) break; } /* * Can't free a bmap cursor without having dealt with the * allocated indirect blocks' accounting. */ ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || cur->bc_private.b.allocated == 0); /* * Free the cursor. */ kmem_zone_free(xfs_btree_cur_zone, cur); } /* * Duplicate the btree cursor. * Allocate a new one, copy the record, re-get the buffers. */ int /* error */ xfs_btree_dup_cursor( xfs_btree_cur_t *cur, /* input cursor */ xfs_btree_cur_t **ncur) /* output cursor */ { xfs_buf_t *bp; /* btree block's buffer pointer */ int error; /* error return value */ int i; /* level number of btree block */ xfs_mount_t *mp; /* mount structure for filesystem */ xfs_btree_cur_t *new; /* new cursor value */ xfs_trans_t *tp; /* transaction pointer, can be NULL */ tp = cur->bc_tp; mp = cur->bc_mp; /* * Allocate a new cursor like the old one. */ new = cur->bc_ops->dup_cursor(cur); /* * Copy the record currently in the cursor. */ new->bc_rec = cur->bc_rec; /* * For each level current, re-get the buffer and copy the ptr value. */ for (i = 0; i < new->bc_nlevels; i++) { new->bc_ptrs[i] = cur->bc_ptrs[i]; new->bc_ra[i] = cur->bc_ra[i]; bp = cur->bc_bufs[i]; if (bp) { error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp, cur->bc_ops->buf_ops); if (error) { xfs_btree_del_cursor(new, error); *ncur = NULL; return error; } } new->bc_bufs[i] = bp; } *ncur = new; return 0; } /* * XFS btree block layout and addressing: * * There are two types of blocks in the btree: leaf and non-leaf blocks. * * The leaf record start with a header then followed by records containing * the values. A non-leaf block also starts with the same header, and * then first contains lookup keys followed by an equal number of pointers * to the btree blocks at the previous level. * * +--------+-------+-------+-------+-------+-------+-------+ * Leaf: | header | rec 1 | rec 2 | rec 3 | rec 4 | rec 5 | rec N | * +--------+-------+-------+-------+-------+-------+-------+ * * +--------+-------+-------+-------+-------+-------+-------+ * Non-Leaf: | header | key 1 | key 2 | key N | ptr 1 | ptr 2 | ptr N | * +--------+-------+-------+-------+-------+-------+-------+ * * The header is called struct xfs_btree_block for reasons better left unknown * and comes in different versions for short (32bit) and long (64bit) block * pointers. The record and key structures are defined by the btree instances * and opaque to the btree core. The block pointers are simple disk endian * integers, available in a short (32bit) and long (64bit) variant. * * The helpers below calculate the offset of a given record, key or pointer * into a btree block (xfs_btree_*_offset) or return a pointer to the given * record, key or pointer (xfs_btree_*_addr). Note that all addressing * inside the btree block is done using indices starting at one, not zero! * * If XFS_BTREE_OVERLAPPING is set, then this btree supports keys containing * overlapping intervals. In such a tree, records are still sorted lowest to * highest and indexed by the smallest key value that refers to the record. * However, nodes are different: each pointer has two associated keys -- one * indexing the lowest key available in the block(s) below (the same behavior * as the key in a regular btree) and another indexing the highest key * available in the block(s) below. Because records are /not/ sorted by the * highest key, all leaf block updates require us to compute the highest key * that matches any record in the leaf and to recursively update the high keys * in the nodes going further up in the tree, if necessary. Nodes look like * this: * * +--------+-----+-----+-----+-----+-----+-------+-------+-----+ * Non-Leaf: | header | lo1 | hi1 | lo2 | hi2 | ... | ptr 1 | ptr 2 | ... | * +--------+-----+-----+-----+-----+-----+-------+-------+-----+ * * To perform an interval query on an overlapped tree, perform the usual * depth-first search and use the low and high keys to decide if we can skip * that particular node. If a leaf node is reached, return the records that * intersect the interval. Note that an interval query may return numerous * entries. For a non-overlapped tree, simply search for the record associated * with the lowest key and iterate forward until a non-matching record is * found. Section 14.3 ("Interval Trees") of _Introduction to Algorithms_ by * Cormen, Leiserson, Rivest, and Stein (2nd or 3rd ed. only) discuss this in * more detail. * * Why do we care about overlapping intervals? Let's say you have a bunch of * reverse mapping records on a reflink filesystem: * * 1: +- file A startblock B offset C length D -----------+ * 2: +- file E startblock F offset G length H --------------+ * 3: +- file I startblock F offset J length K --+ * 4: +- file L... --+ * * Now say we want to map block (B+D) into file A at offset (C+D). Ideally, * we'd simply increment the length of record 1. But how do we find the record * that ends at (B+D-1) (i.e. record 1)? A LE lookup of (B+D-1) would return * record 3 because the keys are ordered first by startblock. An interval * query would return records 1 and 2 because they both overlap (B+D-1), and * from that we can pick out record 1 as the appropriate left neighbor. * * In the non-overlapped case you can do a LE lookup and decrement the cursor * because a record's interval must end before the next record. */ /* * Return size of the btree block header for this btree instance. */ static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) return XFS_BTREE_LBLOCK_CRC_LEN; return XFS_BTREE_LBLOCK_LEN; } if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) return XFS_BTREE_SBLOCK_CRC_LEN; return XFS_BTREE_SBLOCK_LEN; } /* * Return size of btree block pointers for this btree instance. */ static inline size_t xfs_btree_ptr_len(struct xfs_btree_cur *cur) { return (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? sizeof(__be64) : sizeof(__be32); } /* * Calculate offset of the n-th record in a btree block. */ STATIC size_t xfs_btree_rec_offset( struct xfs_btree_cur *cur, int n) { return xfs_btree_block_len(cur) + (n - 1) * cur->bc_ops->rec_len; } /* * Calculate offset of the n-th key in a btree block. */ STATIC size_t xfs_btree_key_offset( struct xfs_btree_cur *cur, int n) { return xfs_btree_block_len(cur) + (n - 1) * cur->bc_ops->key_len; } /* * Calculate offset of the n-th high key in a btree block. */ STATIC size_t xfs_btree_high_key_offset( struct xfs_btree_cur *cur, int n) { return xfs_btree_block_len(cur) + (n - 1) * cur->bc_ops->key_len + (cur->bc_ops->key_len / 2); } /* * Calculate offset of the n-th block pointer in a btree block. */ STATIC size_t xfs_btree_ptr_offset( struct xfs_btree_cur *cur, int n, int level) { return xfs_btree_block_len(cur) + cur->bc_ops->get_maxrecs(cur, level) * cur->bc_ops->key_len + (n - 1) * xfs_btree_ptr_len(cur); } /* * Return a pointer to the n-th record in the btree block. */ union xfs_btree_rec * xfs_btree_rec_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { return (union xfs_btree_rec *) ((char *)block + xfs_btree_rec_offset(cur, n)); } /* * Return a pointer to the n-th key in the btree block. */ union xfs_btree_key * xfs_btree_key_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { return (union xfs_btree_key *) ((char *)block + xfs_btree_key_offset(cur, n)); } /* * Return a pointer to the n-th high key in the btree block. */ union xfs_btree_key * xfs_btree_high_key_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { return (union xfs_btree_key *) ((char *)block + xfs_btree_high_key_offset(cur, n)); } /* * Return a pointer to the n-th block pointer in the btree block. */ union xfs_btree_ptr * xfs_btree_ptr_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { int level = xfs_btree_get_level(block); ASSERT(block->bb_level != 0); return (union xfs_btree_ptr *) ((char *)block + xfs_btree_ptr_offset(cur, n, level)); } /* * Get the root block which is stored in the inode. * * For now this btree implementation assumes the btree root is always * stored in the if_broot field of an inode fork. */ STATIC struct xfs_btree_block * xfs_btree_get_iroot( struct xfs_btree_cur *cur) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); return (struct xfs_btree_block *)ifp->if_broot; } /* * Retrieve the block pointer from the cursor at the given level. * This may be an inode btree root or from a buffer. */ struct xfs_btree_block * /* generic btree block pointer */ xfs_btree_get_block( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level in btree */ struct xfs_buf **bpp) /* buffer containing the block */ { if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level == cur->bc_nlevels - 1)) { *bpp = NULL; return xfs_btree_get_iroot(cur); } *bpp = cur->bc_bufs[level]; return XFS_BUF_TO_BLOCK(*bpp); } /* * Get a buffer for the block, return it with no data read. * Long-form addressing. */ xfs_buf_t * /* buffer for fsbno */ xfs_btree_get_bufl( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_fsblock_t fsbno) /* file system block number */ { xfs_daddr_t d; /* real disk block address */ ASSERT(fsbno != NULLFSBLOCK); d = XFS_FSB_TO_DADDR(mp, fsbno); return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0); } /* * Get a buffer for the block, return it with no data read. * Short-form addressing. */ xfs_buf_t * /* buffer for agno/agbno */ xfs_btree_get_bufs( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno) /* allocation group block number */ { xfs_daddr_t d; /* real disk block address */ ASSERT(agno != NULLAGNUMBER); ASSERT(agbno != NULLAGBLOCK); d = XFS_AGB_TO_DADDR(mp, agno, agbno); return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0); } /* * Check for the cursor referring to the last block at the given level. */ int /* 1=is last block, 0=not last block */ xfs_btree_islastblock( xfs_btree_cur_t *cur, /* btree cursor */ int level) /* level to check */ { struct xfs_btree_block *block; /* generic btree block pointer */ xfs_buf_t *bp; /* buffer containing block */ block = xfs_btree_get_block(cur, level, &bp); xfs_btree_check_block(cur, block, level, bp); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK); else return block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK); } /* * Change the cursor to point to the first record at the given level. * Other levels are unaffected. */ STATIC int /* success=1, failure=0 */ xfs_btree_firstrec( xfs_btree_cur_t *cur, /* btree cursor */ int level) /* level to change */ { struct xfs_btree_block *block; /* generic btree block pointer */ xfs_buf_t *bp; /* buffer containing block */ /* * Get the block pointer for this level. */ block = xfs_btree_get_block(cur, level, &bp); if (xfs_btree_check_block(cur, block, level, bp)) return 0; /* * It's empty, there is no such record. */ if (!block->bb_numrecs) return 0; /* * Set the ptr value to 1, that's the first record/key. */ cur->bc_ptrs[level] = 1; return 1; } /* * Change the cursor to point to the last record in the current block * at the given level. Other levels are unaffected. */ STATIC int /* success=1, failure=0 */ xfs_btree_lastrec( xfs_btree_cur_t *cur, /* btree cursor */ int level) /* level to change */ { struct xfs_btree_block *block; /* generic btree block pointer */ xfs_buf_t *bp; /* buffer containing block */ /* * Get the block pointer for this level. */ block = xfs_btree_get_block(cur, level, &bp); if (xfs_btree_check_block(cur, block, level, bp)) return 0; /* * It's empty, there is no such record. */ if (!block->bb_numrecs) return 0; /* * Set the ptr value to numrecs, that's the last record/key. */ cur->bc_ptrs[level] = be16_to_cpu(block->bb_numrecs); return 1; } /* * Compute first and last byte offsets for the fields given. * Interprets the offsets table, which contains struct field offsets. */ void xfs_btree_offsets( int64_t fields, /* bitmask of fields */ const short *offsets, /* table of field offsets */ int nbits, /* number of bits to inspect */ int *first, /* output: first byte offset */ int *last) /* output: last byte offset */ { int i; /* current bit number */ int64_t imask; /* mask for current bit number */ ASSERT(fields != 0); /* * Find the lowest bit, so the first byte offset. */ for (i = 0, imask = 1LL; ; i++, imask <<= 1) { if (imask & fields) { *first = offsets[i]; break; } } /* * Find the highest bit, so the last byte offset. */ for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) { if (imask & fields) { *last = offsets[i + 1] - 1; break; } } } /* * Get a buffer for the block, return it read in. * Long-form addressing. */ int xfs_btree_read_bufl( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t fsbno, /* file system block number */ struct xfs_buf **bpp, /* buffer for fsbno */ int refval, /* ref count value for buffer */ const struct xfs_buf_ops *ops) { struct xfs_buf *bp; /* return value */ xfs_daddr_t d; /* real disk block address */ int error; if (!xfs_verify_fsbno(mp, fsbno)) return -EFSCORRUPTED; d = XFS_FSB_TO_DADDR(mp, fsbno); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, mp->m_bsize, 0, &bp, ops); if (error) return error; if (bp) xfs_buf_set_ref(bp, refval); *bpp = bp; return 0; } /* * Read-ahead the block, don't wait for it, don't return a buffer. * Long-form addressing. */ /* ARGSUSED */ void xfs_btree_reada_bufl( struct xfs_mount *mp, /* file system mount point */ xfs_fsblock_t fsbno, /* file system block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops) { xfs_daddr_t d; ASSERT(fsbno != NULLFSBLOCK); d = XFS_FSB_TO_DADDR(mp, fsbno); xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops); } /* * Read-ahead the block, don't wait for it, don't return a buffer. * Short-form addressing. */ /* ARGSUSED */ void xfs_btree_reada_bufs( struct xfs_mount *mp, /* file system mount point */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno, /* allocation group block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops) { xfs_daddr_t d; ASSERT(agno != NULLAGNUMBER); ASSERT(agbno != NULLAGBLOCK); d = XFS_AGB_TO_DADDR(mp, agno, agbno); xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops); } STATIC int xfs_btree_readahead_lblock( struct xfs_btree_cur *cur, int lr, struct xfs_btree_block *block) { int rval = 0; xfs_fsblock_t left = be64_to_cpu(block->bb_u.l.bb_leftsib); xfs_fsblock_t right = be64_to_cpu(block->bb_u.l.bb_rightsib); if ((lr & XFS_BTCUR_LEFTRA) && left != NULLFSBLOCK) { xfs_btree_reada_bufl(cur->bc_mp, left, 1, cur->bc_ops->buf_ops); rval++; } if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLFSBLOCK) { xfs_btree_reada_bufl(cur->bc_mp, right, 1, cur->bc_ops->buf_ops); rval++; } return rval; } STATIC int xfs_btree_readahead_sblock( struct xfs_btree_cur *cur, int lr, struct xfs_btree_block *block) { int rval = 0; xfs_agblock_t left = be32_to_cpu(block->bb_u.s.bb_leftsib); xfs_agblock_t right = be32_to_cpu(block->bb_u.s.bb_rightsib); if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) { xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, left, 1, cur->bc_ops->buf_ops); rval++; } if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) { xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, right, 1, cur->bc_ops->buf_ops); rval++; } return rval; } /* * Read-ahead btree blocks, at the given level. * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. */ STATIC int xfs_btree_readahead( struct xfs_btree_cur *cur, /* btree cursor */ int lev, /* level in btree */ int lr) /* left/right bits */ { struct xfs_btree_block *block; /* * No readahead needed if we are at the root level and the * btree root is stored in the inode. */ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (lev == cur->bc_nlevels - 1)) return 0; if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) return 0; cur->bc_ra[lev] |= lr; block = XFS_BUF_TO_BLOCK(cur->bc_bufs[lev]); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return xfs_btree_readahead_lblock(cur, lr, block); return xfs_btree_readahead_sblock(cur, lr, block); } STATIC int xfs_btree_ptr_to_daddr( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, xfs_daddr_t *daddr) { xfs_fsblock_t fsbno; xfs_agblock_t agbno; int error; error = xfs_btree_check_ptr(cur, ptr, 0, 1); if (error) return error; if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { fsbno = be64_to_cpu(ptr->l); *daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno); } else { agbno = be32_to_cpu(ptr->s); *daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno, agbno); } return 0; } /* * Readahead @count btree blocks at the given @ptr location. * * We don't need to care about long or short form btrees here as we have a * method of converting the ptr directly to a daddr available to us. */ STATIC void xfs_btree_readahead_ptr( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, xfs_extlen_t count) { xfs_daddr_t daddr; if (xfs_btree_ptr_to_daddr(cur, ptr, &daddr)) return; xfs_buf_readahead(cur->bc_mp->m_ddev_targp, daddr, cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops); } /* * Set the buffer for level "lev" in the cursor to bp, releasing * any previous buffer. */ STATIC void xfs_btree_setbuf( xfs_btree_cur_t *cur, /* btree cursor */ int lev, /* level in btree */ xfs_buf_t *bp) /* new buffer to set */ { struct xfs_btree_block *b; /* btree block */ if (cur->bc_bufs[lev]) xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[lev]); cur->bc_bufs[lev] = bp; cur->bc_ra[lev] = 0; b = XFS_BUF_TO_BLOCK(bp); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (b->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; if (b->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; } else { if (b->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; if (b->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; } } bool xfs_btree_ptr_is_null( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return ptr->l == cpu_to_be64(NULLFSBLOCK); else return ptr->s == cpu_to_be32(NULLAGBLOCK); } STATIC void xfs_btree_set_ptr_null( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) ptr->l = cpu_to_be64(NULLFSBLOCK); else ptr->s = cpu_to_be32(NULLAGBLOCK); } /* * Get/set/init sibling pointers */ void xfs_btree_get_sibling( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_ptr *ptr, int lr) { ASSERT(lr == XFS_BB_LEFTSIB || lr == XFS_BB_RIGHTSIB); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (lr == XFS_BB_RIGHTSIB) ptr->l = block->bb_u.l.bb_rightsib; else ptr->l = block->bb_u.l.bb_leftsib; } else { if (lr == XFS_BB_RIGHTSIB) ptr->s = block->bb_u.s.bb_rightsib; else ptr->s = block->bb_u.s.bb_leftsib; } } STATIC void xfs_btree_set_sibling( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_ptr *ptr, int lr) { ASSERT(lr == XFS_BB_LEFTSIB || lr == XFS_BB_RIGHTSIB); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (lr == XFS_BB_RIGHTSIB) block->bb_u.l.bb_rightsib = ptr->l; else block->bb_u.l.bb_leftsib = ptr->l; } else { if (lr == XFS_BB_RIGHTSIB) block->bb_u.s.bb_rightsib = ptr->s; else block->bb_u.s.bb_leftsib = ptr->s; } } void xfs_btree_init_block_int( struct xfs_mount *mp, struct xfs_btree_block *buf, xfs_daddr_t blkno, xfs_btnum_t btnum, __u16 level, __u16 numrecs, __u64 owner, unsigned int flags) { int crc = xfs_sb_version_hascrc(&mp->m_sb); __u32 magic = xfs_btree_magic(crc, btnum); buf->bb_magic = cpu_to_be32(magic); buf->bb_level = cpu_to_be16(level); buf->bb_numrecs = cpu_to_be16(numrecs); if (flags & XFS_BTREE_LONG_PTRS) { buf->bb_u.l.bb_leftsib = cpu_to_be64(NULLFSBLOCK); buf->bb_u.l.bb_rightsib = cpu_to_be64(NULLFSBLOCK); if (crc) { buf->bb_u.l.bb_blkno = cpu_to_be64(blkno); buf->bb_u.l.bb_owner = cpu_to_be64(owner); uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid); buf->bb_u.l.bb_pad = 0; buf->bb_u.l.bb_lsn = 0; } } else { /* owner is a 32 bit value on short blocks */ __u32 __owner = (__u32)owner; buf->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); buf->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); if (crc) { buf->bb_u.s.bb_blkno = cpu_to_be64(blkno); buf->bb_u.s.bb_owner = cpu_to_be32(__owner); uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid); buf->bb_u.s.bb_lsn = 0; } } } void xfs_btree_init_block( struct xfs_mount *mp, struct xfs_buf *bp, xfs_btnum_t btnum, __u16 level, __u16 numrecs, __u64 owner) { xfs_btree_init_block_int(mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, btnum, level, numrecs, owner, 0); } STATIC void xfs_btree_init_block_cur( struct xfs_btree_cur *cur, struct xfs_buf *bp, int level, int numrecs) { __u64 owner; /* * we can pull the owner from the cursor right now as the different * owners align directly with the pointer size of the btree. This may * change in future, but is safe for current users of the generic btree * code. */ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) owner = cur->bc_private.b.ip->i_ino; else owner = cur->bc_private.a.agno; xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, cur->bc_btnum, level, numrecs, owner, cur->bc_flags); } /* * Return true if ptr is the last record in the btree and * we need to track updates to this record. The decision * will be further refined in the update_lastrec method. */ STATIC int xfs_btree_is_lastrec( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level) { union xfs_btree_ptr ptr; if (level > 0) return 0; if (!(cur->bc_flags & XFS_BTREE_LASTREC_UPDATE)) return 0; xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &ptr)) return 0; return 1; } STATIC void xfs_btree_buf_to_ptr( struct xfs_btree_cur *cur, struct xfs_buf *bp, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) ptr->l = cpu_to_be64(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp))); else { ptr->s = cpu_to_be32(xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp))); } } STATIC void xfs_btree_set_refs( struct xfs_btree_cur *cur, struct xfs_buf *bp) { switch (cur->bc_btnum) { case XFS_BTNUM_BNO: case XFS_BTNUM_CNT: xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF); break; case XFS_BTNUM_INO: case XFS_BTNUM_FINO: xfs_buf_set_ref(bp, XFS_INO_BTREE_REF); break; case XFS_BTNUM_BMAP: xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF); break; case XFS_BTNUM_RMAP: xfs_buf_set_ref(bp, XFS_RMAP_BTREE_REF); break; case XFS_BTNUM_REFC: xfs_buf_set_ref(bp, XFS_REFC_BTREE_REF); break; default: ASSERT(0); } } STATIC int xfs_btree_get_buf_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, struct xfs_btree_block **block, struct xfs_buf **bpp) { struct xfs_mount *mp = cur->bc_mp; xfs_daddr_t d; int error; error = xfs_btree_ptr_to_daddr(cur, ptr, &d); if (error) return error; *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, mp->m_bsize, 0); if (!*bpp) return -ENOMEM; (*bpp)->b_ops = cur->bc_ops->buf_ops; *block = XFS_BUF_TO_BLOCK(*bpp); return 0; } /* * Read in the buffer at the given ptr and return the buffer and * the block pointer within the buffer. */ STATIC int xfs_btree_read_buf_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int flags, struct xfs_btree_block **block, struct xfs_buf **bpp) { struct xfs_mount *mp = cur->bc_mp; xfs_daddr_t d; int error; /* need to sort out how callers deal with failures first */ ASSERT(!(flags & XBF_TRYLOCK)); error = xfs_btree_ptr_to_daddr(cur, ptr, &d); if (error) return error; error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, mp->m_bsize, flags, bpp, cur->bc_ops->buf_ops); if (error) return error; xfs_btree_set_refs(cur, *bpp); *block = XFS_BUF_TO_BLOCK(*bpp); return 0; } /* * Copy keys from one btree block to another. */ STATIC void xfs_btree_copy_keys( struct xfs_btree_cur *cur, union xfs_btree_key *dst_key, union xfs_btree_key *src_key, int numkeys) { ASSERT(numkeys >= 0); memcpy(dst_key, src_key, numkeys * cur->bc_ops->key_len); } /* * Copy records from one btree block to another. */ STATIC void xfs_btree_copy_recs( struct xfs_btree_cur *cur, union xfs_btree_rec *dst_rec, union xfs_btree_rec *src_rec, int numrecs) { ASSERT(numrecs >= 0); memcpy(dst_rec, src_rec, numrecs * cur->bc_ops->rec_len); } /* * Copy block pointers from one btree block to another. */ STATIC void xfs_btree_copy_ptrs( struct xfs_btree_cur *cur, union xfs_btree_ptr *dst_ptr, union xfs_btree_ptr *src_ptr, int numptrs) { ASSERT(numptrs >= 0); memcpy(dst_ptr, src_ptr, numptrs * xfs_btree_ptr_len(cur)); } /* * Shift keys one index left/right inside a single btree block. */ STATIC void xfs_btree_shift_keys( struct xfs_btree_cur *cur, union xfs_btree_key *key, int dir, int numkeys) { char *dst_key; ASSERT(numkeys >= 0); ASSERT(dir == 1 || dir == -1); dst_key = (char *)key + (dir * cur->bc_ops->key_len); memmove(dst_key, key, numkeys * cur->bc_ops->key_len); } /* * Shift records one index left/right inside a single btree block. */ STATIC void xfs_btree_shift_recs( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, int dir, int numrecs) { char *dst_rec; ASSERT(numrecs >= 0); ASSERT(dir == 1 || dir == -1); dst_rec = (char *)rec + (dir * cur->bc_ops->rec_len); memmove(dst_rec, rec, numrecs * cur->bc_ops->rec_len); } /* * Shift block pointers one index left/right inside a single btree block. */ STATIC void xfs_btree_shift_ptrs( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int dir, int numptrs) { char *dst_ptr; ASSERT(numptrs >= 0); ASSERT(dir == 1 || dir == -1); dst_ptr = (char *)ptr + (dir * xfs_btree_ptr_len(cur)); memmove(dst_ptr, ptr, numptrs * xfs_btree_ptr_len(cur)); } /* * Log key values from the btree block. */ STATIC void xfs_btree_log_keys( struct xfs_btree_cur *cur, struct xfs_buf *bp, int first, int last) { if (bp) { xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_key_offset(cur, first), xfs_btree_key_offset(cur, last + 1) - 1); } else { xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, xfs_ilog_fbroot(cur->bc_private.b.whichfork)); } } /* * Log record values from the btree block. */ void xfs_btree_log_recs( struct xfs_btree_cur *cur, struct xfs_buf *bp, int first, int last) { xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_rec_offset(cur, first), xfs_btree_rec_offset(cur, last + 1) - 1); } /* * Log block pointer fields from a btree block (nonleaf). */ STATIC void xfs_btree_log_ptrs( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_buf *bp, /* buffer containing btree block */ int first, /* index of first pointer to log */ int last) /* index of last pointer to log */ { if (bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); int level = xfs_btree_get_level(block); xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_ptr_offset(cur, first, level), xfs_btree_ptr_offset(cur, last + 1, level) - 1); } else { xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, xfs_ilog_fbroot(cur->bc_private.b.whichfork)); } } /* * Log fields from a btree block header. */ void xfs_btree_log_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_buf *bp, /* buffer containing btree block */ int fields) /* mask of fields: XFS_BB_... */ { int first; /* first byte offset logged */ int last; /* last byte offset logged */ static const short soffsets[] = { /* table of offsets (short) */ offsetof(struct xfs_btree_block, bb_magic), offsetof(struct xfs_btree_block, bb_level), offsetof(struct xfs_btree_block, bb_numrecs), offsetof(struct xfs_btree_block, bb_u.s.bb_leftsib), offsetof(struct xfs_btree_block, bb_u.s.bb_rightsib), offsetof(struct xfs_btree_block, bb_u.s.bb_blkno), offsetof(struct xfs_btree_block, bb_u.s.bb_lsn), offsetof(struct xfs_btree_block, bb_u.s.bb_uuid), offsetof(struct xfs_btree_block, bb_u.s.bb_owner), offsetof(struct xfs_btree_block, bb_u.s.bb_crc), XFS_BTREE_SBLOCK_CRC_LEN }; static const short loffsets[] = { /* table of offsets (long) */ offsetof(struct xfs_btree_block, bb_magic), offsetof(struct xfs_btree_block, bb_level), offsetof(struct xfs_btree_block, bb_numrecs), offsetof(struct xfs_btree_block, bb_u.l.bb_leftsib), offsetof(struct xfs_btree_block, bb_u.l.bb_rightsib), offsetof(struct xfs_btree_block, bb_u.l.bb_blkno), offsetof(struct xfs_btree_block, bb_u.l.bb_lsn), offsetof(struct xfs_btree_block, bb_u.l.bb_uuid), offsetof(struct xfs_btree_block, bb_u.l.bb_owner), offsetof(struct xfs_btree_block, bb_u.l.bb_crc), offsetof(struct xfs_btree_block, bb_u.l.bb_pad), XFS_BTREE_LBLOCK_CRC_LEN }; if (bp) { int nbits; if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) { /* * We don't log the CRC when updating a btree * block but instead recreate it during log * recovery. As the log buffers have checksums * of their own this is safe and avoids logging a crc * update in a lot of places. */ if (fields == XFS_BB_ALL_BITS) fields = XFS_BB_ALL_BITS_CRC; nbits = XFS_BB_NUM_BITS_CRC; } else { nbits = XFS_BB_NUM_BITS; } xfs_btree_offsets(fields, (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? loffsets : soffsets, nbits, &first, &last); xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, first, last); } else { xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, xfs_ilog_fbroot(cur->bc_private.b.whichfork)); } } /* * Increment cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ int /* error */ xfs_btree_increment( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { struct xfs_btree_block *block; union xfs_btree_ptr ptr; struct xfs_buf *bp; int error; /* error return value */ int lev; ASSERT(level < cur->bc_nlevels); /* Read-ahead to the right at this level. */ xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); /* Get a pointer to the btree block. */ block = xfs_btree_get_block(cur, level, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; #endif /* We're done if we remain in the block after the increment. */ if (++cur->bc_ptrs[level] <= xfs_btree_get_numrecs(block)) goto out1; /* Fail if we just went off the right edge of the tree. */ xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &ptr)) goto out0; XFS_BTREE_STATS_INC(cur, increment); /* * March up the tree incrementing pointers. * Stop when we don't go off the right edge of a block. */ for (lev = level + 1; lev < cur->bc_nlevels; lev++) { block = xfs_btree_get_block(cur, lev, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, lev, bp); if (error) goto error0; #endif if (++cur->bc_ptrs[lev] <= xfs_btree_get_numrecs(block)) break; /* Read-ahead the right block for the next loop. */ xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); } /* * If we went off the root then we are either seriously * confused or have the tree root in an inode. */ if (lev == cur->bc_nlevels) { if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) goto out0; ASSERT(0); error = -EFSCORRUPTED; goto error0; } ASSERT(lev < cur->bc_nlevels); /* * Now walk back down the tree, fixing up the cursor's buffer * pointers and key numbers. */ for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { union xfs_btree_ptr *ptrp; ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); --lev; error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); if (error) goto error0; xfs_btree_setbuf(cur, lev, bp); cur->bc_ptrs[lev] = 1; } out1: *stat = 1; return 0; out0: *stat = 0; return 0; error0: return error; } /* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ int /* error */ xfs_btree_decrement( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { struct xfs_btree_block *block; xfs_buf_t *bp; int error; /* error return value */ int lev; union xfs_btree_ptr ptr; ASSERT(level < cur->bc_nlevels); /* Read-ahead to the left at this level. */ xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); /* We're done if we remain in the block after the decrement. */ if (--cur->bc_ptrs[level] > 0) goto out1; /* Get a pointer to the btree block. */ block = xfs_btree_get_block(cur, level, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; #endif /* Fail if we just went off the left edge of the tree. */ xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); if (xfs_btree_ptr_is_null(cur, &ptr)) goto out0; XFS_BTREE_STATS_INC(cur, decrement); /* * March up the tree decrementing pointers. * Stop when we don't go off the left edge of a block. */ for (lev = level + 1; lev < cur->bc_nlevels; lev++) { if (--cur->bc_ptrs[lev] > 0) break; /* Read-ahead the left block for the next loop. */ xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); } /* * If we went off the root then we are seriously confused. * or the root of the tree is in an inode. */ if (lev == cur->bc_nlevels) { if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) goto out0; ASSERT(0); error = -EFSCORRUPTED; goto error0; } ASSERT(lev < cur->bc_nlevels); /* * Now walk back down the tree, fixing up the cursor's buffer * pointers and key numbers. */ for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { union xfs_btree_ptr *ptrp; ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); --lev; error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); if (error) goto error0; xfs_btree_setbuf(cur, lev, bp); cur->bc_ptrs[lev] = xfs_btree_get_numrecs(block); } out1: *stat = 1; return 0; out0: *stat = 0; return 0; error0: return error; } int xfs_btree_lookup_get_block( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level in the btree */ union xfs_btree_ptr *pp, /* ptr to btree block */ struct xfs_btree_block **blkp) /* return btree block */ { struct xfs_buf *bp; /* buffer pointer for btree block */ xfs_daddr_t daddr; int error = 0; /* special case the root block if in an inode */ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level == cur->bc_nlevels - 1)) { *blkp = xfs_btree_get_iroot(cur); return 0; } /* * If the old buffer at this level for the disk address we are * looking for re-use it. * * Otherwise throw it away and get a new one. */ bp = cur->bc_bufs[level]; error = xfs_btree_ptr_to_daddr(cur, pp, &daddr); if (error) return error; if (bp && XFS_BUF_ADDR(bp) == daddr) { *blkp = XFS_BUF_TO_BLOCK(bp); return 0; } error = xfs_btree_read_buf_block(cur, pp, 0, blkp, &bp); if (error) return error; /* Check the inode owner since the verifiers don't. */ if (xfs_sb_version_hascrc(&cur->bc_mp->m_sb) && !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_INVALID_OWNER) && (cur->bc_flags & XFS_BTREE_LONG_PTRS) && be64_to_cpu((*blkp)->bb_u.l.bb_owner) != cur->bc_private.b.ip->i_ino) goto out_bad; /* Did we get the level we were looking for? */ if (be16_to_cpu((*blkp)->bb_level) != level) goto out_bad; /* Check that internal nodes have at least one record. */ if (level != 0 && be16_to_cpu((*blkp)->bb_numrecs) == 0) goto out_bad; xfs_btree_setbuf(cur, level, bp); return 0; out_bad: *blkp = NULL; xfs_trans_brelse(cur->bc_tp, bp); return -EFSCORRUPTED; } /* * Get current search key. For level 0 we don't actually have a key * structure so we make one up from the record. For all other levels * we just return the right key. */ STATIC union xfs_btree_key * xfs_lookup_get_search_key( struct xfs_btree_cur *cur, int level, int keyno, struct xfs_btree_block *block, union xfs_btree_key *kp) { if (level == 0) { cur->bc_ops->init_key_from_rec(kp, xfs_btree_rec_addr(cur, keyno, block)); return kp; } return xfs_btree_key_addr(cur, keyno, block); } /* * Lookup the record. The cursor is made to point to it, based on dir. * stat is set to 0 if can't find any such record, 1 for success. */ int /* error */ xfs_btree_lookup( struct xfs_btree_cur *cur, /* btree cursor */ xfs_lookup_t dir, /* <=, ==, or >= */ int *stat) /* success/failure */ { struct xfs_btree_block *block; /* current btree block */ int64_t diff; /* difference for the current key */ int error; /* error return value */ int keyno; /* current key number */ int level; /* level in the btree */ union xfs_btree_ptr *pp; /* ptr to btree block */ union xfs_btree_ptr ptr; /* ptr to btree block */ XFS_BTREE_STATS_INC(cur, lookup); /* No such thing as a zero-level tree. */ if (cur->bc_nlevels == 0) return -EFSCORRUPTED; block = NULL; keyno = 0; /* initialise start pointer from cursor */ cur->bc_ops->init_ptr_from_cur(cur, &ptr); pp = &ptr; /* * Iterate over each level in the btree, starting at the root. * For each level above the leaves, find the key we need, based * on the lookup record, then follow the corresponding block * pointer down to the next level. */ for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { /* Get the block we need to do the lookup on. */ error = xfs_btree_lookup_get_block(cur, level, pp, &block); if (error) goto error0; if (diff == 0) { /* * If we already had a key match at a higher level, we * know we need to use the first entry in this block. */ keyno = 1; } else { /* Otherwise search this block. Do a binary search. */ int high; /* high entry number */ int low; /* low entry number */ /* Set low and high entry numbers, 1-based. */ low = 1; high = xfs_btree_get_numrecs(block); if (!high) { /* Block is empty, must be an empty leaf. */ if (level != 0 || cur->bc_nlevels != 1) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, cur->bc_mp, block, sizeof(*block)); return -EFSCORRUPTED; } cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; *stat = 0; return 0; } /* Binary search the block. */ while (low <= high) { union xfs_btree_key key; union xfs_btree_key *kp; XFS_BTREE_STATS_INC(cur, compare); /* keyno is average of low and high. */ keyno = (low + high) >> 1; /* Get current search key */ kp = xfs_lookup_get_search_key(cur, level, keyno, block, &key); /* * Compute difference to get next direction: * - less than, move right * - greater than, move left * - equal, we're done */ diff = cur->bc_ops->key_diff(cur, kp); if (diff < 0) low = keyno + 1; else if (diff > 0) high = keyno - 1; else break; } } /* * If there are more levels, set up for the next level * by getting the block number and filling in the cursor. */ if (level > 0) { /* * If we moved left, need the previous key number, * unless there isn't one. */ if (diff > 0 && --keyno < 1) keyno = 1; pp = xfs_btree_ptr_addr(cur, keyno, block); error = xfs_btree_debug_check_ptr(cur, pp, 0, level); if (error) goto error0; cur->bc_ptrs[level] = keyno; } } /* Done with the search. See if we need to adjust the results. */ if (dir != XFS_LOOKUP_LE && diff < 0) { keyno++; /* * If ge search and we went off the end of the block, but it's * not the last block, we're in the wrong block. */ xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (dir == XFS_LOOKUP_GE && keyno > xfs_btree_get_numrecs(block) && !xfs_btree_ptr_is_null(cur, &ptr)) { int i; cur->bc_ptrs[0] = keyno; error = xfs_btree_increment(cur, 0, &i); if (error) goto error0; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); *stat = 1; return 0; } } else if (dir == XFS_LOOKUP_LE && diff > 0) keyno--; cur->bc_ptrs[0] = keyno; /* Return if we succeeded or not. */ if (keyno == 0 || keyno > xfs_btree_get_numrecs(block)) *stat = 0; else if (dir != XFS_LOOKUP_EQ || diff == 0) *stat = 1; else *stat = 0; return 0; error0: return error; } /* Find the high key storage area from a regular key. */ union xfs_btree_key * xfs_btree_high_key_from_key( struct xfs_btree_cur *cur, union xfs_btree_key *key) { ASSERT(cur->bc_flags & XFS_BTREE_OVERLAPPING); return (union xfs_btree_key *)((char *)key + (cur->bc_ops->key_len / 2)); } /* Determine the low (and high if overlapped) keys of a leaf block */ STATIC void xfs_btree_get_leaf_keys( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_key *key) { union xfs_btree_key max_hkey; union xfs_btree_key hkey; union xfs_btree_rec *rec; union xfs_btree_key *high; int n; rec = xfs_btree_rec_addr(cur, 1, block); cur->bc_ops->init_key_from_rec(key, rec); if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { cur->bc_ops->init_high_key_from_rec(&max_hkey, rec); for (n = 2; n <= xfs_btree_get_numrecs(block); n++) { rec = xfs_btree_rec_addr(cur, n, block); cur->bc_ops->init_high_key_from_rec(&hkey, rec); if (cur->bc_ops->diff_two_keys(cur, &hkey, &max_hkey) > 0) max_hkey = hkey; } high = xfs_btree_high_key_from_key(cur, key); memcpy(high, &max_hkey, cur->bc_ops->key_len / 2); } } /* Determine the low (and high if overlapped) keys of a node block */ STATIC void xfs_btree_get_node_keys( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_key *key) { union xfs_btree_key *hkey; union xfs_btree_key *max_hkey; union xfs_btree_key *high; int n; if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { memcpy(key, xfs_btree_key_addr(cur, 1, block), cur->bc_ops->key_len / 2); max_hkey = xfs_btree_high_key_addr(cur, 1, block); for (n = 2; n <= xfs_btree_get_numrecs(block); n++) { hkey = xfs_btree_high_key_addr(cur, n, block); if (cur->bc_ops->diff_two_keys(cur, hkey, max_hkey) > 0) max_hkey = hkey; } high = xfs_btree_high_key_from_key(cur, key); memcpy(high, max_hkey, cur->bc_ops->key_len / 2); } else { memcpy(key, xfs_btree_key_addr(cur, 1, block), cur->bc_ops->key_len); } } /* Derive the keys for any btree block. */ void xfs_btree_get_keys( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_key *key) { if (be16_to_cpu(block->bb_level) == 0) xfs_btree_get_leaf_keys(cur, block, key); else xfs_btree_get_node_keys(cur, block, key); } /* * Decide if we need to update the parent keys of a btree block. For * a standard btree this is only necessary if we're updating the first * record/key. For an overlapping btree, we must always update the * keys because the highest key can be in any of the records or keys * in the block. */ static inline bool xfs_btree_needs_key_update( struct xfs_btree_cur *cur, int ptr) { return (cur->bc_flags & XFS_BTREE_OVERLAPPING) || ptr == 1; } /* * Update the low and high parent keys of the given level, progressing * towards the root. If force_all is false, stop if the keys for a given * level do not need updating. */ STATIC int __xfs_btree_updkeys( struct xfs_btree_cur *cur, int level, struct xfs_btree_block *block, struct xfs_buf *bp0, bool force_all) { union xfs_btree_key key; /* keys from current level */ union xfs_btree_key *lkey; /* keys from the next level up */ union xfs_btree_key *hkey; union xfs_btree_key *nlkey; /* keys from the next level up */ union xfs_btree_key *nhkey; struct xfs_buf *bp; int ptr; ASSERT(cur->bc_flags & XFS_BTREE_OVERLAPPING); /* Exit if there aren't any parent levels to update. */ if (level + 1 >= cur->bc_nlevels) return 0; trace_xfs_btree_updkeys(cur, level, bp0); lkey = &key; hkey = xfs_btree_high_key_from_key(cur, lkey); xfs_btree_get_keys(cur, block, lkey); for (level++; level < cur->bc_nlevels; level++) { #ifdef DEBUG int error; #endif block = xfs_btree_get_block(cur, level, &bp); trace_xfs_btree_updkeys(cur, level, bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) return error; #endif ptr = cur->bc_ptrs[level]; nlkey = xfs_btree_key_addr(cur, ptr, block); nhkey = xfs_btree_high_key_addr(cur, ptr, block); if (!force_all && !(cur->bc_ops->diff_two_keys(cur, nlkey, lkey) != 0 || cur->bc_ops->diff_two_keys(cur, nhkey, hkey) != 0)) break; xfs_btree_copy_keys(cur, nlkey, lkey, 1); xfs_btree_log_keys(cur, bp, ptr, ptr); if (level + 1 >= cur->bc_nlevels) break; xfs_btree_get_node_keys(cur, block, lkey); } return 0; } /* Update all the keys from some level in cursor back to the root. */ STATIC int xfs_btree_updkeys_force( struct xfs_btree_cur *cur, int level) { struct xfs_buf *bp; struct xfs_btree_block *block; block = xfs_btree_get_block(cur, level, &bp); return __xfs_btree_updkeys(cur, level, block, bp, true); } /* * Update the parent keys of the given level, progressing towards the root. */ STATIC int xfs_btree_update_keys( struct xfs_btree_cur *cur, int level) { struct xfs_btree_block *block; struct xfs_buf *bp; union xfs_btree_key *kp; union xfs_btree_key key; int ptr; ASSERT(level >= 0); block = xfs_btree_get_block(cur, level, &bp); if (cur->bc_flags & XFS_BTREE_OVERLAPPING) return __xfs_btree_updkeys(cur, level, block, bp, false); /* * Go up the tree from this level toward the root. * At each level, update the key value to the value input. * Stop when we reach a level where the cursor isn't pointing * at the first entry in the block. */ xfs_btree_get_keys(cur, block, &key); for (level++, ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { #ifdef DEBUG int error; #endif block = xfs_btree_get_block(cur, level, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) return error; #endif ptr = cur->bc_ptrs[level]; kp = xfs_btree_key_addr(cur, ptr, block); xfs_btree_copy_keys(cur, kp, &key, 1); xfs_btree_log_keys(cur, bp, ptr, ptr); } return 0; } /* * Update the record referred to by cur to the value in the * given record. This either works (return 0) or gets an * EFSCORRUPTED error. */ int xfs_btree_update( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { struct xfs_btree_block *block; struct xfs_buf *bp; int error; int ptr; union xfs_btree_rec *rp; /* Pick up the current block. */ block = xfs_btree_get_block(cur, 0, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, 0, bp); if (error) goto error0; #endif /* Get the address of the rec to be updated. */ ptr = cur->bc_ptrs[0]; rp = xfs_btree_rec_addr(cur, ptr, block); /* Fill in the new contents and log them. */ xfs_btree_copy_recs(cur, rp, rec, 1); xfs_btree_log_recs(cur, bp, ptr, ptr); /* * If we are tracking the last record in the tree and * we are at the far right edge of the tree, update it. */ if (xfs_btree_is_lastrec(cur, block, 0)) { cur->bc_ops->update_lastrec(cur, block, rec, ptr, LASTREC_UPDATE); } /* Pass new key value up to our parent. */ if (xfs_btree_needs_key_update(cur, ptr)) { error = xfs_btree_update_keys(cur, 0); if (error) goto error0; } return 0; error0: return error; } /* * Move 1 record left from cur/level if possible. * Update cur to reflect the new path. */ STATIC int /* error */ xfs_btree_lshift( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ int lrecs; /* left record count */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ struct xfs_btree_cur *tcur; /* temporary btree cursor */ int rrecs; /* right record count */ union xfs_btree_ptr lptr; /* left btree pointer */ union xfs_btree_key *rkp = NULL; /* right btree key */ union xfs_btree_ptr *rpp = NULL; /* right address pointer */ union xfs_btree_rec *rrp = NULL; /* right record pointer */ int error; /* error return value */ int i; if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && level == cur->bc_nlevels - 1) goto out0; /* Set up variables for this block as "right". */ right = xfs_btree_get_block(cur, level, &rbp); #ifdef DEBUG error = xfs_btree_check_block(cur, right, level, rbp); if (error) goto error0; #endif /* If we've got no left sibling then we can't shift an entry left. */ xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); if (xfs_btree_ptr_is_null(cur, &lptr)) goto out0; /* * If the cursor entry is the one that would be moved, don't * do it... it's too complicated. */ if (cur->bc_ptrs[level] <= 1) goto out0; /* Set up the left neighbor as "left". */ error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; /* If it's full, it can't take another entry. */ lrecs = xfs_btree_get_numrecs(left); if (lrecs == cur->bc_ops->get_maxrecs(cur, level)) goto out0; rrecs = xfs_btree_get_numrecs(right); /* * We add one entry to the left side and remove one for the right side. * Account for it here, the changes will be updated on disk and logged * later. */ lrecs++; rrecs--; XFS_BTREE_STATS_INC(cur, lshift); XFS_BTREE_STATS_ADD(cur, moves, 1); /* * If non-leaf, copy a key and a ptr to the left block. * Log the changes to the left block. */ if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ lkp = xfs_btree_key_addr(cur, lrecs, left); rkp = xfs_btree_key_addr(cur, 1, right); lpp = xfs_btree_ptr_addr(cur, lrecs, left); rpp = xfs_btree_ptr_addr(cur, 1, right); error = xfs_btree_debug_check_ptr(cur, rpp, 0, level); if (error) goto error0; xfs_btree_copy_keys(cur, lkp, rkp, 1); xfs_btree_copy_ptrs(cur, lpp, rpp, 1); xfs_btree_log_keys(cur, lbp, lrecs, lrecs); xfs_btree_log_ptrs(cur, lbp, lrecs, lrecs); ASSERT(cur->bc_ops->keys_inorder(cur, xfs_btree_key_addr(cur, lrecs - 1, left), lkp)); } else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ lrp = xfs_btree_rec_addr(cur, lrecs, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_copy_recs(cur, lrp, rrp, 1); xfs_btree_log_recs(cur, lbp, lrecs, lrecs); ASSERT(cur->bc_ops->recs_inorder(cur, xfs_btree_rec_addr(cur, lrecs - 1, left), lrp)); } xfs_btree_set_numrecs(left, lrecs); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); xfs_btree_set_numrecs(right, rrecs); xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); /* * Slide the contents of right down one entry. */ XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1); if (level > 0) { /* It's a nonleaf. operate on keys and ptrs */ int i; /* loop index */ for (i = 0; i < rrecs; i++) { error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level); if (error) goto error0; } xfs_btree_shift_keys(cur, xfs_btree_key_addr(cur, 2, right), -1, rrecs); xfs_btree_shift_ptrs(cur, xfs_btree_ptr_addr(cur, 2, right), -1, rrecs); xfs_btree_log_keys(cur, rbp, 1, rrecs); xfs_btree_log_ptrs(cur, rbp, 1, rrecs); } else { /* It's a leaf. operate on records */ xfs_btree_shift_recs(cur, xfs_btree_rec_addr(cur, 2, right), -1, rrecs); xfs_btree_log_recs(cur, rbp, 1, rrecs); } /* * Using a temporary cursor, update the parent key values of the * block on the left. */ if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0); error = xfs_btree_decrement(tcur, level, &i); if (error) goto error1; /* Update the parent high keys of the left block, if needed. */ error = xfs_btree_update_keys(tcur, level); if (error) goto error1; xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); } /* Update the parent keys of the right block. */ error = xfs_btree_update_keys(cur, level); if (error) goto error0; /* Slide the cursor value left one. */ cur->bc_ptrs[level]--; *stat = 1; return 0; out0: *stat = 0; return 0; error0: return error; error1: xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); return error; } /* * Move 1 record right from cur/level if possible. * Update cur to reflect the new path. */ STATIC int /* error */ xfs_btree_rshift( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ struct xfs_btree_cur *tcur; /* temporary btree cursor */ union xfs_btree_ptr rptr; /* right block pointer */ union xfs_btree_key *rkp; /* right btree key */ int rrecs; /* right record count */ int lrecs; /* left record count */ int error; /* error return value */ int i; /* loop counter */ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level == cur->bc_nlevels - 1)) goto out0; /* Set up variables for this block as "left". */ left = xfs_btree_get_block(cur, level, &lbp); #ifdef DEBUG error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif /* If we've got no right sibling then we can't shift an entry right. */ xfs_btree_get_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &rptr)) goto out0; /* * If the cursor entry is the one that would be moved, don't * do it... it's too complicated. */ lrecs = xfs_btree_get_numrecs(left); if (cur->bc_ptrs[level] >= lrecs) goto out0; /* Set up the right neighbor as "right". */ error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; /* If it's full, it can't take another entry. */ rrecs = xfs_btree_get_numrecs(right); if (rrecs == cur->bc_ops->get_maxrecs(cur, level)) goto out0; XFS_BTREE_STATS_INC(cur, rshift); XFS_BTREE_STATS_ADD(cur, moves, rrecs); /* * Make a hole at the start of the right neighbor block, then * copy the last left block entry to the hole. */ if (level > 0) { /* It's a nonleaf. make a hole in the keys and ptrs */ union xfs_btree_key *lkp; union xfs_btree_ptr *lpp; union xfs_btree_ptr *rpp; lkp = xfs_btree_key_addr(cur, lrecs, left); lpp = xfs_btree_ptr_addr(cur, lrecs, left); rkp = xfs_btree_key_addr(cur, 1, right); rpp = xfs_btree_ptr_addr(cur, 1, right); for (i = rrecs - 1; i >= 0; i--) { error = xfs_btree_debug_check_ptr(cur, rpp, i, level); if (error) goto error0; } xfs_btree_shift_keys(cur, rkp, 1, rrecs); xfs_btree_shift_ptrs(cur, rpp, 1, rrecs); error = xfs_btree_debug_check_ptr(cur, lpp, 0, level); if (error) goto error0; /* Now put the new data in, and log it. */ xfs_btree_copy_keys(cur, rkp, lkp, 1); xfs_btree_copy_ptrs(cur, rpp, lpp, 1); xfs_btree_log_keys(cur, rbp, 1, rrecs + 1); xfs_btree_log_ptrs(cur, rbp, 1, rrecs + 1); ASSERT(cur->bc_ops->keys_inorder(cur, rkp, xfs_btree_key_addr(cur, 2, right))); } else { /* It's a leaf. make a hole in the records */ union xfs_btree_rec *lrp; union xfs_btree_rec *rrp; lrp = xfs_btree_rec_addr(cur, lrecs, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_shift_recs(cur, rrp, 1, rrecs); /* Now put the new data in, and log it. */ xfs_btree_copy_recs(cur, rrp, lrp, 1); xfs_btree_log_recs(cur, rbp, 1, rrecs + 1); } /* * Decrement and log left's numrecs, bump and log right's numrecs. */ xfs_btree_set_numrecs(left, --lrecs); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); xfs_btree_set_numrecs(right, ++rrecs); xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); /* * Using a temporary cursor, update the parent key values of the * block on the right. */ error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; i = xfs_btree_lastrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0); error = xfs_btree_increment(tcur, level, &i); if (error) goto error1; /* Update the parent high keys of the left block, if needed. */ if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { error = xfs_btree_update_keys(cur, level); if (error) goto error1; } /* Update the parent keys of the right block. */ error = xfs_btree_update_keys(tcur, level); if (error) goto error1; xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); *stat = 1; return 0; out0: *stat = 0; return 0; error0: return error; error1: xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); return error; } /* * Split cur/level block in half. * Return new block number and the key to its first * record (to be inserted into parent). */ STATIC int /* error */ __xfs_btree_split( struct xfs_btree_cur *cur, int level, union xfs_btree_ptr *ptrp, union xfs_btree_key *key, struct xfs_btree_cur **curp, int *stat) /* success/failure */ { union xfs_btree_ptr lptr; /* left sibling block ptr */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ union xfs_btree_ptr rptr; /* right sibling block ptr */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ union xfs_btree_ptr rrptr; /* right-right sibling ptr */ struct xfs_buf *rrbp; /* right-right buffer pointer */ struct xfs_btree_block *rrblock; /* right-right btree block */ int lrecs; int rrecs; int src_index; int error; /* error return value */ int i; XFS_BTREE_STATS_INC(cur, split); /* Set up left block (current one). */ left = xfs_btree_get_block(cur, level, &lbp); #ifdef DEBUG error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif xfs_btree_buf_to_ptr(cur, lbp, &lptr); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, stat); if (error) goto error0; if (*stat == 0) goto out0; XFS_BTREE_STATS_INC(cur, alloc); /* Set up the new block as "right". */ error = xfs_btree_get_buf_block(cur, &rptr, &right, &rbp); if (error) goto error0; /* Fill in the btree header for the new right block. */ xfs_btree_init_block_cur(cur, rbp, xfs_btree_get_level(left), 0); /* * Split the entries between the old and the new block evenly. * Make sure that if there's an odd number of entries now, that * each new block will have the same number of entries. */ lrecs = xfs_btree_get_numrecs(left); rrecs = lrecs / 2; if ((lrecs & 1) && cur->bc_ptrs[level] <= rrecs + 1) rrecs++; src_index = (lrecs - rrecs + 1); XFS_BTREE_STATS_ADD(cur, moves, rrecs); /* Adjust numrecs for the later get_*_keys() calls. */ lrecs -= rrecs; xfs_btree_set_numrecs(left, lrecs); xfs_btree_set_numrecs(right, xfs_btree_get_numrecs(right) + rrecs); /* * Copy btree block entries from the left block over to the * new block, the right. Update the right block and log the * changes. */ if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ union xfs_btree_key *rkp; /* right btree key */ union xfs_btree_ptr *rpp; /* right address pointer */ lkp = xfs_btree_key_addr(cur, src_index, left); lpp = xfs_btree_ptr_addr(cur, src_index, left); rkp = xfs_btree_key_addr(cur, 1, right); rpp = xfs_btree_ptr_addr(cur, 1, right); for (i = src_index; i < rrecs; i++) { error = xfs_btree_debug_check_ptr(cur, lpp, i, level); if (error) goto error0; } /* Copy the keys & pointers to the new block. */ xfs_btree_copy_keys(cur, rkp, lkp, rrecs); xfs_btree_copy_ptrs(cur, rpp, lpp, rrecs); xfs_btree_log_keys(cur, rbp, 1, rrecs); xfs_btree_log_ptrs(cur, rbp, 1, rrecs); /* Stash the keys of the new block for later insertion. */ xfs_btree_get_node_keys(cur, right, key); } else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ union xfs_btree_rec *rrp; /* right record pointer */ lrp = xfs_btree_rec_addr(cur, src_index, left); rrp = xfs_btree_rec_addr(cur, 1, right); /* Copy records to the new block. */ xfs_btree_copy_recs(cur, rrp, lrp, rrecs); xfs_btree_log_recs(cur, rbp, 1, rrecs); /* Stash the keys of the new block for later insertion. */ xfs_btree_get_leaf_keys(cur, right, key); } /* * Find the left block number by looking in the buffer. * Adjust sibling pointers. */ xfs_btree_get_sibling(cur, left, &rrptr, XFS_BB_RIGHTSIB); xfs_btree_set_sibling(cur, right, &rrptr, XFS_BB_RIGHTSIB); xfs_btree_set_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); xfs_btree_set_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); xfs_btree_log_block(cur, rbp, XFS_BB_ALL_BITS); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); /* * If there's a block to the new block's right, make that block * point back to right instead of to left. */ if (!xfs_btree_ptr_is_null(cur, &rrptr)) { error = xfs_btree_read_buf_block(cur, &rrptr, 0, &rrblock, &rrbp); if (error) goto error0; xfs_btree_set_sibling(cur, rrblock, &rptr, XFS_BB_LEFTSIB); xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB); } /* Update the parent high keys of the left block, if needed. */ if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { error = xfs_btree_update_keys(cur, level); if (error) goto error0; } /* * If the cursor is really in the right block, move it there. * If it's just pointing past the last entry in left, then we'll * insert there, so don't change anything in that case. */ if (cur->bc_ptrs[level] > lrecs + 1) { xfs_btree_setbuf(cur, level, rbp); cur->bc_ptrs[level] -= lrecs; } /* * If there are more levels, we'll need another cursor which refers * the right block, no matter where this cursor was. */ if (level + 1 < cur->bc_nlevels) { error = xfs_btree_dup_cursor(cur, curp); if (error) goto error0; (*curp)->bc_ptrs[level + 1]++; } *ptrp = rptr; *stat = 1; return 0; out0: *stat = 0; return 0; error0: return error; } #ifdef __KERNEL__ struct xfs_btree_split_args { struct xfs_btree_cur *cur; int level; union xfs_btree_ptr *ptrp; union xfs_btree_key *key; struct xfs_btree_cur **curp; int *stat; /* success/failure */ int result; bool kswapd; /* allocation in kswapd context */ struct completion *done; struct work_struct work; }; /* * Stack switching interfaces for allocation */ static void xfs_btree_split_worker( struct work_struct *work) { struct xfs_btree_split_args *args = container_of(work, struct xfs_btree_split_args, work); unsigned long pflags; unsigned long new_pflags = PF_MEMALLOC_NOFS; /* * we are in a transaction context here, but may also be doing work * in kswapd context, and hence we may need to inherit that state * temporarily to ensure that we don't block waiting for memory reclaim * in any way. */ if (args->kswapd) new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; current_set_flags_nested(&pflags, new_pflags); args->result = __xfs_btree_split(args->cur, args->level, args->ptrp, args->key, args->curp, args->stat); complete(args->done); current_restore_flags_nested(&pflags, new_pflags); } /* * BMBT split requests often come in with little stack to work on. Push * them off to a worker thread so there is lots of stack to use. For the other * btree types, just call directly to avoid the context switch overhead here. */ STATIC int /* error */ xfs_btree_split( struct xfs_btree_cur *cur, int level, union xfs_btree_ptr *ptrp, union xfs_btree_key *key, struct xfs_btree_cur **curp, int *stat) /* success/failure */ { struct xfs_btree_split_args args; DECLARE_COMPLETION_ONSTACK(done); if (cur->bc_btnum != XFS_BTNUM_BMAP) return __xfs_btree_split(cur, level, ptrp, key, curp, stat); args.cur = cur; args.level = level; args.ptrp = ptrp; args.key = key; args.curp = curp; args.stat = stat; args.done = &done; args.kswapd = current_is_kswapd(); INIT_WORK_ONSTACK(&args.work, xfs_btree_split_worker); queue_work(xfs_alloc_wq, &args.work); wait_for_completion(&done); destroy_work_on_stack(&args.work); return args.result; } #else /* !KERNEL */ #define xfs_btree_split __xfs_btree_split #endif /* * Copy the old inode root contents into a real block and make the * broot point to it. */ int /* error */ xfs_btree_new_iroot( struct xfs_btree_cur *cur, /* btree cursor */ int *logflags, /* logging flags for inode */ int *stat) /* return status - 0 fail */ { struct xfs_buf *cbp; /* buffer for cblock */ struct xfs_btree_block *block; /* btree block */ struct xfs_btree_block *cblock; /* child btree block */ union xfs_btree_key *ckp; /* child key pointer */ union xfs_btree_ptr *cpp; /* child ptr pointer */ union xfs_btree_key *kp; /* pointer to btree key */ union xfs_btree_ptr *pp; /* pointer to block addr */ union xfs_btree_ptr nptr; /* new block addr */ int level; /* btree level */ int error; /* error return code */ int i; /* loop counter */ XFS_BTREE_STATS_INC(cur, newroot); ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); level = cur->bc_nlevels - 1; block = xfs_btree_get_iroot(cur); pp = xfs_btree_ptr_addr(cur, 1, block); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat); if (error) goto error0; if (*stat == 0) return 0; XFS_BTREE_STATS_INC(cur, alloc); /* Copy the root into a real block. */ error = xfs_btree_get_buf_block(cur, &nptr, &cblock, &cbp); if (error) goto error0; /* * we can't just memcpy() the root in for CRC enabled btree blocks. * In that case have to also ensure the blkno remains correct */ memcpy(cblock, block, xfs_btree_block_len(cur)); if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) cblock->bb_u.l.bb_blkno = cpu_to_be64(cbp->b_bn); else cblock->bb_u.s.bb_blkno = cpu_to_be64(cbp->b_bn); } be16_add_cpu(&block->bb_level, 1); xfs_btree_set_numrecs(block, 1); cur->bc_nlevels++; cur->bc_ptrs[level + 1] = 1; kp = xfs_btree_key_addr(cur, 1, block); ckp = xfs_btree_key_addr(cur, 1, cblock); xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock)); cpp = xfs_btree_ptr_addr(cur, 1, cblock); for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) { error = xfs_btree_debug_check_ptr(cur, pp, i, level); if (error) goto error0; } xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock)); error = xfs_btree_debug_check_ptr(cur, &nptr, 0, level); if (error) goto error0; xfs_btree_copy_ptrs(cur, pp, &nptr, 1); xfs_iroot_realloc(cur->bc_private.b.ip, 1 - xfs_btree_get_numrecs(cblock), cur->bc_private.b.whichfork); xfs_btree_setbuf(cur, level, cbp); /* * Do all this logging at the end so that * the root is at the right level. */ xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS); xfs_btree_log_keys(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); xfs_btree_log_ptrs(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); *logflags |= XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork); *stat = 1; return 0; error0: return error; } /* * Allocate a new root block, fill it in. */ STATIC int /* error */ xfs_btree_new_root( struct xfs_btree_cur *cur, /* btree cursor */ int *stat) /* success/failure */ { struct xfs_btree_block *block; /* one half of the old root block */ struct xfs_buf *bp; /* buffer containing block */ int error; /* error return value */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ struct xfs_buf *nbp; /* new (root) buffer */ struct xfs_btree_block *new; /* new (root) btree block */ int nptr; /* new value for key index, 1 or 2 */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ union xfs_btree_ptr rptr; union xfs_btree_ptr lptr; XFS_BTREE_STATS_INC(cur, newroot); /* initialise our start point from the cursor */ cur->bc_ops->init_ptr_from_cur(cur, &rptr); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, stat); if (error) goto error0; if (*stat == 0) goto out0; XFS_BTREE_STATS_INC(cur, alloc); /* Set up the new block. */ error = xfs_btree_get_buf_block(cur, &lptr, &new, &nbp); if (error) goto error0; /* Set the root in the holding structure increasing the level by 1. */ cur->bc_ops->set_root(cur, &lptr, 1); /* * At the previous root level there are now two blocks: the old root, * and the new block generated when it was split. We don't know which * one the cursor is pointing at, so we set up variables "left" and * "right" for each case. */ block = xfs_btree_get_block(cur, cur->bc_nlevels - 1, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, cur->bc_nlevels - 1, bp); if (error) goto error0; #endif xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &rptr)) { /* Our block is left, pick up the right block. */ lbp = bp; xfs_btree_buf_to_ptr(cur, lbp, &lptr); left = block; error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; bp = rbp; nptr = 1; } else { /* Our block is right, pick up the left block. */ rbp = bp; xfs_btree_buf_to_ptr(cur, rbp, &rptr); right = block; xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; bp = lbp; nptr = 2; } /* Fill in the new block's btree header and log it. */ xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2); xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS); ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) && !xfs_btree_ptr_is_null(cur, &rptr)); /* Fill in the key data in the new root. */ if (xfs_btree_get_level(left) > 0) { /* * Get the keys for the left block's keys and put them directly * in the parent block. Do the same for the right block. */ xfs_btree_get_node_keys(cur, left, xfs_btree_key_addr(cur, 1, new)); xfs_btree_get_node_keys(cur, right, xfs_btree_key_addr(cur, 2, new)); } else { /* * Get the keys for the left block's records and put them * directly in the parent block. Do the same for the right * block. */ xfs_btree_get_leaf_keys(cur, left, xfs_btree_key_addr(cur, 1, new)); xfs_btree_get_leaf_keys(cur, right, xfs_btree_key_addr(cur, 2, new)); } xfs_btree_log_keys(cur, nbp, 1, 2); /* Fill in the pointer data in the new root. */ xfs_btree_copy_ptrs(cur, xfs_btree_ptr_addr(cur, 1, new), &lptr, 1); xfs_btree_copy_ptrs(cur, xfs_btree_ptr_addr(cur, 2, new), &rptr, 1); xfs_btree_log_ptrs(cur, nbp, 1, 2); /* Fix up the cursor. */ xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); cur->bc_ptrs[cur->bc_nlevels] = nptr; cur->bc_nlevels++; *stat = 1; return 0; error0: return error; out0: *stat = 0; return 0; } STATIC int xfs_btree_make_block_unfull( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* btree level */ int numrecs,/* # of recs in block */ int *oindex,/* old tree index */ int *index, /* new tree index */ union xfs_btree_ptr *nptr, /* new btree ptr */ struct xfs_btree_cur **ncur, /* new btree cursor */ union xfs_btree_key *key, /* key of new block */ int *stat) { int error = 0; if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && level == cur->bc_nlevels - 1) { struct xfs_inode *ip = cur->bc_private.b.ip; if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { /* A root block that can be made bigger. */ xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork); *stat = 1; } else { /* A root block that needs replacing */ int logflags = 0; error = xfs_btree_new_iroot(cur, &logflags, stat); if (error || *stat == 0) return error; xfs_trans_log_inode(cur->bc_tp, ip, logflags); } return 0; } /* First, try shifting an entry to the right neighbor. */ error = xfs_btree_rshift(cur, level, stat); if (error || *stat) return error; /* Next, try shifting an entry to the left neighbor. */ error = xfs_btree_lshift(cur, level, stat); if (error) return error; if (*stat) { *oindex = *index = cur->bc_ptrs[level]; return 0; } /* * Next, try splitting the current block in half. * * If this works we have to re-set our variables because we * could be in a different block now. */ error = xfs_btree_split(cur, level, nptr, key, ncur, stat); if (error || *stat == 0) return error; *index = cur->bc_ptrs[level]; return 0; } /* * Insert one record/level. Return information to the caller * allowing the next level up to proceed if necessary. */ STATIC int xfs_btree_insrec( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level to insert record at */ union xfs_btree_ptr *ptrp, /* i/o: block number inserted */ union xfs_btree_rec *rec, /* record to insert */ union xfs_btree_key *key, /* i/o: block key for ptrp */ struct xfs_btree_cur **curp, /* output: new cursor replacing cur */ int *stat) /* success/failure */ { struct xfs_btree_block *block; /* btree block */ struct xfs_buf *bp; /* buffer for block */ union xfs_btree_ptr nptr; /* new block ptr */ struct xfs_btree_cur *ncur; /* new btree cursor */ union xfs_btree_key nkey; /* new block key */ union xfs_btree_key *lkey; int optr; /* old key/record index */ int ptr; /* key/record index */ int numrecs;/* number of records */ int error; /* error return value */ int i; xfs_daddr_t old_bn; ncur = NULL; lkey = &nkey; /* * If we have an external root pointer, and we've made it to the * root level, allocate a new root block and we're done. */ if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level >= cur->bc_nlevels)) { error = xfs_btree_new_root(cur, stat); xfs_btree_set_ptr_null(cur, ptrp); return error; } /* If we're off the left edge, return failure. */ ptr = cur->bc_ptrs[level]; if (ptr == 0) { *stat = 0; return 0; } optr = ptr; XFS_BTREE_STATS_INC(cur, insrec); /* Get pointers to the btree buffer and block. */ block = xfs_btree_get_block(cur, level, &bp); old_bn = bp ? bp->b_bn : XFS_BUF_DADDR_NULL; numrecs = xfs_btree_get_numrecs(block); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; /* Check that the new entry is being inserted in the right place. */ if (ptr <= numrecs) { if (level == 0) { ASSERT(cur->bc_ops->recs_inorder(cur, rec, xfs_btree_rec_addr(cur, ptr, block))); } else { ASSERT(cur->bc_ops->keys_inorder(cur, key, xfs_btree_key_addr(cur, ptr, block))); } } #endif /* * If the block is full, we can't insert the new entry until we * make the block un-full. */ xfs_btree_set_ptr_null(cur, &nptr); if (numrecs == cur->bc_ops->get_maxrecs(cur, level)) { error = xfs_btree_make_block_unfull(cur, level, numrecs, &optr, &ptr, &nptr, &ncur, lkey, stat); if (error || *stat == 0) goto error0; } /* * The current block may have changed if the block was * previously full and we have just made space in it. */ block = xfs_btree_get_block(cur, level, &bp); numrecs = xfs_btree_get_numrecs(block); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) return error; #endif /* * At this point we know there's room for our new entry in the block * we're pointing at. */ XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr + 1); if (level > 0) { /* It's a nonleaf. make a hole in the keys and ptrs */ union xfs_btree_key *kp; union xfs_btree_ptr *pp; kp = xfs_btree_key_addr(cur, ptr, block); pp = xfs_btree_ptr_addr(cur, ptr, block); for (i = numrecs - ptr; i >= 0; i--) { error = xfs_btree_debug_check_ptr(cur, pp, i, level); if (error) return error; } xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1); xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1); error = xfs_btree_debug_check_ptr(cur, ptrp, 0, level); if (error) goto error0; /* Now put the new data in, bump numrecs and log it. */ xfs_btree_copy_keys(cur, kp, key, 1); xfs_btree_copy_ptrs(cur, pp, ptrp, 1); numrecs++; xfs_btree_set_numrecs(block, numrecs); xfs_btree_log_ptrs(cur, bp, ptr, numrecs); xfs_btree_log_keys(cur, bp, ptr, numrecs); #ifdef DEBUG if (ptr < numrecs) { ASSERT(cur->bc_ops->keys_inorder(cur, kp, xfs_btree_key_addr(cur, ptr + 1, block))); } #endif } else { /* It's a leaf. make a hole in the records */ union xfs_btree_rec *rp; rp = xfs_btree_rec_addr(cur, ptr, block); xfs_btree_shift_recs(cur, rp, 1, numrecs - ptr + 1); /* Now put the new data in, bump numrecs and log it. */ xfs_btree_copy_recs(cur, rp, rec, 1); xfs_btree_set_numrecs(block, ++numrecs); xfs_btree_log_recs(cur, bp, ptr, numrecs); #ifdef DEBUG if (ptr < numrecs) { ASSERT(cur->bc_ops->recs_inorder(cur, rp, xfs_btree_rec_addr(cur, ptr + 1, block))); } #endif } /* Log the new number of records in the btree header. */ xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); /* * If we just inserted into a new tree block, we have to * recalculate nkey here because nkey is out of date. * * Otherwise we're just updating an existing block (having shoved * some records into the new tree block), so use the regular key * update mechanism. */ if (bp && bp->b_bn != old_bn) { xfs_btree_get_keys(cur, block, lkey); } else if (xfs_btree_needs_key_update(cur, optr)) { error = xfs_btree_update_keys(cur, level); if (error) goto error0; } /* * If we are tracking the last record in the tree and * we are at the far right edge of the tree, update it. */ if (xfs_btree_is_lastrec(cur, block, level)) { cur->bc_ops->update_lastrec(cur, block, rec, ptr, LASTREC_INSREC); } /* * Return the new block number, if any. * If there is one, give back a record value and a cursor too. */ *ptrp = nptr; if (!xfs_btree_ptr_is_null(cur, &nptr)) { xfs_btree_copy_keys(cur, key, lkey, 1); *curp = ncur; } *stat = 1; return 0; error0: return error; } /* * Insert the record at the point referenced by cur. * * A multi-level split of the tree on insert will invalidate the original * cursor. All callers of this function should assume that the cursor is * no longer valid and revalidate it. */ int xfs_btree_insert( struct xfs_btree_cur *cur, int *stat) { int error; /* error return value */ int i; /* result value, 0 for failure */ int level; /* current level number in btree */ union xfs_btree_ptr nptr; /* new block number (split result) */ struct xfs_btree_cur *ncur; /* new cursor (split result) */ struct xfs_btree_cur *pcur; /* previous level's cursor */ union xfs_btree_key bkey; /* key of block to insert */ union xfs_btree_key *key; union xfs_btree_rec rec; /* record to insert */ level = 0; ncur = NULL; pcur = cur; key = &bkey; xfs_btree_set_ptr_null(cur, &nptr); /* Make a key out of the record data to be inserted, and save it. */ cur->bc_ops->init_rec_from_cur(cur, &rec); cur->bc_ops->init_key_from_rec(key, &rec); /* * Loop going up the tree, starting at the leaf level. * Stop when we don't get a split block, that must mean that * the insert is finished with this level. */ do { /* * Insert nrec/nptr into this level of the tree. * Note if we fail, nptr will be null. */ error = xfs_btree_insrec(pcur, level, &nptr, &rec, key, &ncur, &i); if (error) { if (pcur != cur) xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); goto error0; } XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); level++; /* * See if the cursor we just used is trash. * Can't trash the caller's cursor, but otherwise we should * if ncur is a new cursor or we're about to be done. */ if (pcur != cur && (ncur || xfs_btree_ptr_is_null(cur, &nptr))) { /* Save the state from the cursor before we trash it */ if (cur->bc_ops->update_cursor) cur->bc_ops->update_cursor(pcur, cur); cur->bc_nlevels = pcur->bc_nlevels; xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); } /* If we got a new cursor, switch to it. */ if (ncur) { pcur = ncur; ncur = NULL; } } while (!xfs_btree_ptr_is_null(cur, &nptr)); *stat = i; return 0; error0: return error; } /* * Try to merge a non-leaf block back into the inode root. * * Note: the killroot names comes from the fact that we're effectively * killing the old root block. But because we can't just delete the * inode we have to copy the single block it was pointing to into the * inode. */ STATIC int xfs_btree_kill_iroot( struct xfs_btree_cur *cur) { int whichfork = cur->bc_private.b.whichfork; struct xfs_inode *ip = cur->bc_private.b.ip; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_block *block; struct xfs_btree_block *cblock; union xfs_btree_key *kp; union xfs_btree_key *ckp; union xfs_btree_ptr *pp; union xfs_btree_ptr *cpp; struct xfs_buf *cbp; int level; int index; int numrecs; int error; #ifdef DEBUG union xfs_btree_ptr ptr; #endif int i; ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); ASSERT(cur->bc_nlevels > 1); /* * Don't deal with the root block needs to be a leaf case. * We're just going to turn the thing back into extents anyway. */ level = cur->bc_nlevels - 1; if (level == 1) goto out0; /* * Give up if the root has multiple children. */ block = xfs_btree_get_iroot(cur); if (xfs_btree_get_numrecs(block) != 1) goto out0; cblock = xfs_btree_get_block(cur, level - 1, &cbp); numrecs = xfs_btree_get_numrecs(cblock); /* * Only do this if the next level will fit. * Then the data must be copied up to the inode, * instead of freeing the root you free the next level. */ if (numrecs > cur->bc_ops->get_dmaxrecs(cur, level)) goto out0; XFS_BTREE_STATS_INC(cur, killroot); #ifdef DEBUG xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); #endif index = numrecs - cur->bc_ops->get_maxrecs(cur, level); if (index) { xfs_iroot_realloc(cur->bc_private.b.ip, index, cur->bc_private.b.whichfork); block = ifp->if_broot; } be16_add_cpu(&block->bb_numrecs, index); ASSERT(block->bb_numrecs == cblock->bb_numrecs); kp = xfs_btree_key_addr(cur, 1, block); ckp = xfs_btree_key_addr(cur, 1, cblock); xfs_btree_copy_keys(cur, kp, ckp, numrecs); pp = xfs_btree_ptr_addr(cur, 1, block); cpp = xfs_btree_ptr_addr(cur, 1, cblock); for (i = 0; i < numrecs; i++) { error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1); if (error) return error; } xfs_btree_copy_ptrs(cur, pp, cpp, numrecs); error = xfs_btree_free_block(cur, cbp); if (error) return error; cur->bc_bufs[level - 1] = NULL; be16_add_cpu(&block->bb_level, -1); xfs_trans_log_inode(cur->bc_tp, ip, XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork)); cur->bc_nlevels--; out0: return 0; } /* * Kill the current root node, and replace it with it's only child node. */ STATIC int xfs_btree_kill_root( struct xfs_btree_cur *cur, struct xfs_buf *bp, int level, union xfs_btree_ptr *newroot) { int error; XFS_BTREE_STATS_INC(cur, killroot); /* * Update the root pointer, decreasing the level by 1 and then * free the old root. */ cur->bc_ops->set_root(cur, newroot, -1); error = xfs_btree_free_block(cur, bp); if (error) return error; cur->bc_bufs[level] = NULL; cur->bc_ra[level] = 0; cur->bc_nlevels--; return 0; } STATIC int xfs_btree_dec_cursor( struct xfs_btree_cur *cur, int level, int *stat) { int error; int i; if (level > 0) { error = xfs_btree_decrement(cur, level, &i); if (error) return error; } *stat = 1; return 0; } /* * Single level of the btree record deletion routine. * Delete record pointed to by cur/level. * Remove the record from its block then rebalance the tree. * Return 0 for error, 1 for done, 2 to go on to the next level. */ STATIC int /* error */ xfs_btree_delrec( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level removing record from */ int *stat) /* fail/done/go-on */ { struct xfs_btree_block *block; /* btree block */ union xfs_btree_ptr cptr; /* current block ptr */ struct xfs_buf *bp; /* buffer for block */ int error; /* error return value */ int i; /* loop counter */ union xfs_btree_ptr lptr; /* left sibling block ptr */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ int lrecs = 0; /* left record count */ int ptr; /* key/record index */ union xfs_btree_ptr rptr; /* right sibling block ptr */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ struct xfs_btree_block *rrblock; /* right-right btree block */ struct xfs_buf *rrbp; /* right-right buffer pointer */ int rrecs = 0; /* right record count */ struct xfs_btree_cur *tcur; /* temporary btree cursor */ int numrecs; /* temporary numrec count */ tcur = NULL; /* Get the index of the entry being deleted, check for nothing there. */ ptr = cur->bc_ptrs[level]; if (ptr == 0) { *stat = 0; return 0; } /* Get the buffer & block containing the record or key/ptr. */ block = xfs_btree_get_block(cur, level, &bp); numrecs = xfs_btree_get_numrecs(block); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; #endif /* Fail if we're off the end of the block. */ if (ptr > numrecs) { *stat = 0; return 0; } XFS_BTREE_STATS_INC(cur, delrec); XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr); /* Excise the entries being deleted. */ if (level > 0) { /* It's a nonleaf. operate on keys and ptrs */ union xfs_btree_key *lkp; union xfs_btree_ptr *lpp; lkp = xfs_btree_key_addr(cur, ptr + 1, block); lpp = xfs_btree_ptr_addr(cur, ptr + 1, block); for (i = 0; i < numrecs - ptr; i++) { error = xfs_btree_debug_check_ptr(cur, lpp, i, level); if (error) goto error0; } if (ptr < numrecs) { xfs_btree_shift_keys(cur, lkp, -1, numrecs - ptr); xfs_btree_shift_ptrs(cur, lpp, -1, numrecs - ptr); xfs_btree_log_keys(cur, bp, ptr, numrecs - 1); xfs_btree_log_ptrs(cur, bp, ptr, numrecs - 1); } } else { /* It's a leaf. operate on records */ if (ptr < numrecs) { xfs_btree_shift_recs(cur, xfs_btree_rec_addr(cur, ptr + 1, block), -1, numrecs - ptr); xfs_btree_log_recs(cur, bp, ptr, numrecs - 1); } } /* * Decrement and log the number of entries in the block. */ xfs_btree_set_numrecs(block, --numrecs); xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); /* * If we are tracking the last record in the tree and * we are at the far right edge of the tree, update it. */ if (xfs_btree_is_lastrec(cur, block, level)) { cur->bc_ops->update_lastrec(cur, block, NULL, ptr, LASTREC_DELREC); } /* * We're at the root level. First, shrink the root block in-memory. * Try to get rid of the next level down. If we can't then there's * nothing left to do. */ if (level == cur->bc_nlevels - 1) { if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) { xfs_iroot_realloc(cur->bc_private.b.ip, -1, cur->bc_private.b.whichfork); error = xfs_btree_kill_iroot(cur); if (error) goto error0; error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; *stat = 1; return 0; } /* * If this is the root level, and there's only one entry left, * and it's NOT the leaf level, then we can get rid of this * level. */ if (numrecs == 1 && level > 0) { union xfs_btree_ptr *pp; /* * pp is still set to the first pointer in the block. * Make it the new root of the btree. */ pp = xfs_btree_ptr_addr(cur, 1, block); error = xfs_btree_kill_root(cur, bp, level, pp); if (error) goto error0; } else if (level > 0) { error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; } *stat = 1; return 0; } /* * If we deleted the leftmost entry in the block, update the * key values above us in the tree. */ if (xfs_btree_needs_key_update(cur, ptr)) { error = xfs_btree_update_keys(cur, level); if (error) goto error0; } /* * If the number of records remaining in the block is at least * the minimum, we're done. */ if (numrecs >= cur->bc_ops->get_minrecs(cur, level)) { error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } /* * Otherwise, we have to move some records around to keep the * tree balanced. Look at the left and right sibling blocks to * see if we can re-balance by moving only one record. */ xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); xfs_btree_get_sibling(cur, block, &lptr, XFS_BB_LEFTSIB); if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) { /* * One child of root, need to get a chance to copy its contents * into the root and delete it. Can't go up to next level, * there's nothing to delete there. */ if (xfs_btree_ptr_is_null(cur, &rptr) && xfs_btree_ptr_is_null(cur, &lptr) && level == cur->bc_nlevels - 2) { error = xfs_btree_kill_iroot(cur); if (!error) error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } } ASSERT(!xfs_btree_ptr_is_null(cur, &rptr) || !xfs_btree_ptr_is_null(cur, &lptr)); /* * Duplicate the cursor so our btree manipulations here won't * disrupt the next level up. */ error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; /* * If there's a right sibling, see if it's ok to shift an entry * out of it. */ if (!xfs_btree_ptr_is_null(cur, &rptr)) { /* * Move the temp cursor to the last entry in the next block. * Actually any entry but the first would suffice. */ i = xfs_btree_lastrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_increment(tcur, level, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); i = xfs_btree_lastrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); /* Grab a pointer to the block. */ right = xfs_btree_get_block(tcur, level, &rbp); #ifdef DEBUG error = xfs_btree_check_block(tcur, right, level, rbp); if (error) goto error0; #endif /* Grab the current block number, for future use. */ xfs_btree_get_sibling(tcur, right, &cptr, XFS_BB_LEFTSIB); /* * If right block is full enough so that removing one entry * won't make it too empty, and left-shifting an entry out * of right to us works, we're done. */ if (xfs_btree_get_numrecs(right) - 1 >= cur->bc_ops->get_minrecs(tcur, level)) { error = xfs_btree_lshift(tcur, level, &i); if (error) goto error0; if (i) { ASSERT(xfs_btree_get_numrecs(block) >= cur->bc_ops->get_minrecs(tcur, level)); xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); tcur = NULL; error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } } /* * Otherwise, grab the number of records in right for * future reference, and fix up the temp cursor to point * to our block again (last record). */ rrecs = xfs_btree_get_numrecs(right); if (!xfs_btree_ptr_is_null(cur, &lptr)) { i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_decrement(tcur, level, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); } } /* * If there's a left sibling, see if it's ok to shift an entry * out of it. */ if (!xfs_btree_ptr_is_null(cur, &lptr)) { /* * Move the temp cursor to the first entry in the * previous block. */ i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_decrement(tcur, level, &i); if (error) goto error0; i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); /* Grab a pointer to the block. */ left = xfs_btree_get_block(tcur, level, &lbp); #ifdef DEBUG error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif /* Grab the current block number, for future use. */ xfs_btree_get_sibling(tcur, left, &cptr, XFS_BB_RIGHTSIB); /* * If left block is full enough so that removing one entry * won't make it too empty, and right-shifting an entry out * of left to us works, we're done. */ if (xfs_btree_get_numrecs(left) - 1 >= cur->bc_ops->get_minrecs(tcur, level)) { error = xfs_btree_rshift(tcur, level, &i); if (error) goto error0; if (i) { ASSERT(xfs_btree_get_numrecs(block) >= cur->bc_ops->get_minrecs(tcur, level)); xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); tcur = NULL; if (level == 0) cur->bc_ptrs[0]++; *stat = 1; return 0; } } /* * Otherwise, grab the number of records in right for * future reference. */ lrecs = xfs_btree_get_numrecs(left); } /* Delete the temp cursor, we're done with it. */ xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); tcur = NULL; /* If here, we need to do a join to keep the tree balanced. */ ASSERT(!xfs_btree_ptr_is_null(cur, &cptr)); if (!xfs_btree_ptr_is_null(cur, &lptr) && lrecs + xfs_btree_get_numrecs(block) <= cur->bc_ops->get_maxrecs(cur, level)) { /* * Set "right" to be the starting block, * "left" to be the left neighbor. */ rptr = cptr; right = block; rbp = bp; error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; /* * If that won't work, see if we can join with the right neighbor block. */ } else if (!xfs_btree_ptr_is_null(cur, &rptr) && rrecs + xfs_btree_get_numrecs(block) <= cur->bc_ops->get_maxrecs(cur, level)) { /* * Set "left" to be the starting block, * "right" to be the right neighbor. */ lptr = cptr; left = block; lbp = bp; error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; /* * Otherwise, we can't fix the imbalance. * Just return. This is probably a logic error, but it's not fatal. */ } else { error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } rrecs = xfs_btree_get_numrecs(right); lrecs = xfs_btree_get_numrecs(left); /* * We're now going to join "left" and "right" by moving all the stuff * in "right" to "left" and deleting "right". */ XFS_BTREE_STATS_ADD(cur, moves, rrecs); if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ union xfs_btree_key *rkp; /* right btree key */ union xfs_btree_ptr *rpp; /* right address pointer */ lkp = xfs_btree_key_addr(cur, lrecs + 1, left); lpp = xfs_btree_ptr_addr(cur, lrecs + 1, left); rkp = xfs_btree_key_addr(cur, 1, right); rpp = xfs_btree_ptr_addr(cur, 1, right); for (i = 1; i < rrecs; i++) { error = xfs_btree_debug_check_ptr(cur, rpp, i, level); if (error) goto error0; } xfs_btree_copy_keys(cur, lkp, rkp, rrecs); xfs_btree_copy_ptrs(cur, lpp, rpp, rrecs); xfs_btree_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs); xfs_btree_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs); } else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ union xfs_btree_rec *rrp; /* right record pointer */ lrp = xfs_btree_rec_addr(cur, lrecs + 1, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_copy_recs(cur, lrp, rrp, rrecs); xfs_btree_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs); } XFS_BTREE_STATS_INC(cur, join); /* * Fix up the number of records and right block pointer in the * surviving block, and log it. */ xfs_btree_set_numrecs(left, lrecs + rrecs); xfs_btree_get_sibling(cur, right, &cptr, XFS_BB_RIGHTSIB), xfs_btree_set_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); /* If there is a right sibling, point it to the remaining block. */ xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &cptr)) { error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp); if (error) goto error0; xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB); xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB); } /* Free the deleted block. */ error = xfs_btree_free_block(cur, rbp); if (error) goto error0; /* * If we joined with the left neighbor, set the buffer in the * cursor to the left block, and fix up the index. */ if (bp != lbp) { cur->bc_bufs[level] = lbp; cur->bc_ptrs[level] += lrecs; cur->bc_ra[level] = 0; } /* * If we joined with the right neighbor and there's a level above * us, increment the cursor at that level. */ else if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) || (level + 1 < cur->bc_nlevels)) { error = xfs_btree_increment(cur, level + 1, &i); if (error) goto error0; } /* * Readjust the ptr at this level if it's not a leaf, since it's * still pointing at the deletion point, which makes the cursor * inconsistent. If this makes the ptr 0, the caller fixes it up. * We can't use decrement because it would change the next level up. */ if (level > 0) cur->bc_ptrs[level]--; /* * We combined blocks, so we have to update the parent keys if the * btree supports overlapped intervals. However, bc_ptrs[level + 1] * points to the old block so that the caller knows which record to * delete. Therefore, the caller must be savvy enough to call updkeys * for us if we return stat == 2. The other exit points from this * function don't require deletions further up the tree, so they can * call updkeys directly. */ /* Return value means the next level up has something to do. */ *stat = 2; return 0; error0: if (tcur) xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); return error; } /* * Delete the record pointed to by cur. * The cursor refers to the place where the record was (could be inserted) * when the operation returns. */ int /* error */ xfs_btree_delete( struct xfs_btree_cur *cur, int *stat) /* success/failure */ { int error; /* error return value */ int level; int i; bool joined = false; /* * Go up the tree, starting at leaf level. * * If 2 is returned then a join was done; go to the next level. * Otherwise we are done. */ for (level = 0, i = 2; i == 2; level++) { error = xfs_btree_delrec(cur, level, &i); if (error) goto error0; if (i == 2) joined = true; } /* * If we combined blocks as part of deleting the record, delrec won't * have updated the parent high keys so we have to do that here. */ if (joined && (cur->bc_flags & XFS_BTREE_OVERLAPPING)) { error = xfs_btree_updkeys_force(cur, 0); if (error) goto error0; } if (i == 0) { for (level = 1; level < cur->bc_nlevels; level++) { if (cur->bc_ptrs[level] == 0) { error = xfs_btree_decrement(cur, level, &i); if (error) goto error0; break; } } } *stat = i; return 0; error0: return error; } /* * Get the data from the pointed-to record. */ int /* error */ xfs_btree_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ union xfs_btree_rec **recp, /* output: btree record */ int *stat) /* output: success/failure */ { struct xfs_btree_block *block; /* btree block */ struct xfs_buf *bp; /* buffer pointer */ int ptr; /* record number */ #ifdef DEBUG int error; /* error return value */ #endif ptr = cur->bc_ptrs[0]; block = xfs_btree_get_block(cur, 0, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, 0, bp); if (error) return error; #endif /* * Off the right end or left end, return failure. */ if (ptr > xfs_btree_get_numrecs(block) || ptr <= 0) { *stat = 0; return 0; } /* * Point to the record and extract its data. */ *recp = xfs_btree_rec_addr(cur, ptr, block); *stat = 1; return 0; } /* Visit a block in a btree. */ STATIC int xfs_btree_visit_block( struct xfs_btree_cur *cur, int level, xfs_btree_visit_blocks_fn fn, void *data) { struct xfs_btree_block *block; struct xfs_buf *bp; union xfs_btree_ptr rptr; int error; /* do right sibling readahead */ xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); block = xfs_btree_get_block(cur, level, &bp); /* process the block */ error = fn(cur, level, data); if (error) return error; /* now read rh sibling block for next iteration */ xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &rptr)) return -ENOENT; return xfs_btree_lookup_get_block(cur, level, &rptr, &block); } /* Visit every block in a btree. */ int xfs_btree_visit_blocks( struct xfs_btree_cur *cur, xfs_btree_visit_blocks_fn fn, void *data) { union xfs_btree_ptr lptr; int level; struct xfs_btree_block *block = NULL; int error = 0; cur->bc_ops->init_ptr_from_cur(cur, &lptr); /* for each level */ for (level = cur->bc_nlevels - 1; level >= 0; level--) { /* grab the left hand block */ error = xfs_btree_lookup_get_block(cur, level, &lptr, &block); if (error) return error; /* readahead the left most block for the next level down */ if (level > 0) { union xfs_btree_ptr *ptr; ptr = xfs_btree_ptr_addr(cur, 1, block); xfs_btree_readahead_ptr(cur, ptr, 1); /* save for the next iteration of the loop */ xfs_btree_copy_ptrs(cur, &lptr, ptr, 1); } /* for each buffer in the level */ do { error = xfs_btree_visit_block(cur, level, fn, data); } while (!error); if (error != -ENOENT) return error; } return 0; } /* * Change the owner of a btree. * * The mechanism we use here is ordered buffer logging. Because we don't know * how many buffers were are going to need to modify, we don't really want to * have to make transaction reservations for the worst case of every buffer in a * full size btree as that may be more space that we can fit in the log.... * * We do the btree walk in the most optimal manner possible - we have sibling * pointers so we can just walk all the blocks on each level from left to right * in a single pass, and then move to the next level and do the same. We can * also do readahead on the sibling pointers to get IO moving more quickly, * though for slow disks this is unlikely to make much difference to performance * as the amount of CPU work we have to do before moving to the next block is * relatively small. * * For each btree block that we load, modify the owner appropriately, set the * buffer as an ordered buffer and log it appropriately. We need to ensure that * we mark the region we change dirty so that if the buffer is relogged in * a subsequent transaction the changes we make here as an ordered buffer are * correctly relogged in that transaction. If we are in recovery context, then * just queue the modified buffer as delayed write buffer so the transaction * recovery completion writes the changes to disk. */ struct xfs_btree_block_change_owner_info { uint64_t new_owner; struct list_head *buffer_list; }; static int xfs_btree_block_change_owner( struct xfs_btree_cur *cur, int level, void *data) { struct xfs_btree_block_change_owner_info *bbcoi = data; struct xfs_btree_block *block; struct xfs_buf *bp; /* modify the owner */ block = xfs_btree_get_block(cur, level, &bp); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (block->bb_u.l.bb_owner == cpu_to_be64(bbcoi->new_owner)) return 0; block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner); } else { if (block->bb_u.s.bb_owner == cpu_to_be32(bbcoi->new_owner)) return 0; block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner); } /* * If the block is a root block hosted in an inode, we might not have a * buffer pointer here and we shouldn't attempt to log the change as the * information is already held in the inode and discarded when the root * block is formatted into the on-disk inode fork. We still change it, * though, so everything is consistent in memory. */ if (!bp) { ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); ASSERT(level == cur->bc_nlevels - 1); return 0; } if (cur->bc_tp) { if (!xfs_trans_ordered_buf(cur->bc_tp, bp)) { xfs_btree_log_block(cur, bp, XFS_BB_OWNER); return -EAGAIN; } } else { xfs_buf_delwri_queue(bp, bbcoi->buffer_list); } return 0; } int xfs_btree_change_owner( struct xfs_btree_cur *cur, uint64_t new_owner, struct list_head *buffer_list) { struct xfs_btree_block_change_owner_info bbcoi; bbcoi.new_owner = new_owner; bbcoi.buffer_list = buffer_list; return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner, &bbcoi); } /* Verify the v5 fields of a long-format btree block. */ xfs_failaddr_t xfs_btree_lblock_v5hdr_verify( struct xfs_buf *bp, uint64_t owner) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); if (!xfs_sb_version_hascrc(&mp->m_sb)) return __this_address; if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (block->bb_u.l.bb_blkno != cpu_to_be64(bp->b_bn)) return __this_address; if (owner != XFS_RMAP_OWN_UNKNOWN && be64_to_cpu(block->bb_u.l.bb_owner) != owner) return __this_address; return NULL; } /* Verify a long-format btree block. */ xfs_failaddr_t xfs_btree_lblock_verify( struct xfs_buf *bp, unsigned int max_recs) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > max_recs) return __this_address; /* sibling pointer verification */ if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_leftsib))) return __this_address; if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_rightsib))) return __this_address; return NULL; } /** * xfs_btree_sblock_v5hdr_verify() -- verify the v5 fields of a short-format * btree block * * @bp: buffer containing the btree block * @max_recs: pointer to the m_*_mxr max records field in the xfs mount * @pag_max_level: pointer to the per-ag max level field */ xfs_failaddr_t xfs_btree_sblock_v5hdr_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_perag *pag = bp->b_pag; if (!xfs_sb_version_hascrc(&mp->m_sb)) return __this_address; if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) return __this_address; if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) return __this_address; return NULL; } /** * xfs_btree_sblock_verify() -- verify a short-format btree block * * @bp: buffer containing the btree block * @max_recs: maximum records allowed in this btree node */ xfs_failaddr_t xfs_btree_sblock_verify( struct xfs_buf *bp, unsigned int max_recs) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_agblock_t agno; /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > max_recs) return __this_address; /* sibling pointer verification */ agno = xfs_daddr_to_agno(mp, XFS_BUF_ADDR(bp)); if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) && !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_leftsib))) return __this_address; if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) && !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_rightsib))) return __this_address; return NULL; } /* * Calculate the number of btree levels needed to store a given number of * records in a short-format btree. */ uint xfs_btree_compute_maxlevels( uint *limits, unsigned long len) { uint level; unsigned long maxblocks; maxblocks = (len + limits[0] - 1) / limits[0]; for (level = 1; maxblocks > 1; level++) maxblocks = (maxblocks + limits[1] - 1) / limits[1]; return level; } /* * Query a regular btree for all records overlapping a given interval. * Start with a LE lookup of the key of low_rec and return all records * until we find a record with a key greater than the key of high_rec. */ STATIC int xfs_btree_simple_query_range( struct xfs_btree_cur *cur, union xfs_btree_key *low_key, union xfs_btree_key *high_key, xfs_btree_query_range_fn fn, void *priv) { union xfs_btree_rec *recp; union xfs_btree_key rec_key; int64_t diff; int stat; bool firstrec = true; int error; ASSERT(cur->bc_ops->init_high_key_from_rec); ASSERT(cur->bc_ops->diff_two_keys); /* * Find the leftmost record. The btree cursor must be set * to the low record used to generate low_key. */ stat = 0; error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, &stat); if (error) goto out; /* Nothing? See if there's anything to the right. */ if (!stat) { error = xfs_btree_increment(cur, 0, &stat); if (error) goto out; } while (stat) { /* Find the record. */ error = xfs_btree_get_rec(cur, &recp, &stat); if (error || !stat) break; /* Skip if high_key(rec) < low_key. */ if (firstrec) { cur->bc_ops->init_high_key_from_rec(&rec_key, recp); firstrec = false; diff = cur->bc_ops->diff_two_keys(cur, low_key, &rec_key); if (diff > 0) goto advloop; } /* Stop if high_key < low_key(rec). */ cur->bc_ops->init_key_from_rec(&rec_key, recp); diff = cur->bc_ops->diff_two_keys(cur, &rec_key, high_key); if (diff > 0) break; /* Callback */ error = fn(cur, recp, priv); if (error < 0 || error == XFS_BTREE_QUERY_RANGE_ABORT) break; advloop: /* Move on to the next record. */ error = xfs_btree_increment(cur, 0, &stat); if (error) break; } out: return error; } /* * Query an overlapped interval btree for all records overlapping a given * interval. This function roughly follows the algorithm given in * "Interval Trees" of _Introduction to Algorithms_, which is section * 14.3 in the 2nd and 3rd editions. * * First, generate keys for the low and high records passed in. * * For any leaf node, generate the high and low keys for the record. * If the record keys overlap with the query low/high keys, pass the * record to the function iterator. * * For any internal node, compare the low and high keys of each * pointer against the query low/high keys. If there's an overlap, * follow the pointer. * * As an optimization, we stop scanning a block when we find a low key * that is greater than the query's high key. */ STATIC int xfs_btree_overlapped_query_range( struct xfs_btree_cur *cur, union xfs_btree_key *low_key, union xfs_btree_key *high_key, xfs_btree_query_range_fn fn, void *priv) { union xfs_btree_ptr ptr; union xfs_btree_ptr *pp; union xfs_btree_key rec_key; union xfs_btree_key rec_hkey; union xfs_btree_key *lkp; union xfs_btree_key *hkp; union xfs_btree_rec *recp; struct xfs_btree_block *block; int64_t ldiff; int64_t hdiff; int level; struct xfs_buf *bp; int i; int error; /* Load the root of the btree. */ level = cur->bc_nlevels - 1; cur->bc_ops->init_ptr_from_cur(cur, &ptr); error = xfs_btree_lookup_get_block(cur, level, &ptr, &block); if (error) return error; xfs_btree_get_block(cur, level, &bp); trace_xfs_btree_overlapped_query_range(cur, level, bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto out; #endif cur->bc_ptrs[level] = 1; while (level < cur->bc_nlevels) { block = xfs_btree_get_block(cur, level, &bp); /* End of node, pop back towards the root. */ if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) { pop_up: if (level < cur->bc_nlevels - 1) cur->bc_ptrs[level + 1]++; level++; continue; } if (level == 0) { /* Handle a leaf node. */ recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block); cur->bc_ops->init_high_key_from_rec(&rec_hkey, recp); ldiff = cur->bc_ops->diff_two_keys(cur, &rec_hkey, low_key); cur->bc_ops->init_key_from_rec(&rec_key, recp); hdiff = cur->bc_ops->diff_two_keys(cur, high_key, &rec_key); /* * If (record's high key >= query's low key) and * (query's high key >= record's low key), then * this record overlaps the query range; callback. */ if (ldiff >= 0 && hdiff >= 0) { error = fn(cur, recp, priv); if (error < 0 || error == XFS_BTREE_QUERY_RANGE_ABORT) break; } else if (hdiff < 0) { /* Record is larger than high key; pop. */ goto pop_up; } cur->bc_ptrs[level]++; continue; } /* Handle an internal node. */ lkp = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block); hkp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block); pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block); ldiff = cur->bc_ops->diff_two_keys(cur, hkp, low_key); hdiff = cur->bc_ops->diff_two_keys(cur, high_key, lkp); /* * If (pointer's high key >= query's low key) and * (query's high key >= pointer's low key), then * this record overlaps the query range; follow pointer. */ if (ldiff >= 0 && hdiff >= 0) { level--; error = xfs_btree_lookup_get_block(cur, level, pp, &block); if (error) goto out; xfs_btree_get_block(cur, level, &bp); trace_xfs_btree_overlapped_query_range(cur, level, bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto out; #endif cur->bc_ptrs[level] = 1; continue; } else if (hdiff < 0) { /* The low key is larger than the upper range; pop. */ goto pop_up; } cur->bc_ptrs[level]++; } out: /* * If we don't end this function with the cursor pointing at a record * block, a subsequent non-error cursor deletion will not release * node-level buffers, causing a buffer leak. This is quite possible * with a zero-results range query, so release the buffers if we * failed to return any results. */ if (cur->bc_bufs[0] == NULL) { for (i = 0; i < cur->bc_nlevels; i++) { if (cur->bc_bufs[i]) { xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]); cur->bc_bufs[i] = NULL; cur->bc_ptrs[i] = 0; cur->bc_ra[i] = 0; } } } return error; } /* * Query a btree for all records overlapping a given interval of keys. The * supplied function will be called with each record found; return one of the * XFS_BTREE_QUERY_RANGE_{CONTINUE,ABORT} values or the usual negative error * code. This function returns XFS_BTREE_QUERY_RANGE_ABORT, zero, or a * negative error code. */ int xfs_btree_query_range( struct xfs_btree_cur *cur, union xfs_btree_irec *low_rec, union xfs_btree_irec *high_rec, xfs_btree_query_range_fn fn, void *priv) { union xfs_btree_rec rec; union xfs_btree_key low_key; union xfs_btree_key high_key; /* Find the keys of both ends of the interval. */ cur->bc_rec = *high_rec; cur->bc_ops->init_rec_from_cur(cur, &rec); cur->bc_ops->init_key_from_rec(&high_key, &rec); cur->bc_rec = *low_rec; cur->bc_ops->init_rec_from_cur(cur, &rec); cur->bc_ops->init_key_from_rec(&low_key, &rec); /* Enforce low key < high key. */ if (cur->bc_ops->diff_two_keys(cur, &low_key, &high_key) > 0) return -EINVAL; if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING)) return xfs_btree_simple_query_range(cur, &low_key, &high_key, fn, priv); return xfs_btree_overlapped_query_range(cur, &low_key, &high_key, fn, priv); } /* Query a btree for all records. */ int xfs_btree_query_all( struct xfs_btree_cur *cur, xfs_btree_query_range_fn fn, void *priv) { union xfs_btree_key low_key; union xfs_btree_key high_key; memset(&cur->bc_rec, 0, sizeof(cur->bc_rec)); memset(&low_key, 0, sizeof(low_key)); memset(&high_key, 0xFF, sizeof(high_key)); return xfs_btree_simple_query_range(cur, &low_key, &high_key, fn, priv); } /* * Calculate the number of blocks needed to store a given number of records * in a short-format (per-AG metadata) btree. */ unsigned long long xfs_btree_calc_size( uint *limits, unsigned long long len) { int level; int maxrecs; unsigned long long rval; maxrecs = limits[0]; for (level = 0, rval = 0; len > 1; level++) { len += maxrecs - 1; do_div(len, maxrecs); maxrecs = limits[1]; rval += len; } return rval; } static int xfs_btree_count_blocks_helper( struct xfs_btree_cur *cur, int level, void *data) { xfs_extlen_t *blocks = data; (*blocks)++; return 0; } /* Count the blocks in a btree and return the result in *blocks. */ int xfs_btree_count_blocks( struct xfs_btree_cur *cur, xfs_extlen_t *blocks) { *blocks = 0; return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper, blocks); } /* Compare two btree pointers. */ int64_t xfs_btree_diff_two_ptrs( struct xfs_btree_cur *cur, const union xfs_btree_ptr *a, const union xfs_btree_ptr *b) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return (int64_t)be64_to_cpu(a->l) - be64_to_cpu(b->l); return (int64_t)be32_to_cpu(a->s) - be32_to_cpu(b->s); } /* If there's an extent, we're done. */ STATIC int xfs_btree_has_record_helper( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, void *priv) { return XFS_BTREE_QUERY_RANGE_ABORT; } /* Is there a record covering a given range of keys? */ int xfs_btree_has_record( struct xfs_btree_cur *cur, union xfs_btree_irec *low, union xfs_btree_irec *high, bool *exists) { int error; error = xfs_btree_query_range(cur, low, high, &xfs_btree_has_record_helper, NULL); if (error == XFS_BTREE_QUERY_RANGE_ABORT) { *exists = true; return 0; } *exists = false; return error; } /* Are there more records in this btree? */ bool xfs_btree_has_more_records( struct xfs_btree_cur *cur) { struct xfs_btree_block *block; struct xfs_buf *bp; block = xfs_btree_get_block(cur, 0, &bp); /* There are still records in this block. */ if (cur->bc_ptrs[0] < xfs_btree_get_numrecs(block)) return true; /* There are more record blocks. */ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK); else return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK); } xfsprogs-5.3.0/libxfs/xfs_btree.h0000644000175000017500000004055513570057155016706 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_BTREE_H__ #define __XFS_BTREE_H__ struct xfs_buf; struct xfs_inode; struct xfs_mount; struct xfs_trans; extern kmem_zone_t *xfs_btree_cur_zone; /* * Generic key, ptr and record wrapper structures. * * These are disk format structures, and are converted where necessary * by the btree specific code that needs to interpret them. */ union xfs_btree_ptr { __be32 s; /* short form ptr */ __be64 l; /* long form ptr */ }; /* * The in-core btree key. Overlapping btrees actually store two keys * per pointer, so we reserve enough memory to hold both. The __*bigkey * items should never be accessed directly. */ union xfs_btree_key { struct xfs_bmbt_key bmbt; xfs_bmdr_key_t bmbr; /* bmbt root block */ xfs_alloc_key_t alloc; struct xfs_inobt_key inobt; struct xfs_rmap_key rmap; struct xfs_rmap_key __rmap_bigkey[2]; struct xfs_refcount_key refc; }; union xfs_btree_rec { struct xfs_bmbt_rec bmbt; xfs_bmdr_rec_t bmbr; /* bmbt root block */ struct xfs_alloc_rec alloc; struct xfs_inobt_rec inobt; struct xfs_rmap_rec rmap; struct xfs_refcount_rec refc; }; /* * This nonsense is to make -wlint happy. */ #define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) #define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) #define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) #define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) #define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) #define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) #define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) #define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi) #define XFS_BTNUM_RMAP ((xfs_btnum_t)XFS_BTNUM_RMAPi) #define XFS_BTNUM_REFC ((xfs_btnum_t)XFS_BTNUM_REFCi) uint32_t xfs_btree_magic(int crc, xfs_btnum_t btnum); /* * For logging record fields. */ #define XFS_BB_MAGIC (1 << 0) #define XFS_BB_LEVEL (1 << 1) #define XFS_BB_NUMRECS (1 << 2) #define XFS_BB_LEFTSIB (1 << 3) #define XFS_BB_RIGHTSIB (1 << 4) #define XFS_BB_BLKNO (1 << 5) #define XFS_BB_LSN (1 << 6) #define XFS_BB_UUID (1 << 7) #define XFS_BB_OWNER (1 << 8) #define XFS_BB_NUM_BITS 5 #define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) #define XFS_BB_NUM_BITS_CRC 9 #define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) /* * Generic stats interface */ #define XFS_BTREE_STATS_INC(cur, stat) \ XFS_STATS_INC_OFF((cur)->bc_mp, (cur)->bc_statoff + __XBTS_ ## stat) #define XFS_BTREE_STATS_ADD(cur, stat, val) \ XFS_STATS_ADD_OFF((cur)->bc_mp, (cur)->bc_statoff + __XBTS_ ## stat, val) #define XFS_BTREE_MAXLEVELS 9 /* max of all btrees */ struct xfs_btree_ops { /* size of the key and record structures */ size_t key_len; size_t rec_len; /* cursor operations */ struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); void (*update_cursor)(struct xfs_btree_cur *src, struct xfs_btree_cur *dst); /* update btree root pointer */ void (*set_root)(struct xfs_btree_cur *cur, union xfs_btree_ptr *nptr, int level_change); /* block allocation / freeing */ int (*alloc_block)(struct xfs_btree_cur *cur, union xfs_btree_ptr *start_bno, union xfs_btree_ptr *new_bno, int *stat); int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); /* update last record information */ void (*update_lastrec)(struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_rec *rec, int ptr, int reason); /* records in block/level */ int (*get_minrecs)(struct xfs_btree_cur *cur, int level); int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); /* records on disk. Matter for the root in inode case. */ int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level); /* init values of btree structures */ void (*init_key_from_rec)(union xfs_btree_key *key, union xfs_btree_rec *rec); void (*init_rec_from_cur)(struct xfs_btree_cur *cur, union xfs_btree_rec *rec); void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr); void (*init_high_key_from_rec)(union xfs_btree_key *key, union xfs_btree_rec *rec); /* difference between key value and cursor value */ int64_t (*key_diff)(struct xfs_btree_cur *cur, union xfs_btree_key *key); /* * Difference between key2 and key1 -- positive if key1 > key2, * negative if key1 < key2, and zero if equal. */ int64_t (*diff_two_keys)(struct xfs_btree_cur *cur, union xfs_btree_key *key1, union xfs_btree_key *key2); const struct xfs_buf_ops *buf_ops; /* check that k1 is lower than k2 */ int (*keys_inorder)(struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2); /* check that r1 is lower than r2 */ int (*recs_inorder)(struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2); }; /* * Reasons for the update_lastrec method to be called. */ #define LASTREC_UPDATE 0 #define LASTREC_INSREC 1 #define LASTREC_DELREC 2 union xfs_btree_irec { struct xfs_alloc_rec_incore a; struct xfs_bmbt_irec b; struct xfs_inobt_rec_incore i; struct xfs_rmap_irec r; struct xfs_refcount_irec rc; }; /* Per-AG btree private information. */ union xfs_btree_cur_private { struct { unsigned long nr_ops; /* # record updates */ int shape_changes; /* # of extent splits */ } refc; }; /* * Btree cursor structure. * This collects all information needed by the btree code in one place. */ typedef struct xfs_btree_cur { struct xfs_trans *bc_tp; /* transaction we're in, if any */ struct xfs_mount *bc_mp; /* file system mount struct */ const struct xfs_btree_ops *bc_ops; uint bc_flags; /* btree features - below */ union xfs_btree_irec bc_rec; /* current insert/search record value */ struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ #define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ #define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ uint8_t bc_nlevels; /* number of levels in the tree */ uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ xfs_btnum_t bc_btnum; /* identifies which btree type */ int bc_statoff; /* offset of btre stats array */ union { struct { /* needed for BNO, CNT, INO */ struct xfs_buf *agbp; /* agf/agi buffer pointer */ xfs_agnumber_t agno; /* ag number */ union xfs_btree_cur_private priv; } a; struct { /* needed for BMAP */ struct xfs_inode *ip; /* pointer to our inode */ int allocated; /* count of alloced */ short forksize; /* fork's inode space */ char whichfork; /* data or attr fork */ char flags; /* flags */ #define XFS_BTCUR_BPRV_WASDEL (1<<0) /* was delayed */ #define XFS_BTCUR_BPRV_INVALID_OWNER (1<<1) /* for ext swap */ } b; } bc_private; /* per-btree type data */ } xfs_btree_cur_t; /* cursor flags */ #define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ #define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ #define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ #define XFS_BTREE_CRC_BLOCKS (1<<3) /* uses extended btree blocks */ #define XFS_BTREE_OVERLAPPING (1<<4) /* overlapping intervals */ #define XFS_BTREE_NOERROR 0 #define XFS_BTREE_ERROR 1 /* * Convert from buffer to btree block header. */ #define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)((bp)->b_addr)) /* * Internal long and short btree block checks. They return NULL if the * block is ok or the address of the failed check otherwise. */ xfs_failaddr_t __xfs_btree_check_lblock(struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *bp); xfs_failaddr_t __xfs_btree_check_sblock(struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *bp); /* * Check that block header is ok. */ int xfs_btree_check_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* generic btree block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp); /* buffer containing block, if any */ /* * Check that (long) pointer is ok. */ bool /* error (0 or EFSCORRUPTED) */ xfs_btree_check_lptr( struct xfs_btree_cur *cur, /* btree cursor */ xfs_fsblock_t fsbno, /* btree block disk address */ int level); /* btree block level */ /* * Check that (short) pointer is ok. */ bool /* error (0 or EFSCORRUPTED) */ xfs_btree_check_sptr( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t agbno, /* btree block disk address */ int level); /* btree block level */ /* * Delete the btree cursor. */ void xfs_btree_del_cursor( xfs_btree_cur_t *cur, /* btree cursor */ int error); /* del because of error */ /* * Duplicate the btree cursor. * Allocate a new one, copy the record, re-get the buffers. */ int /* error */ xfs_btree_dup_cursor( xfs_btree_cur_t *cur, /* input cursor */ xfs_btree_cur_t **ncur);/* output cursor */ /* * Get a buffer for the block, return it with no data read. * Long-form addressing. */ struct xfs_buf * /* buffer for fsbno */ xfs_btree_get_bufl( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t fsbno); /* file system block number */ /* * Get a buffer for the block, return it with no data read. * Short-form addressing. */ struct xfs_buf * /* buffer for agno/agbno */ xfs_btree_get_bufs( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno); /* allocation group block number */ /* * Check for the cursor referring to the last block at the given level. */ int /* 1=is last block, 0=not last block */ xfs_btree_islastblock( xfs_btree_cur_t *cur, /* btree cursor */ int level); /* level to check */ /* * Compute first and last byte offsets for the fields given. * Interprets the offsets table, which contains struct field offsets. */ void xfs_btree_offsets( int64_t fields, /* bitmask of fields */ const short *offsets,/* table of field offsets */ int nbits, /* number of bits to inspect */ int *first, /* output: first byte offset */ int *last); /* output: last byte offset */ /* * Get a buffer for the block, return it read in. * Long-form addressing. */ int /* error */ xfs_btree_read_bufl( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t fsbno, /* file system block number */ struct xfs_buf **bpp, /* buffer for fsbno */ int refval, /* ref count value for buffer */ const struct xfs_buf_ops *ops); /* * Read-ahead the block, don't wait for it, don't return a buffer. * Long-form addressing. */ void /* error */ xfs_btree_reada_bufl( struct xfs_mount *mp, /* file system mount point */ xfs_fsblock_t fsbno, /* file system block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops); /* * Read-ahead the block, don't wait for it, don't return a buffer. * Short-form addressing. */ void /* error */ xfs_btree_reada_bufs( struct xfs_mount *mp, /* file system mount point */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno, /* allocation group block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops); /* * Initialise a new btree block header */ void xfs_btree_init_block( struct xfs_mount *mp, struct xfs_buf *bp, xfs_btnum_t btnum, __u16 level, __u16 numrecs, __u64 owner); void xfs_btree_init_block_int( struct xfs_mount *mp, struct xfs_btree_block *buf, xfs_daddr_t blkno, xfs_btnum_t btnum, __u16 level, __u16 numrecs, __u64 owner, unsigned int flags); /* * Common btree core entry points. */ int xfs_btree_increment(struct xfs_btree_cur *, int, int *); int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); int xfs_btree_insert(struct xfs_btree_cur *, int *); int xfs_btree_delete(struct xfs_btree_cur *, int *); int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); int xfs_btree_change_owner(struct xfs_btree_cur *cur, uint64_t new_owner, struct list_head *buffer_list); /* * btree block CRC helpers */ void xfs_btree_lblock_calc_crc(struct xfs_buf *); bool xfs_btree_lblock_verify_crc(struct xfs_buf *); void xfs_btree_sblock_calc_crc(struct xfs_buf *); bool xfs_btree_sblock_verify_crc(struct xfs_buf *); /* * Internal btree helpers also used by xfs_bmap.c. */ void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); void xfs_btree_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, int); /* * Helpers. */ static inline int xfs_btree_get_numrecs(struct xfs_btree_block *block) { return be16_to_cpu(block->bb_numrecs); } static inline void xfs_btree_set_numrecs(struct xfs_btree_block *block, uint16_t numrecs) { block->bb_numrecs = cpu_to_be16(numrecs); } static inline int xfs_btree_get_level(struct xfs_btree_block *block) { return be16_to_cpu(block->bb_level); } /* * Min and max functions for extlen, agblock, fileoff, and filblks types. */ #define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b)) #define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b)) #define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b)) #define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b)) #define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b)) #define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b)) #define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b)) #define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b)) xfs_failaddr_t xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp); xfs_failaddr_t xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs); xfs_failaddr_t xfs_btree_lblock_v5hdr_verify(struct xfs_buf *bp, uint64_t owner); xfs_failaddr_t xfs_btree_lblock_verify(struct xfs_buf *bp, unsigned int max_recs); uint xfs_btree_compute_maxlevels(uint *limits, unsigned long len); unsigned long long xfs_btree_calc_size(uint *limits, unsigned long long len); /* return codes */ #define XFS_BTREE_QUERY_RANGE_CONTINUE (XFS_ITER_CONTINUE) /* keep iterating */ #define XFS_BTREE_QUERY_RANGE_ABORT (XFS_ITER_ABORT) /* stop iterating */ typedef int (*xfs_btree_query_range_fn)(struct xfs_btree_cur *cur, union xfs_btree_rec *rec, void *priv); int xfs_btree_query_range(struct xfs_btree_cur *cur, union xfs_btree_irec *low_rec, union xfs_btree_irec *high_rec, xfs_btree_query_range_fn fn, void *priv); int xfs_btree_query_all(struct xfs_btree_cur *cur, xfs_btree_query_range_fn fn, void *priv); typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level, void *data); int xfs_btree_visit_blocks(struct xfs_btree_cur *cur, xfs_btree_visit_blocks_fn fn, void *data); int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks); union xfs_btree_rec *xfs_btree_rec_addr(struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block); union xfs_btree_key *xfs_btree_key_addr(struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block); union xfs_btree_key *xfs_btree_high_key_addr(struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block); union xfs_btree_ptr *xfs_btree_ptr_addr(struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block); int xfs_btree_lookup_get_block(struct xfs_btree_cur *cur, int level, union xfs_btree_ptr *pp, struct xfs_btree_block **blkp); struct xfs_btree_block *xfs_btree_get_block(struct xfs_btree_cur *cur, int level, struct xfs_buf **bpp); bool xfs_btree_ptr_is_null(struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr); int64_t xfs_btree_diff_two_ptrs(struct xfs_btree_cur *cur, const union xfs_btree_ptr *a, const union xfs_btree_ptr *b); void xfs_btree_get_sibling(struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_ptr *ptr, int lr); void xfs_btree_get_keys(struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_key *key); union xfs_btree_key *xfs_btree_high_key_from_key(struct xfs_btree_cur *cur, union xfs_btree_key *key); int xfs_btree_has_record(struct xfs_btree_cur *cur, union xfs_btree_irec *low, union xfs_btree_irec *high, bool *exists); bool xfs_btree_has_more_records(struct xfs_btree_cur *cur); #endif /* __XFS_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_cksum.h0000644000175000017500000000450413435336036016717 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _XFS_CKSUM_H #define _XFS_CKSUM_H 1 #define XFS_CRC_SEED (~(uint32_t)0) /* * Calculate the intermediate checksum for a buffer that has the CRC field * inside it. The offset of the 32bit crc fields is passed as the * cksum_offset parameter. We do not modify the buffer during verification, * hence we have to split the CRC calculation across the cksum_offset. */ static inline uint32_t xfs_start_cksum_safe(char *buffer, size_t length, unsigned long cksum_offset) { uint32_t zero = 0; uint32_t crc; /* Calculate CRC up to the checksum. */ crc = crc32c(XFS_CRC_SEED, buffer, cksum_offset); /* Skip checksum field */ crc = crc32c(crc, &zero, sizeof(__u32)); /* Calculate the rest of the CRC. */ return crc32c(crc, &buffer[cksum_offset + sizeof(__be32)], length - (cksum_offset + sizeof(__be32))); } /* * Fast CRC method where the buffer is modified. Callers must have exclusive * access to the buffer while the calculation takes place. */ static inline uint32_t xfs_start_cksum_update(char *buffer, size_t length, unsigned long cksum_offset) { /* zero the CRC field */ *(__le32 *)(buffer + cksum_offset) = 0; /* single pass CRC calculation for the entire buffer */ return crc32c(XFS_CRC_SEED, buffer, length); } /* * Convert the intermediate checksum to the final ondisk format. * * The CRC32c calculation uses LE format even on BE machines, but returns the * result in host endian format. Hence we need to byte swap it back to LE format * so that it is consistent on disk. */ static inline __le32 xfs_end_cksum(uint32_t crc) { return ~cpu_to_le32(crc); } /* * Helper to generate the checksum for a buffer. * * This modifies the buffer temporarily - callers must have exclusive * access to the buffer while the calculation takes place. */ static inline void xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) { uint32_t crc = xfs_start_cksum_update(buffer, length, cksum_offset); *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc); } /* * Helper to verify the checksum for a buffer. */ static inline int xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset) { uint32_t crc = xfs_start_cksum_safe(buffer, length, cksum_offset); return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); } #endif /* _XFS_CKSUM_H */ xfsprogs-5.3.0/libxfs/xfs_da_btree.c0000644000175000017500000021601513570057155017341 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_attr_leaf.h" #include "xfs_trace.h" /* * xfs_da_btree.c * * Routines to implement directories as Btrees of hashed names. */ /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Routines used for growing the Btree. */ STATIC int xfs_da3_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *existing_root, xfs_da_state_blk_t *new_child); STATIC int xfs_da3_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *existing_blk, xfs_da_state_blk_t *split_blk, xfs_da_state_blk_t *blk_to_add, int treelevel, int *result); STATIC void xfs_da3_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *node_blk_1, xfs_da_state_blk_t *node_blk_2); STATIC void xfs_da3_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *old_node_blk, xfs_da_state_blk_t *new_node_blk); /* * Routines used for shrinking the Btree. */ STATIC int xfs_da3_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk); STATIC int xfs_da3_node_toosmall(xfs_da_state_t *state, int *retval); STATIC void xfs_da3_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk); STATIC void xfs_da3_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *src_node_blk, xfs_da_state_blk_t *dst_node_blk); /* * Utility routines. */ STATIC int xfs_da3_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, xfs_da_state_blk_t *save_blk); kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ /* * Allocate a dir-state structure. * We don't put them on the stack since they're large. */ xfs_da_state_t * xfs_da_state_alloc(void) { return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS); } /* * Kill the altpath contents of a da-state structure. */ STATIC void xfs_da_state_kill_altpath(xfs_da_state_t *state) { int i; for (i = 0; i < state->altpath.active; i++) state->altpath.blk[i].bp = NULL; state->altpath.active = 0; } /* * Free a da-state structure. */ void xfs_da_state_free(xfs_da_state_t *state) { xfs_da_state_kill_altpath(state); #ifdef DEBUG memset((char *)state, 0, sizeof(*state)); #endif /* DEBUG */ kmem_zone_free(xfs_da_state_zone, state); } /* * Verify an xfs_da3_blkinfo structure. Note that the da3 fields are only * accessible on v5 filesystems. This header format is common across da node, * attr leaf and dir leaf blocks. */ xfs_failaddr_t xfs_da3_blkinfo_verify( struct xfs_buf *bp, struct xfs_da3_blkinfo *hdr3) { struct xfs_mount *mp = bp->b_mount; struct xfs_da_blkinfo *hdr = &hdr3->hdr; if (!xfs_verify_magic16(bp, hdr->magic)) return __this_address; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) return __this_address; } return NULL; } static xfs_failaddr_t xfs_da3_node_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_da_intnode *hdr = bp->b_addr; struct xfs_da3_icnode_hdr ichdr; const struct xfs_dir_ops *ops; xfs_failaddr_t fa; ops = xfs_dir_get_ops(mp, NULL); ops->node_hdr_from_disk(&ichdr, hdr); fa = xfs_da3_blkinfo_verify(bp, bp->b_addr); if (fa) return fa; if (ichdr.level == 0) return __this_address; if (ichdr.level > XFS_DA_NODE_MAXDEPTH) return __this_address; if (ichdr.count == 0) return __this_address; /* * we don't know if the node is for and attribute or directory tree, * so only fail if the count is outside both bounds */ if (ichdr.count > mp->m_dir_geo->node_ents && ichdr.count > mp->m_attr_geo->node_ents) return __this_address; /* XXX: hash order check? */ return NULL; } static void xfs_da3_node_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_da3_node_hdr *hdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_da3_node_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF); } /* * leaf/node format detection on trees is sketchy, so a node read can be done on * leaf level blocks when detection identifies the tree as a node format tree * incorrectly. In this case, we need to swap the verifier to match the correct * format of the block being read. */ static void xfs_da3_node_read_verify( struct xfs_buf *bp) { struct xfs_da_blkinfo *info = bp->b_addr; xfs_failaddr_t fa; switch (be16_to_cpu(info->magic)) { case XFS_DA3_NODE_MAGIC: if (!xfs_buf_verify_cksum(bp, XFS_DA3_NODE_CRC_OFF)) { xfs_verifier_error(bp, -EFSBADCRC, __this_address); break; } /* fall through */ case XFS_DA_NODE_MAGIC: fa = xfs_da3_node_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: bp->b_ops = &xfs_attr3_leaf_buf_ops; bp->b_ops->verify_read(bp); return; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: bp->b_ops = &xfs_dir3_leafn_buf_ops; bp->b_ops->verify_read(bp); return; default: xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); break; } } /* Verify the structure of a da3 block. */ static xfs_failaddr_t xfs_da3_node_verify_struct( struct xfs_buf *bp) { struct xfs_da_blkinfo *info = bp->b_addr; switch (be16_to_cpu(info->magic)) { case XFS_DA3_NODE_MAGIC: case XFS_DA_NODE_MAGIC: return xfs_da3_node_verify(bp); case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: bp->b_ops = &xfs_attr3_leaf_buf_ops; return bp->b_ops->verify_struct(bp); case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: bp->b_ops = &xfs_dir3_leafn_buf_ops; return bp->b_ops->verify_struct(bp); default: return __this_address; } } const struct xfs_buf_ops xfs_da3_node_buf_ops = { .name = "xfs_da3_node", .magic16 = { cpu_to_be16(XFS_DA_NODE_MAGIC), cpu_to_be16(XFS_DA3_NODE_MAGIC) }, .verify_read = xfs_da3_node_read_verify, .verify_write = xfs_da3_node_write_verify, .verify_struct = xfs_da3_node_verify_struct, }; int xfs_da3_node_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int which_fork) { int err; err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, which_fork, &xfs_da3_node_buf_ops); if (!err && tp && *bpp) { struct xfs_da_blkinfo *info = (*bpp)->b_addr; int type; switch (be16_to_cpu(info->magic)) { case XFS_DA_NODE_MAGIC: case XFS_DA3_NODE_MAGIC: type = XFS_BLFT_DA_NODE_BUF; break; case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: type = XFS_BLFT_ATTR_LEAF_BUF; break; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: type = XFS_BLFT_DIR_LEAFN_BUF; break; default: XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, tp->t_mountp, info, sizeof(*info)); xfs_trans_brelse(tp, *bpp); *bpp = NULL; return -EFSCORRUPTED; } xfs_trans_buf_set_type(tp, *bpp, type); } return err; } /*======================================================================== * Routines used for growing the Btree. *========================================================================*/ /* * Create the initial contents of an intermediate node. */ int xfs_da3_node_create( struct xfs_da_args *args, xfs_dablk_t blkno, int level, struct xfs_buf **bpp, int whichfork) { struct xfs_da_intnode *node; struct xfs_trans *tp = args->trans; struct xfs_mount *mp = tp->t_mountp; struct xfs_da3_icnode_hdr ichdr = {0}; struct xfs_buf *bp; int error; struct xfs_inode *dp = args->dp; trace_xfs_da_node_create(args); ASSERT(level <= XFS_DA_NODE_MAXDEPTH); error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, whichfork); if (error) return error; bp->b_ops = &xfs_da3_node_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); node = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_node_hdr *hdr3 = bp->b_addr; memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr)); ichdr.magic = XFS_DA3_NODE_MAGIC; hdr3->info.blkno = cpu_to_be64(bp->b_bn); hdr3->info.owner = cpu_to_be64(args->dp->i_ino); uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid); } else { ichdr.magic = XFS_DA_NODE_MAGIC; } ichdr.level = level; dp->d_ops->node_hdr_to_disk(node, &ichdr); xfs_trans_log_buf(tp, bp, XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); *bpp = bp; return 0; } /* * Split a leaf node, rebalance, then possibly split * intermediate nodes, rebalance, etc. */ int /* error */ xfs_da3_split( struct xfs_da_state *state) { struct xfs_da_state_blk *oldblk; struct xfs_da_state_blk *newblk; struct xfs_da_state_blk *addblk; struct xfs_da_intnode *node; int max; int action = 0; int error; int i; trace_xfs_da_split(state->args); /* * Walk back up the tree splitting/inserting/adjusting as necessary. * If we need to insert and there isn't room, split the node, then * decide which fragment to insert the new block from below into. * Note that we may split the root this way, but we need more fixup. */ max = state->path.active - 1; ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC); addblk = &state->path.blk[max]; /* initial dummy value */ for (i = max; (i >= 0) && addblk; state->path.active--, i--) { oldblk = &state->path.blk[i]; newblk = &state->altpath.blk[i]; /* * If a leaf node then * Allocate a new leaf node, then rebalance across them. * else if an intermediate node then * We split on the last layer, must we split the node? */ switch (oldblk->magic) { case XFS_ATTR_LEAF_MAGIC: error = xfs_attr3_leaf_split(state, oldblk, newblk); if ((error != 0) && (error != -ENOSPC)) { return error; /* GROT: attr is inconsistent */ } if (!error) { addblk = newblk; break; } /* * Entry wouldn't fit, split the leaf again. The new * extrablk will be consumed by xfs_da3_node_split if * the node is split. */ state->extravalid = 1; if (state->inleaf) { state->extraafter = 0; /* before newblk */ trace_xfs_attr_leaf_split_before(state->args); error = xfs_attr3_leaf_split(state, oldblk, &state->extrablk); } else { state->extraafter = 1; /* after newblk */ trace_xfs_attr_leaf_split_after(state->args); error = xfs_attr3_leaf_split(state, newblk, &state->extrablk); } if (error) return error; /* GROT: attr inconsistent */ addblk = newblk; break; case XFS_DIR2_LEAFN_MAGIC: error = xfs_dir2_leafn_split(state, oldblk, newblk); if (error) return error; addblk = newblk; break; case XFS_DA_NODE_MAGIC: error = xfs_da3_node_split(state, oldblk, newblk, addblk, max - i, &action); addblk->bp = NULL; if (error) return error; /* GROT: dir is inconsistent */ /* * Record the newly split block for the next time thru? */ if (action) addblk = newblk; else addblk = NULL; break; } /* * Update the btree to show the new hashval for this child. */ xfs_da3_fixhashpath(state, &state->path); } if (!addblk) return 0; /* * xfs_da3_node_split() should have consumed any extra blocks we added * during a double leaf split in the attr fork. This is guaranteed as * we can't be here if the attr fork only has a single leaf block. */ ASSERT(state->extravalid == 0 || state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC); /* * Split the root node. */ ASSERT(state->path.active == 0); oldblk = &state->path.blk[0]; error = xfs_da3_root_split(state, oldblk, addblk); if (error) goto out; /* * Update pointers to the node which used to be block 0 and just got * bumped because of the addition of a new root node. Note that the * original block 0 could be at any position in the list of blocks in * the tree. * * Note: the magic numbers and sibling pointers are in the same physical * place for both v2 and v3 headers (by design). Hence it doesn't matter * which version of the xfs_da_intnode structure we use here as the * result will be the same using either structure. */ node = oldblk->bp->b_addr; if (node->hdr.info.forw) { if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) { error = -EFSCORRUPTED; goto out; } node = addblk->bp->b_addr; node->hdr.info.back = cpu_to_be32(oldblk->blkno); xfs_trans_log_buf(state->args->trans, addblk->bp, XFS_DA_LOGRANGE(node, &node->hdr.info, sizeof(node->hdr.info))); } node = oldblk->bp->b_addr; if (node->hdr.info.back) { if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) { error = -EFSCORRUPTED; goto out; } node = addblk->bp->b_addr; node->hdr.info.forw = cpu_to_be32(oldblk->blkno); xfs_trans_log_buf(state->args->trans, addblk->bp, XFS_DA_LOGRANGE(node, &node->hdr.info, sizeof(node->hdr.info))); } out: addblk->bp = NULL; return error; } /* * Split the root. We have to create a new root and point to the two * parts (the split old root) that we just created. Copy block zero to * the EOF, extending the inode in process. */ STATIC int /* error */ xfs_da3_root_split( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_da_state_blk *blk2) { struct xfs_da_intnode *node; struct xfs_da_intnode *oldroot; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_args *args; struct xfs_buf *bp; struct xfs_inode *dp; struct xfs_trans *tp; struct xfs_dir2_leaf *leaf; xfs_dablk_t blkno; int level; int error; int size; trace_xfs_da_root_split(state->args); /* * Copy the existing (incorrect) block from the root node position * to a free space somewhere. */ args = state->args; error = xfs_da_grow_inode(args, &blkno); if (error) return error; dp = args->dp; tp = args->trans; error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork); if (error) return error; node = bp->b_addr; oldroot = blk1->bp->b_addr; if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) { struct xfs_da3_icnode_hdr icnodehdr; dp->d_ops->node_hdr_from_disk(&icnodehdr, oldroot); btree = dp->d_ops->node_tree_p(oldroot); size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot); level = icnodehdr.level; /* * we are about to copy oldroot to bp, so set up the type * of bp while we know exactly what it will be. */ xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); } else { struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; leaf = (xfs_dir2_leaf_t *)oldroot; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); size = (int)((char *)&ents[leafhdr.count] - (char *)leaf); level = 0; /* * we are about to copy oldroot to bp, so set up the type * of bp while we know exactly what it will be. */ xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); } /* * we can copy most of the information in the node from one block to * another, but for CRC enabled headers we have to make sure that the * block specific identifiers are kept intact. We update the buffer * directly for this. */ memcpy(node, oldroot, size); if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { struct xfs_da3_intnode *node3 = (struct xfs_da3_intnode *)node; node3->hdr.info.blkno = cpu_to_be64(bp->b_bn); } xfs_trans_log_buf(tp, bp, 0, size - 1); bp->b_ops = blk1->bp->b_ops; xfs_trans_buf_copy_type(bp, blk1->bp); blk1->bp = bp; blk1->blkno = blkno; /* * Set up the new root node. */ error = xfs_da3_node_create(args, (args->whichfork == XFS_DATA_FORK) ? args->geo->leafblk : 0, level + 1, &bp, args->whichfork); if (error) return error; node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); btree[0].hashval = cpu_to_be32(blk1->hashval); btree[0].before = cpu_to_be32(blk1->blkno); btree[1].hashval = cpu_to_be32(blk2->hashval); btree[1].before = cpu_to_be32(blk2->blkno); nodehdr.count = 2; dp->d_ops->node_hdr_to_disk(node, &nodehdr); #ifdef DEBUG if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { ASSERT(blk1->blkno >= args->geo->leafblk && blk1->blkno < args->geo->freeblk); ASSERT(blk2->blkno >= args->geo->leafblk && blk2->blkno < args->geo->freeblk); } #endif /* Header is already logged by xfs_da_node_create */ xfs_trans_log_buf(tp, bp, XFS_DA_LOGRANGE(node, btree, sizeof(xfs_da_node_entry_t) * 2)); return 0; } /* * Split the node, rebalance, then add the new entry. */ STATIC int /* error */ xfs_da3_node_split( struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk, struct xfs_da_state_blk *addblk, int treelevel, int *result) { struct xfs_da_intnode *node; struct xfs_da3_icnode_hdr nodehdr; xfs_dablk_t blkno; int newcount; int error; int useextra; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_split(state->args); node = oldblk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); /* * With V2 dirs the extra block is data or freespace. */ useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK; newcount = 1 + useextra; /* * Do we have to split the node? */ if (nodehdr.count + newcount > state->args->geo->node_ents) { /* * Allocate a new node, add to the doubly linked chain of * nodes, then move some of our excess entries into it. */ error = xfs_da_grow_inode(state->args, &blkno); if (error) return error; /* GROT: dir is inconsistent */ error = xfs_da3_node_create(state->args, blkno, treelevel, &newblk->bp, state->args->whichfork); if (error) return error; /* GROT: dir is inconsistent */ newblk->blkno = blkno; newblk->magic = XFS_DA_NODE_MAGIC; xfs_da3_node_rebalance(state, oldblk, newblk); error = xfs_da3_blk_link(state, oldblk, newblk); if (error) return error; *result = 1; } else { *result = 0; } /* * Insert the new entry(s) into the correct block * (updating last hashval in the process). * * xfs_da3_node_add() inserts BEFORE the given index, * and as a result of using node_lookup_int() we always * point to a valid entry (not after one), but a split * operation always results in a new block whose hashvals * FOLLOW the current block. * * If we had double-split op below us, then add the extra block too. */ node = oldblk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); if (oldblk->index <= nodehdr.count) { oldblk->index++; xfs_da3_node_add(state, oldblk, addblk); if (useextra) { if (state->extraafter) oldblk->index++; xfs_da3_node_add(state, oldblk, &state->extrablk); state->extravalid = 0; } } else { newblk->index++; xfs_da3_node_add(state, newblk, addblk); if (useextra) { if (state->extraafter) newblk->index++; xfs_da3_node_add(state, newblk, &state->extrablk); state->extravalid = 0; } } return 0; } /* * Balance the btree elements between two intermediate nodes, * usually one full and one empty. * * NOTE: if blk2 is empty, then it will get the upper half of blk1. */ STATIC void xfs_da3_node_rebalance( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_da_state_blk *blk2) { struct xfs_da_intnode *node1; struct xfs_da_intnode *node2; struct xfs_da_intnode *tmpnode; struct xfs_da_node_entry *btree1; struct xfs_da_node_entry *btree2; struct xfs_da_node_entry *btree_s; struct xfs_da_node_entry *btree_d; struct xfs_da3_icnode_hdr nodehdr1; struct xfs_da3_icnode_hdr nodehdr2; struct xfs_trans *tp; int count; int tmp; int swap = 0; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_rebalance(state->args); node1 = blk1->bp->b_addr; node2 = blk2->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); /* * Figure out how many entries need to move, and in which direction. * Swap the nodes around if that makes it simpler. */ if (nodehdr1.count > 0 && nodehdr2.count > 0 && ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) || (be32_to_cpu(btree2[nodehdr2.count - 1].hashval) < be32_to_cpu(btree1[nodehdr1.count - 1].hashval)))) { tmpnode = node1; node1 = node2; node2 = tmpnode; dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); swap = 1; } count = (nodehdr1.count - nodehdr2.count) / 2; if (count == 0) return; tp = state->args->trans; /* * Two cases: high-to-low and low-to-high. */ if (count > 0) { /* * Move elements in node2 up to make a hole. */ tmp = nodehdr2.count; if (tmp > 0) { tmp *= (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree2[0]; btree_d = &btree2[count]; memmove(btree_d, btree_s, tmp); } /* * Move the req'd B-tree elements from high in node1 to * low in node2. */ nodehdr2.count += count; tmp = count * (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree1[nodehdr1.count - count]; btree_d = &btree2[0]; memcpy(btree_d, btree_s, tmp); nodehdr1.count -= count; } else { /* * Move the req'd B-tree elements from low in node2 to * high in node1. */ count = -count; tmp = count * (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree2[0]; btree_d = &btree1[nodehdr1.count]; memcpy(btree_d, btree_s, tmp); nodehdr1.count += count; xfs_trans_log_buf(tp, blk1->bp, XFS_DA_LOGRANGE(node1, btree_d, tmp)); /* * Move elements in node2 down to fill the hole. */ tmp = nodehdr2.count - count; tmp *= (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree2[count]; btree_d = &btree2[0]; memmove(btree_d, btree_s, tmp); nodehdr2.count -= count; } /* * Log header of node 1 and all current bits of node 2. */ dp->d_ops->node_hdr_to_disk(node1, &nodehdr1); xfs_trans_log_buf(tp, blk1->bp, XFS_DA_LOGRANGE(node1, &node1->hdr, dp->d_ops->node_hdr_size)); dp->d_ops->node_hdr_to_disk(node2, &nodehdr2); xfs_trans_log_buf(tp, blk2->bp, XFS_DA_LOGRANGE(node2, &node2->hdr, dp->d_ops->node_hdr_size + (sizeof(btree2[0]) * nodehdr2.count))); /* * Record the last hashval from each block for upward propagation. * (note: don't use the swapped node pointers) */ if (swap) { node1 = blk1->bp->b_addr; node2 = blk2->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); } blk1->hashval = be32_to_cpu(btree1[nodehdr1.count - 1].hashval); blk2->hashval = be32_to_cpu(btree2[nodehdr2.count - 1].hashval); /* * Adjust the expected index for insertion. */ if (blk1->index >= nodehdr1.count) { blk2->index = blk1->index - nodehdr1.count; blk1->index = nodehdr1.count + 1; /* make it invalid */ } } /* * Add a new entry to an intermediate node. */ STATIC void xfs_da3_node_add( struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk) { struct xfs_da_intnode *node; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_node_entry *btree; int tmp; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_add(state->args); node = oldblk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count); ASSERT(newblk->blkno != 0); if (state->args->whichfork == XFS_DATA_FORK) ASSERT(newblk->blkno >= state->args->geo->leafblk && newblk->blkno < state->args->geo->freeblk); /* * We may need to make some room before we insert the new node. */ tmp = 0; if (oldblk->index < nodehdr.count) { tmp = (nodehdr.count - oldblk->index) * (uint)sizeof(*btree); memmove(&btree[oldblk->index + 1], &btree[oldblk->index], tmp); } btree[oldblk->index].hashval = cpu_to_be32(newblk->hashval); btree[oldblk->index].before = cpu_to_be32(newblk->blkno); xfs_trans_log_buf(state->args->trans, oldblk->bp, XFS_DA_LOGRANGE(node, &btree[oldblk->index], tmp + sizeof(*btree))); nodehdr.count += 1; dp->d_ops->node_hdr_to_disk(node, &nodehdr); xfs_trans_log_buf(state->args->trans, oldblk->bp, XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); /* * Copy the last hash value from the oldblk to propagate upwards. */ oldblk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval); } /*======================================================================== * Routines used for shrinking the Btree. *========================================================================*/ /* * Deallocate an empty leaf node, remove it from its parent, * possibly deallocating that block, etc... */ int xfs_da3_join( struct xfs_da_state *state) { struct xfs_da_state_blk *drop_blk; struct xfs_da_state_blk *save_blk; int action = 0; int error; trace_xfs_da_join(state->args); drop_blk = &state->path.blk[ state->path.active-1 ]; save_blk = &state->altpath.blk[ state->path.active-1 ]; ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); /* * Walk back up the tree joining/deallocating as necessary. * When we stop dropping blocks, break out. */ for ( ; state->path.active >= 2; drop_blk--, save_blk--, state->path.active--) { /* * See if we can combine the block with a neighbor. * (action == 0) => no options, just leave * (action == 1) => coalesce, then unlink * (action == 2) => block empty, unlink it */ switch (drop_blk->magic) { case XFS_ATTR_LEAF_MAGIC: error = xfs_attr3_leaf_toosmall(state, &action); if (error) return error; if (action == 0) return 0; xfs_attr3_leaf_unbalance(state, drop_blk, save_blk); break; case XFS_DIR2_LEAFN_MAGIC: error = xfs_dir2_leafn_toosmall(state, &action); if (error) return error; if (action == 0) return 0; xfs_dir2_leafn_unbalance(state, drop_blk, save_blk); break; case XFS_DA_NODE_MAGIC: /* * Remove the offending node, fixup hashvals, * check for a toosmall neighbor. */ xfs_da3_node_remove(state, drop_blk); xfs_da3_fixhashpath(state, &state->path); error = xfs_da3_node_toosmall(state, &action); if (error) return error; if (action == 0) return 0; xfs_da3_node_unbalance(state, drop_blk, save_blk); break; } xfs_da3_fixhashpath(state, &state->altpath); error = xfs_da3_blk_unlink(state, drop_blk, save_blk); xfs_da_state_kill_altpath(state); if (error) return error; error = xfs_da_shrink_inode(state->args, drop_blk->blkno, drop_blk->bp); drop_blk->bp = NULL; if (error) return error; } /* * We joined all the way to the top. If it turns out that * we only have one entry in the root, make the child block * the new root. */ xfs_da3_node_remove(state, drop_blk); xfs_da3_fixhashpath(state, &state->path); error = xfs_da3_root_join(state, &state->path.blk[0]); return error; } #ifdef DEBUG static void xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level) { __be16 magic = blkinfo->magic; if (level == 1) { ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) || magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); } else { ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); } ASSERT(!blkinfo->forw); ASSERT(!blkinfo->back); } #else /* !DEBUG */ #define xfs_da_blkinfo_onlychild_validate(blkinfo, level) #endif /* !DEBUG */ /* * We have only one entry in the root. Copy the only remaining child of * the old root to block 0 as the new root node. */ STATIC int xfs_da3_root_join( struct xfs_da_state *state, struct xfs_da_state_blk *root_blk) { struct xfs_da_intnode *oldroot; struct xfs_da_args *args; xfs_dablk_t child; struct xfs_buf *bp; struct xfs_da3_icnode_hdr oldroothdr; struct xfs_da_node_entry *btree; int error; struct xfs_inode *dp = state->args->dp; trace_xfs_da_root_join(state->args); ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC); args = state->args; oldroot = root_blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&oldroothdr, oldroot); ASSERT(oldroothdr.forw == 0); ASSERT(oldroothdr.back == 0); /* * If the root has more than one child, then don't do anything. */ if (oldroothdr.count > 1) return 0; /* * Read in the (only) child block, then copy those bytes into * the root block's buffer and free the original child block. */ btree = dp->d_ops->node_tree_p(oldroot); child = be32_to_cpu(btree[0].before); ASSERT(child != 0); error = xfs_da3_node_read(args->trans, dp, child, -1, &bp, args->whichfork); if (error) return error; xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level); /* * This could be copying a leaf back into the root block in the case of * there only being a single leaf block left in the tree. Hence we have * to update the b_ops pointer as well to match the buffer type change * that could occur. For dir3 blocks we also need to update the block * number in the buffer header. */ memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize); root_blk->bp->b_ops = bp->b_ops; xfs_trans_buf_copy_type(root_blk->bp, bp); if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) { struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr; da3->blkno = cpu_to_be64(root_blk->bp->b_bn); } xfs_trans_log_buf(args->trans, root_blk->bp, 0, args->geo->blksize - 1); error = xfs_da_shrink_inode(args, child, bp); return error; } /* * Check a node block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. */ STATIC int xfs_da3_node_toosmall( struct xfs_da_state *state, int *action) { struct xfs_da_intnode *node; struct xfs_da_state_blk *blk; struct xfs_da_blkinfo *info; xfs_dablk_t blkno; struct xfs_buf *bp; struct xfs_da3_icnode_hdr nodehdr; int count; int forward; int error; int retval; int i; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_toosmall(state->args); /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[ state->path.active-1 ]; info = blk->bp->b_addr; node = (xfs_da_intnode_t *)info; dp->d_ops->node_hdr_from_disk(&nodehdr, node); if (nodehdr.count > (state->args->geo->node_ents >> 1)) { *action = 0; /* blk over 50%, don't try to join */ return 0; /* blk over 50%, don't try to join */ } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (arbitrarily) * to merge with the forward block unless it is NULL. */ if (nodehdr.count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (info->forw != 0); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); if (error) return error; if (retval) { *action = 0; } else { *action = 2; } return 0; } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink a directory over time. */ count = state->args->geo->node_ents; count -= state->args->geo->node_ents >> 2; count -= nodehdr.count; /* start with smaller blk num */ forward = nodehdr.forw < nodehdr.back; for (i = 0; i < 2; forward = !forward, i++) { struct xfs_da3_icnode_hdr thdr; if (forward) blkno = nodehdr.forw; else blkno = nodehdr.back; if (blkno == 0) continue; error = xfs_da3_node_read(state->args->trans, dp, blkno, -1, &bp, state->args->whichfork); if (error) return error; node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&thdr, node); xfs_trans_brelse(state->args->trans, bp); if (count - thdr.count >= 0) break; /* fits with at least 25% to spare */ } if (i >= 2) { *action = 0; return 0; } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) { error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); } else { error = xfs_da3_path_shift(state, &state->path, forward, 0, &retval); } if (error) return error; if (retval) { *action = 0; return 0; } *action = 1; return 0; } /* * Pick up the last hashvalue from an intermediate node. */ STATIC uint xfs_da3_node_lasthash( struct xfs_inode *dp, struct xfs_buf *bp, int *count) { struct xfs_da_intnode *node; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); if (count) *count = nodehdr.count; if (!nodehdr.count) return 0; btree = dp->d_ops->node_tree_p(node); return be32_to_cpu(btree[nodehdr.count - 1].hashval); } /* * Walk back up the tree adjusting hash values as necessary, * when we stop making changes, return. */ void xfs_da3_fixhashpath( struct xfs_da_state *state, struct xfs_da_state_path *path) { struct xfs_da_state_blk *blk; struct xfs_da_intnode *node; struct xfs_da_node_entry *btree; xfs_dahash_t lasthash=0; int level; int count; struct xfs_inode *dp = state->args->dp; trace_xfs_da_fixhashpath(state->args); level = path->active-1; blk = &path->blk[ level ]; switch (blk->magic) { case XFS_ATTR_LEAF_MAGIC: lasthash = xfs_attr_leaf_lasthash(blk->bp, &count); if (count == 0) return; break; case XFS_DIR2_LEAFN_MAGIC: lasthash = xfs_dir2_leaf_lasthash(dp, blk->bp, &count); if (count == 0) return; break; case XFS_DA_NODE_MAGIC: lasthash = xfs_da3_node_lasthash(dp, blk->bp, &count); if (count == 0) return; break; } for (blk--, level--; level >= 0; blk--, level--) { struct xfs_da3_icnode_hdr nodehdr; node = blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); if (be32_to_cpu(btree[blk->index].hashval) == lasthash) break; blk->hashval = lasthash; btree[blk->index].hashval = cpu_to_be32(lasthash); xfs_trans_log_buf(state->args->trans, blk->bp, XFS_DA_LOGRANGE(node, &btree[blk->index], sizeof(*btree))); lasthash = be32_to_cpu(btree[nodehdr.count - 1].hashval); } } /* * Remove an entry from an intermediate node. */ STATIC void xfs_da3_node_remove( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk) { struct xfs_da_intnode *node; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_node_entry *btree; int index; int tmp; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_remove(state->args); node = drop_blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); ASSERT(drop_blk->index < nodehdr.count); ASSERT(drop_blk->index >= 0); /* * Copy over the offending entry, or just zero it out. */ index = drop_blk->index; btree = dp->d_ops->node_tree_p(node); if (index < nodehdr.count - 1) { tmp = nodehdr.count - index - 1; tmp *= (uint)sizeof(xfs_da_node_entry_t); memmove(&btree[index], &btree[index + 1], tmp); xfs_trans_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &btree[index], tmp)); index = nodehdr.count - 1; } memset(&btree[index], 0, sizeof(xfs_da_node_entry_t)); xfs_trans_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index]))); nodehdr.count -= 1; dp->d_ops->node_hdr_to_disk(node, &nodehdr); xfs_trans_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); /* * Copy the last hash value from the block to propagate upwards. */ drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval); } /* * Unbalance the elements between two intermediate nodes, * move all Btree elements from one node into another. */ STATIC void xfs_da3_node_unbalance( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk) { struct xfs_da_intnode *drop_node; struct xfs_da_intnode *save_node; struct xfs_da_node_entry *drop_btree; struct xfs_da_node_entry *save_btree; struct xfs_da3_icnode_hdr drop_hdr; struct xfs_da3_icnode_hdr save_hdr; struct xfs_trans *tp; int sindex; int tmp; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_unbalance(state->args); drop_node = drop_blk->bp->b_addr; save_node = save_blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&drop_hdr, drop_node); dp->d_ops->node_hdr_from_disk(&save_hdr, save_node); drop_btree = dp->d_ops->node_tree_p(drop_node); save_btree = dp->d_ops->node_tree_p(save_node); tp = state->args->trans; /* * If the dying block has lower hashvals, then move all the * elements in the remaining block up to make a hole. */ if ((be32_to_cpu(drop_btree[0].hashval) < be32_to_cpu(save_btree[0].hashval)) || (be32_to_cpu(drop_btree[drop_hdr.count - 1].hashval) < be32_to_cpu(save_btree[save_hdr.count - 1].hashval))) { /* XXX: check this - is memmove dst correct? */ tmp = save_hdr.count * sizeof(xfs_da_node_entry_t); memmove(&save_btree[drop_hdr.count], &save_btree[0], tmp); sindex = 0; xfs_trans_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_btree[0], (save_hdr.count + drop_hdr.count) * sizeof(xfs_da_node_entry_t))); } else { sindex = save_hdr.count; xfs_trans_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_btree[sindex], drop_hdr.count * sizeof(xfs_da_node_entry_t))); } /* * Move all the B-tree elements from drop_blk to save_blk. */ tmp = drop_hdr.count * (uint)sizeof(xfs_da_node_entry_t); memcpy(&save_btree[sindex], &drop_btree[0], tmp); save_hdr.count += drop_hdr.count; dp->d_ops->node_hdr_to_disk(save_node, &save_hdr); xfs_trans_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_node->hdr, dp->d_ops->node_hdr_size)); /* * Save the last hashval in the remaining block for upward propagation. */ save_blk->hashval = be32_to_cpu(save_btree[save_hdr.count - 1].hashval); } /*======================================================================== * Routines used for finding things in the Btree. *========================================================================*/ /* * Walk down the Btree looking for a particular filename, filling * in the state structure as we go. * * We will set the state structure to point to each of the elements * in each of the nodes where either the hashval is or should be. * * We support duplicate hashval's so for each entry in the current * node that could contain the desired hashval, descend. This is a * pruned depth-first tree search. */ int /* error */ xfs_da3_node_lookup_int( struct xfs_da_state *state, int *result) { struct xfs_da_state_blk *blk; struct xfs_da_blkinfo *curr; struct xfs_da_intnode *node; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_args *args; xfs_dablk_t blkno; xfs_dahash_t hashval; xfs_dahash_t btreehashval; int probe; int span; int max; int error; int retval; unsigned int expected_level = 0; uint16_t magic; struct xfs_inode *dp = state->args->dp; args = state->args; /* * Descend thru the B-tree searching each level for the right * node to use, until the right hashval is found. */ blkno = args->geo->leafblk; for (blk = &state->path.blk[0], state->path.active = 1; state->path.active <= XFS_DA_NODE_MAXDEPTH; blk++, state->path.active++) { /* * Read the next node down in the tree. */ blk->blkno = blkno; error = xfs_da3_node_read(args->trans, args->dp, blkno, -1, &blk->bp, args->whichfork); if (error) { blk->blkno = 0; state->path.active--; return error; } curr = blk->bp->b_addr; magic = be16_to_cpu(curr->magic); if (magic == XFS_ATTR_LEAF_MAGIC || magic == XFS_ATTR3_LEAF_MAGIC) { blk->magic = XFS_ATTR_LEAF_MAGIC; blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); break; } if (magic == XFS_DIR2_LEAFN_MAGIC || magic == XFS_DIR3_LEAFN_MAGIC) { blk->magic = XFS_DIR2_LEAFN_MAGIC; blk->hashval = xfs_dir2_leaf_lasthash(args->dp, blk->bp, NULL); break; } if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC) return -EFSCORRUPTED; blk->magic = XFS_DA_NODE_MAGIC; /* * Search an intermediate node for a match. */ node = blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); /* Tree taller than we can handle; bail out! */ if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) return -EFSCORRUPTED; /* Check the level from the root. */ if (blkno == args->geo->leafblk) expected_level = nodehdr.level - 1; else if (expected_level != nodehdr.level) return -EFSCORRUPTED; else expected_level--; max = nodehdr.count; blk->hashval = be32_to_cpu(btree[max - 1].hashval); /* * Binary search. (note: small blocks will skip loop) */ probe = span = max / 2; hashval = args->hashval; while (span > 4) { span /= 2; btreehashval = be32_to_cpu(btree[probe].hashval); if (btreehashval < hashval) probe += span; else if (btreehashval > hashval) probe -= span; else break; } ASSERT((probe >= 0) && (probe < max)); ASSERT((span <= 4) || (be32_to_cpu(btree[probe].hashval) == hashval)); /* * Since we may have duplicate hashval's, find the first * matching hashval in the node. */ while (probe > 0 && be32_to_cpu(btree[probe].hashval) >= hashval) { probe--; } while (probe < max && be32_to_cpu(btree[probe].hashval) < hashval) { probe++; } /* * Pick the right block to descend on. */ if (probe == max) { blk->index = max - 1; blkno = be32_to_cpu(btree[max - 1].before); } else { blk->index = probe; blkno = be32_to_cpu(btree[probe].before); } /* We can't point back to the root. */ if (blkno == args->geo->leafblk) return -EFSCORRUPTED; } if (expected_level != 0) return -EFSCORRUPTED; /* * A leaf block that ends in the hashval that we are interested in * (final hashval == search hashval) means that the next block may * contain more entries with the same hashval, shift upward to the * next leaf and keep searching. */ for (;;) { if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { retval = xfs_dir2_leafn_lookup_int(blk->bp, args, &blk->index, state); } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { retval = xfs_attr3_leaf_lookup_int(blk->bp, args); blk->index = args->index; args->blkno = blk->blkno; } else { ASSERT(0); return -EFSCORRUPTED; } if (((retval == -ENOENT) || (retval == -ENOATTR)) && (blk->hashval == args->hashval)) { error = xfs_da3_path_shift(state, &state->path, 1, 1, &retval); if (error) return error; if (retval == 0) { continue; } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { /* path_shift() gives ENOENT */ retval = -ENOATTR; } } break; } *result = retval; return 0; } /*======================================================================== * Utility routines. *========================================================================*/ /* * Compare two intermediate nodes for "order". */ STATIC int xfs_da3_node_order( struct xfs_inode *dp, struct xfs_buf *node1_bp, struct xfs_buf *node2_bp) { struct xfs_da_intnode *node1; struct xfs_da_intnode *node2; struct xfs_da_node_entry *btree1; struct xfs_da_node_entry *btree2; struct xfs_da3_icnode_hdr node1hdr; struct xfs_da3_icnode_hdr node2hdr; node1 = node1_bp->b_addr; node2 = node2_bp->b_addr; dp->d_ops->node_hdr_from_disk(&node1hdr, node1); dp->d_ops->node_hdr_from_disk(&node2hdr, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); if (node1hdr.count > 0 && node2hdr.count > 0 && ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) || (be32_to_cpu(btree2[node2hdr.count - 1].hashval) < be32_to_cpu(btree1[node1hdr.count - 1].hashval)))) { return 1; } return 0; } /* * Link a new block into a doubly linked list of blocks (of whatever type). */ int /* error */ xfs_da3_blk_link( struct xfs_da_state *state, struct xfs_da_state_blk *old_blk, struct xfs_da_state_blk *new_blk) { struct xfs_da_blkinfo *old_info; struct xfs_da_blkinfo *new_info; struct xfs_da_blkinfo *tmp_info; struct xfs_da_args *args; struct xfs_buf *bp; int before = 0; int error; struct xfs_inode *dp = state->args->dp; /* * Set up environment. */ args = state->args; ASSERT(args != NULL); old_info = old_blk->bp->b_addr; new_info = new_blk->bp->b_addr; ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || old_blk->magic == XFS_DIR2_LEAFN_MAGIC || old_blk->magic == XFS_ATTR_LEAF_MAGIC); switch (old_blk->magic) { case XFS_ATTR_LEAF_MAGIC: before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); break; case XFS_DIR2_LEAFN_MAGIC: before = xfs_dir2_leafn_order(dp, old_blk->bp, new_blk->bp); break; case XFS_DA_NODE_MAGIC: before = xfs_da3_node_order(dp, old_blk->bp, new_blk->bp); break; } /* * Link blocks in appropriate order. */ if (before) { /* * Link new block in before existing block. */ trace_xfs_da_link_before(args); new_info->forw = cpu_to_be32(old_blk->blkno); new_info->back = old_info->back; if (old_info->back) { error = xfs_da3_node_read(args->trans, dp, be32_to_cpu(old_info->back), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == old_info->magic); ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno); tmp_info->forw = cpu_to_be32(new_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); } old_info->back = cpu_to_be32(new_blk->blkno); } else { /* * Link new block in after existing block. */ trace_xfs_da_link_after(args); new_info->forw = old_info->forw; new_info->back = cpu_to_be32(old_blk->blkno); if (old_info->forw) { error = xfs_da3_node_read(args->trans, dp, be32_to_cpu(old_info->forw), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == old_info->magic); ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno); tmp_info->back = cpu_to_be32(new_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); } old_info->forw = cpu_to_be32(new_blk->blkno); } xfs_trans_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1); xfs_trans_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1); return 0; } /* * Unlink a block from a doubly linked list of blocks. */ STATIC int /* error */ xfs_da3_blk_unlink( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk) { struct xfs_da_blkinfo *drop_info; struct xfs_da_blkinfo *save_info; struct xfs_da_blkinfo *tmp_info; struct xfs_da_args *args; struct xfs_buf *bp; int error; /* * Set up environment. */ args = state->args; ASSERT(args != NULL); save_info = save_blk->bp->b_addr; drop_info = drop_blk->bp->b_addr; ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || save_blk->magic == XFS_DIR2_LEAFN_MAGIC || save_blk->magic == XFS_ATTR_LEAF_MAGIC); ASSERT(save_blk->magic == drop_blk->magic); ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) || (be32_to_cpu(save_info->back) == drop_blk->blkno)); ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) || (be32_to_cpu(drop_info->back) == save_blk->blkno)); /* * Unlink the leaf block from the doubly linked chain of leaves. */ if (be32_to_cpu(save_info->back) == drop_blk->blkno) { trace_xfs_da_unlink_back(args); save_info->back = drop_info->back; if (drop_info->back) { error = xfs_da3_node_read(args->trans, args->dp, be32_to_cpu(drop_info->back), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == save_info->magic); ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno); tmp_info->forw = cpu_to_be32(save_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info) - 1); } } else { trace_xfs_da_unlink_forward(args); save_info->forw = drop_info->forw; if (drop_info->forw) { error = xfs_da3_node_read(args->trans, args->dp, be32_to_cpu(drop_info->forw), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == save_info->magic); ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno); tmp_info->back = cpu_to_be32(save_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info) - 1); } } xfs_trans_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1); return 0; } /* * Move a path "forward" or "!forward" one block at the current level. * * This routine will adjust a "path" to point to the next block * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the * Btree, including updating pointers to the intermediate nodes between * the new bottom and the root. */ int /* error */ xfs_da3_path_shift( struct xfs_da_state *state, struct xfs_da_state_path *path, int forward, int release, int *result) { struct xfs_da_state_blk *blk; struct xfs_da_blkinfo *info; struct xfs_da_intnode *node; struct xfs_da_args *args; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; struct xfs_buf *bp; xfs_dablk_t blkno = 0; int level; int error; struct xfs_inode *dp = state->args->dp; trace_xfs_da_path_shift(state->args); /* * Roll up the Btree looking for the first block where our * current index is not at the edge of the block. Note that * we skip the bottom layer because we want the sibling block. */ args = state->args; ASSERT(args != NULL); ASSERT(path != NULL); ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); level = (path->active-1) - 1; /* skip bottom layer in path */ for (blk = &path->blk[level]; level >= 0; blk--, level--) { node = blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); if (forward && (blk->index < nodehdr.count - 1)) { blk->index++; blkno = be32_to_cpu(btree[blk->index].before); break; } else if (!forward && (blk->index > 0)) { blk->index--; blkno = be32_to_cpu(btree[blk->index].before); break; } } if (level < 0) { *result = -ENOENT; /* we're out of our tree */ ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); return 0; } /* * Roll down the edge of the subtree until we reach the * same depth we were at originally. */ for (blk++, level++; level < path->active; blk++, level++) { /* * Read the next child block into a local buffer. */ error = xfs_da3_node_read(args->trans, dp, blkno, -1, &bp, args->whichfork); if (error) return error; /* * Release the old block (if it's dirty, the trans doesn't * actually let go) and swap the local buffer into the path * structure. This ensures failure of the above read doesn't set * a NULL buffer in an active slot in the path. */ if (release) xfs_trans_brelse(args->trans, blk->bp); blk->blkno = blkno; blk->bp = bp; info = blk->bp->b_addr; ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || info->magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) || info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || info->magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); /* * Note: we flatten the magic number to a single type so we * don't have to compare against crc/non-crc types elsewhere. */ switch (be16_to_cpu(info->magic)) { case XFS_DA_NODE_MAGIC: case XFS_DA3_NODE_MAGIC: blk->magic = XFS_DA_NODE_MAGIC; node = (xfs_da_intnode_t *)info; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); blk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval); if (forward) blk->index = 0; else blk->index = nodehdr.count - 1; blkno = be32_to_cpu(btree[blk->index].before); break; case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: blk->magic = XFS_ATTR_LEAF_MAGIC; ASSERT(level == path->active-1); blk->index = 0; blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); break; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: blk->magic = XFS_DIR2_LEAFN_MAGIC; ASSERT(level == path->active-1); blk->index = 0; blk->hashval = xfs_dir2_leaf_lasthash(args->dp, blk->bp, NULL); break; default: ASSERT(0); break; } } *result = 0; return 0; } /*======================================================================== * Utility routines. *========================================================================*/ /* * Implement a simple hash on a character string. * Rotate the hash value by 7 bits, then XOR each character in. * This is implemented with some source-level loop unrolling. */ xfs_dahash_t xfs_da_hashname(const uint8_t *name, int namelen) { xfs_dahash_t hash; /* * Do four characters at a time as long as we can. */ for (hash = 0; namelen >= 4; namelen -= 4, name += 4) hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ (name[3] << 0) ^ rol32(hash, 7 * 4); /* * Now do the rest of the characters. */ switch (namelen) { case 3: return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ rol32(hash, 7 * 3); case 2: return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2); case 1: return (name[0] << 0) ^ rol32(hash, 7 * 1); default: /* case 0: */ return hash; } } enum xfs_dacmp xfs_da_compname( struct xfs_da_args *args, const unsigned char *name, int len) { return (args->namelen == len && memcmp(args->name, name, len) == 0) ? XFS_CMP_EXACT : XFS_CMP_DIFFERENT; } static xfs_dahash_t xfs_default_hashname( struct xfs_name *name) { return xfs_da_hashname(name->name, name->len); } const struct xfs_nameops xfs_default_nameops = { .hashname = xfs_default_hashname, .compname = xfs_da_compname }; int xfs_da_grow_inode_int( struct xfs_da_args *args, xfs_fileoff_t *bno, int count) { struct xfs_trans *tp = args->trans; struct xfs_inode *dp = args->dp; int w = args->whichfork; xfs_rfsblock_t nblks = dp->i_d.di_nblocks; struct xfs_bmbt_irec map, *mapp; int nmap, error, got, i, mapi; /* * Find a spot in the file space to put the new block. */ error = xfs_bmap_first_unused(tp, dp, count, bno, w); if (error) return error; /* * Try mapping it in one filesystem block. */ nmap = 1; error = xfs_bmapi_write(tp, dp, *bno, count, xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, args->total, &map, &nmap); if (error) return error; ASSERT(nmap <= 1); if (nmap == 1) { mapp = ↦ mapi = 1; } else if (nmap == 0 && count > 1) { xfs_fileoff_t b; int c; /* * If we didn't get it and the block might work if fragmented, * try without the CONTIG flag. Loop until we get it all. */ mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); for (b = *bno, mapi = 0; b < *bno + count; ) { nmap = min(XFS_BMAP_MAX_NMAP, count); c = (int)(*bno + count - b); error = xfs_bmapi_write(tp, dp, b, c, xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA, args->total, &mapp[mapi], &nmap); if (error) goto out_free_map; if (nmap < 1) break; mapi += nmap; b = mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount; } } else { mapi = 0; mapp = NULL; } /* * Count the blocks we got, make sure it matches the total. */ for (i = 0, got = 0; i < mapi; i++) got += mapp[i].br_blockcount; if (got != count || mapp[0].br_startoff != *bno || mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != *bno + count) { error = -ENOSPC; goto out_free_map; } /* account for newly allocated blocks in reserved blocks total */ args->total -= dp->i_d.di_nblocks - nblks; out_free_map: if (mapp != &map) kmem_free(mapp); return error; } /* * Add a block to the btree ahead of the file. * Return the new block number to the caller. */ int xfs_da_grow_inode( struct xfs_da_args *args, xfs_dablk_t *new_blkno) { xfs_fileoff_t bno; int error; trace_xfs_da_grow_inode(args); bno = args->geo->leafblk; error = xfs_da_grow_inode_int(args, &bno, args->geo->fsbcount); if (!error) *new_blkno = (xfs_dablk_t)bno; return error; } /* * Ick. We need to always be able to remove a btree block, even * if there's no space reservation because the filesystem is full. * This is called if xfs_bunmapi on a btree block fails due to ENOSPC. * It swaps the target block with the last block in the file. The * last block in the file can always be removed since it can't cause * a bmap btree split to do that. */ STATIC int xfs_da3_swap_lastblock( struct xfs_da_args *args, xfs_dablk_t *dead_blknop, struct xfs_buf **dead_bufp) { struct xfs_da_blkinfo *dead_info; struct xfs_da_blkinfo *sib_info; struct xfs_da_intnode *par_node; struct xfs_da_intnode *dead_node; struct xfs_dir2_leaf *dead_leaf2; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr par_hdr; struct xfs_inode *dp; struct xfs_trans *tp; struct xfs_mount *mp; struct xfs_buf *dead_buf; struct xfs_buf *last_buf; struct xfs_buf *sib_buf; struct xfs_buf *par_buf; xfs_dahash_t dead_hash; xfs_fileoff_t lastoff; xfs_dablk_t dead_blkno; xfs_dablk_t last_blkno; xfs_dablk_t sib_blkno; xfs_dablk_t par_blkno; int error; int w; int entno; int level; int dead_level; trace_xfs_da_swap_lastblock(args); dead_buf = *dead_bufp; dead_blkno = *dead_blknop; tp = args->trans; dp = args->dp; w = args->whichfork; ASSERT(w == XFS_DATA_FORK); mp = dp->i_mount; lastoff = args->geo->freeblk; error = xfs_bmap_last_before(tp, dp, &lastoff, w); if (error) return error; if (unlikely(lastoff == 0)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(1)", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } /* * Read the last block in the btree space. */ last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount; error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w); if (error) return error; /* * Copy the last block into the dead buffer and log it. */ memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize); xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1); dead_info = dead_buf->b_addr; /* * Get values from the moved block. */ if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || dead_info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; dp->d_ops->leaf_hdr_from_disk(&leafhdr, dead_leaf2); ents = dp->d_ops->leaf_ents_p(dead_leaf2); dead_level = 0; dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval); } else { struct xfs_da3_icnode_hdr deadhdr; dead_node = (xfs_da_intnode_t *)dead_info; dp->d_ops->node_hdr_from_disk(&deadhdr, dead_node); btree = dp->d_ops->node_tree_p(dead_node); dead_level = deadhdr.level; dead_hash = be32_to_cpu(btree[deadhdr.count - 1].hashval); } sib_buf = par_buf = NULL; /* * If the moved block has a left sibling, fix up the pointers. */ if ((sib_blkno = be32_to_cpu(dead_info->back))) { error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w); if (error) goto done; sib_info = sib_buf->b_addr; if (unlikely( be32_to_cpu(sib_info->forw) != last_blkno || sib_info->magic != dead_info->magic)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(2)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } sib_info->forw = cpu_to_be32(dead_blkno); xfs_trans_log_buf(tp, sib_buf, XFS_DA_LOGRANGE(sib_info, &sib_info->forw, sizeof(sib_info->forw))); sib_buf = NULL; } /* * If the moved block has a right sibling, fix up the pointers. */ if ((sib_blkno = be32_to_cpu(dead_info->forw))) { error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w); if (error) goto done; sib_info = sib_buf->b_addr; if (unlikely( be32_to_cpu(sib_info->back) != last_blkno || sib_info->magic != dead_info->magic)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(3)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } sib_info->back = cpu_to_be32(dead_blkno); xfs_trans_log_buf(tp, sib_buf, XFS_DA_LOGRANGE(sib_info, &sib_info->back, sizeof(sib_info->back))); sib_buf = NULL; } par_blkno = args->geo->leafblk; level = -1; /* * Walk down the tree looking for the parent of the moved block. */ for (;;) { error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w); if (error) goto done; par_node = par_buf->b_addr; dp->d_ops->node_hdr_from_disk(&par_hdr, par_node); if (level >= 0 && level != par_hdr.level + 1) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(4)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } level = par_hdr.level; btree = dp->d_ops->node_tree_p(par_node); for (entno = 0; entno < par_hdr.count && be32_to_cpu(btree[entno].hashval) < dead_hash; entno++) continue; if (entno == par_hdr.count) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(5)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } par_blkno = be32_to_cpu(btree[entno].before); if (level == dead_level + 1) break; xfs_trans_brelse(tp, par_buf); par_buf = NULL; } /* * We're in the right parent block. * Look for the right entry. */ for (;;) { for (; entno < par_hdr.count && be32_to_cpu(btree[entno].before) != last_blkno; entno++) continue; if (entno < par_hdr.count) break; par_blkno = par_hdr.forw; xfs_trans_brelse(tp, par_buf); par_buf = NULL; if (unlikely(par_blkno == 0)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(6)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w); if (error) goto done; par_node = par_buf->b_addr; dp->d_ops->node_hdr_from_disk(&par_hdr, par_node); if (par_hdr.level != level) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(7)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } btree = dp->d_ops->node_tree_p(par_node); entno = 0; } /* * Update the parent entry pointing to the moved block. */ btree[entno].before = cpu_to_be32(dead_blkno); xfs_trans_log_buf(tp, par_buf, XFS_DA_LOGRANGE(par_node, &btree[entno].before, sizeof(btree[entno].before))); *dead_blknop = last_blkno; *dead_bufp = last_buf; return 0; done: if (par_buf) xfs_trans_brelse(tp, par_buf); if (sib_buf) xfs_trans_brelse(tp, sib_buf); xfs_trans_brelse(tp, last_buf); return error; } /* * Remove a btree block from a directory or attribute. */ int xfs_da_shrink_inode( struct xfs_da_args *args, xfs_dablk_t dead_blkno, struct xfs_buf *dead_buf) { struct xfs_inode *dp; int done, error, w, count; struct xfs_trans *tp; trace_xfs_da_shrink_inode(args); dp = args->dp; w = args->whichfork; tp = args->trans; count = args->geo->fsbcount; for (;;) { /* * Remove extents. If we get ENOSPC for a dir we have to move * the last block to the place we want to kill. */ error = xfs_bunmapi(tp, dp, dead_blkno, count, xfs_bmapi_aflag(w), 0, &done); if (error == -ENOSPC) { if (w != XFS_DATA_FORK) break; error = xfs_da3_swap_lastblock(args, &dead_blkno, &dead_buf); if (error) break; } else { break; } } xfs_trans_binval(tp, dead_buf); return error; } /* * See if the mapping(s) for this btree block are valid, i.e. * don't contain holes, are logically contiguous, and cover the whole range. */ STATIC int xfs_da_map_covers_blocks( int nmap, xfs_bmbt_irec_t *mapp, xfs_dablk_t bno, int count) { int i; xfs_fileoff_t off; for (i = 0, off = bno; i < nmap; i++) { if (mapp[i].br_startblock == HOLESTARTBLOCK || mapp[i].br_startblock == DELAYSTARTBLOCK) { return 0; } if (off != mapp[i].br_startoff) { return 0; } off += mapp[i].br_blockcount; } return off == bno + count; } /* * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map. * * For the single map case, it is assumed that the caller has provided a pointer * to a valid xfs_buf_map. For the multiple map case, this function will * allocate the xfs_buf_map to hold all the maps and replace the caller's single * map pointer with the allocated map. */ static int xfs_buf_map_from_irec( struct xfs_mount *mp, struct xfs_buf_map **mapp, int *nmaps, struct xfs_bmbt_irec *irecs, int nirecs) { struct xfs_buf_map *map; int i; ASSERT(*nmaps == 1); ASSERT(nirecs >= 1); if (nirecs > 1) { map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), KM_SLEEP | KM_NOFS); if (!map) return -ENOMEM; *mapp = map; } *nmaps = nirecs; map = *mapp; for (i = 0; i < *nmaps; i++) { ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK && irecs[i].br_startblock != HOLESTARTBLOCK); map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock); map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount); } return 0; } /* * Map the block we are given ready for reading. There are three possible return * values: * -1 - will be returned if we land in a hole and mappedbno == -2 so the * caller knows not to execute a subsequent read. * 0 - if we mapped the block successfully * >0 - positive error number if there was an error. */ static int xfs_dabuf_map( struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, int whichfork, struct xfs_buf_map **map, int *nmaps) { struct xfs_mount *mp = dp->i_mount; int nfsb; int error = 0; struct xfs_bmbt_irec irec; struct xfs_bmbt_irec *irecs = &irec; int nirecs; ASSERT(map && *map); ASSERT(*nmaps == 1); if (whichfork == XFS_DATA_FORK) nfsb = mp->m_dir_geo->fsbcount; else nfsb = mp->m_attr_geo->fsbcount; /* * Caller doesn't have a mapping. -2 means don't complain * if we land in a hole. */ if (mappedbno == -1 || mappedbno == -2) { /* * Optimize the one-block case. */ if (nfsb != 1) irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP | KM_NOFS); nirecs = nfsb; error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs, &nirecs, xfs_bmapi_aflag(whichfork)); if (error) goto out; } else { irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); irecs->br_startoff = (xfs_fileoff_t)bno; irecs->br_blockcount = nfsb; irecs->br_state = 0; nirecs = 1; } if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) { error = mappedbno == -2 ? -1 : -EFSCORRUPTED; if (unlikely(error == -EFSCORRUPTED)) { if (xfs_error_level >= XFS_ERRLEVEL_LOW) { int i; xfs_alert(mp, "%s: bno %lld dir: inode %lld", __func__, (long long)bno, (long long)dp->i_ino); for (i = 0; i < *nmaps; i++) { xfs_alert(mp, "[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d", i, (long long)irecs[i].br_startoff, (long long)irecs[i].br_startblock, (long long)irecs[i].br_blockcount, irecs[i].br_state); } } XFS_ERROR_REPORT("xfs_da_do_buf(1)", XFS_ERRLEVEL_LOW, mp); } goto out; } error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs); out: if (irecs != &irec) kmem_free(irecs); return error; } /* * Get a buffer for the dir/attr block. */ int xfs_da_get_buf( struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork) { struct xfs_buf *bp; struct xfs_buf_map map; struct xfs_buf_map *mapp; int nmap; int error; *bpp = NULL; mapp = ↦ nmap = 1; error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ if (error == -1) error = 0; goto out_free; } bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp, mapp, nmap, 0); error = bp ? bp->b_error : -EIO; if (error) { if (bp) xfs_trans_brelse(trans, bp); goto out_free; } *bpp = bp; out_free: if (mapp != &map) kmem_free(mapp); return error; } /* * Get a buffer for the dir/attr block, fill in the contents. */ int xfs_da_read_buf( struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; struct xfs_buf_map map; struct xfs_buf_map *mapp; int nmap; int error; *bpp = NULL; mapp = ↦ nmap = 1; error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ if (error == -1) error = 0; goto out_free; } error = xfs_trans_read_buf_map(dp->i_mount, trans, dp->i_mount->m_ddev_targp, mapp, nmap, 0, &bp, ops); if (error) goto out_free; if (whichfork == XFS_ATTR_FORK) xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF); else xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF); *bpp = bp; out_free: if (mapp != &map) kmem_free(mapp); return error; } /* * Readahead the dir/attr block. */ int xfs_da_reada_buf( struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, int whichfork, const struct xfs_buf_ops *ops) { struct xfs_buf_map map; struct xfs_buf_map *mapp; int nmap; int error; mapp = ↦ nmap = 1; error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ if (error == -1) error = 0; goto out_free; } mappedbno = mapp[0].bm_bn; xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, ops); out_free: if (mapp != &map) kmem_free(mapp); return error; } xfsprogs-5.3.0/libxfs/xfs_da_btree.h0000644000175000017500000001672313435336036017350 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_DA_BTREE_H__ #define __XFS_DA_BTREE_H__ struct xfs_inode; struct xfs_trans; struct zone; struct xfs_dir_ops; /* * Directory/attribute geometry information. There will be one of these for each * data fork type, and it will be passed around via the xfs_da_args. Global * structures will be attached to the xfs_mount. */ struct xfs_da_geometry { int blksize; /* da block size in bytes */ int fsbcount; /* da block size in filesystem blocks */ uint8_t fsblog; /* log2 of _filesystem_ block size */ uint8_t blklog; /* log2 of da block size */ uint node_ents; /* # of entries in a danode */ int magicpct; /* 37% of block size in bytes */ xfs_dablk_t datablk; /* blockno of dir data v2 */ xfs_dablk_t leafblk; /* blockno of leaf data v2 */ xfs_dablk_t freeblk; /* blockno of free data v2 */ }; /*======================================================================== * Btree searching and modification structure definitions. *========================================================================*/ /* * Search comparison results */ enum xfs_dacmp { XFS_CMP_DIFFERENT, /* names are completely different */ XFS_CMP_EXACT, /* names are exactly the same */ XFS_CMP_CASE /* names are same but differ in case */ }; /* * Structure to ease passing around component names. */ typedef struct xfs_da_args { struct xfs_da_geometry *geo; /* da block geometry */ const uint8_t *name; /* string (maybe not NULL terminated) */ int namelen; /* length of string (maybe no NULL) */ uint8_t filetype; /* filetype of inode for directories */ uint8_t *value; /* set of bytes (maybe contain NULLs) */ int valuelen; /* length of value */ int flags; /* argument flags (eg: ATTR_NOCREATE) */ xfs_dahash_t hashval; /* hash value of name */ xfs_ino_t inumber; /* input/output inode number */ struct xfs_inode *dp; /* directory inode to manipulate */ struct xfs_trans *trans; /* current trans (changes over time) */ xfs_extlen_t total; /* total blocks needed, for 1st bmap */ int whichfork; /* data or attribute fork */ xfs_dablk_t blkno; /* blkno of attr leaf of interest */ int index; /* index of attr of interest in blk */ xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ int rmtblkcnt; /* remote attr value block count */ int rmtvaluelen; /* remote attr value length in bytes */ xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ int index2; /* index of 2nd attr in blk */ xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ int rmtblkcnt2; /* remote attr value block count */ int rmtvaluelen2; /* remote attr value length in bytes */ int op_flags; /* operation flags */ enum xfs_dacmp cmpresult; /* name compare result for lookups */ } xfs_da_args_t; /* * Operation flags: */ #define XFS_DA_OP_JUSTCHECK 0x0001 /* check for ok with no space */ #define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */ #define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */ #define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ #define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */ #define XFS_DA_OP_FLAGS \ { XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \ { XFS_DA_OP_RENAME, "RENAME" }, \ { XFS_DA_OP_ADDNAME, "ADDNAME" }, \ { XFS_DA_OP_OKNOENT, "OKNOENT" }, \ { XFS_DA_OP_CILOOKUP, "CILOOKUP" } /* * Storage for holding state during Btree searches and split/join ops. * * Only need space for 5 intermediate nodes. With a minimum of 62-way * fanout to the Btree, we can support over 900 million directory blocks, * which is slightly more than enough. */ typedef struct xfs_da_state_blk { struct xfs_buf *bp; /* buffer containing block */ xfs_dablk_t blkno; /* filesystem blkno of buffer */ xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */ int index; /* relevant index into block */ xfs_dahash_t hashval; /* last hash value in block */ int magic; /* blk's magic number, ie: blk type */ } xfs_da_state_blk_t; typedef struct xfs_da_state_path { int active; /* number of active levels */ xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH]; } xfs_da_state_path_t; typedef struct xfs_da_state { xfs_da_args_t *args; /* filename arguments */ struct xfs_mount *mp; /* filesystem mount point */ xfs_da_state_path_t path; /* search/split paths */ xfs_da_state_path_t altpath; /* alternate path for join */ unsigned char inleaf; /* insert into 1->lf, 0->splf */ unsigned char extravalid; /* T/F: extrablk is in use */ unsigned char extraafter; /* T/F: extrablk is after new */ xfs_da_state_blk_t extrablk; /* for double-splits on leaves */ /* for dirv2 extrablk is data */ } xfs_da_state_t; /* * Utility macros to aid in logging changed structure fields. */ #define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE)) #define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \ (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) /* * Name ops for directory and/or attr name operations */ struct xfs_nameops { xfs_dahash_t (*hashname)(struct xfs_name *); enum xfs_dacmp (*compname)(struct xfs_da_args *, const unsigned char *, int); }; /*======================================================================== * Function prototypes. *========================================================================*/ /* * Routines used for growing the Btree. */ int xfs_da3_node_create(struct xfs_da_args *args, xfs_dablk_t blkno, int level, struct xfs_buf **bpp, int whichfork); int xfs_da3_split(xfs_da_state_t *state); /* * Routines used for shrinking the Btree. */ int xfs_da3_join(xfs_da_state_t *state); void xfs_da3_fixhashpath(struct xfs_da_state *state, struct xfs_da_state_path *path_to_to_fix); /* * Routines used for finding things in the Btree. */ int xfs_da3_node_lookup_int(xfs_da_state_t *state, int *result); int xfs_da3_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, int forward, int release, int *result); /* * Utility routines. */ int xfs_da3_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, xfs_da_state_blk_t *new_blk); int xfs_da3_node_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int which_fork); /* * Utility routines. */ int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno); int xfs_da_grow_inode_int(struct xfs_da_args *args, xfs_fileoff_t *bno, int count); int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bp, int whichfork); int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork, const struct xfs_buf_ops *ops); int xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, int whichfork, const struct xfs_buf_ops *ops); int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, struct xfs_buf *dead_buf); uint xfs_da_hashname(const uint8_t *name_string, int name_length); enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, const unsigned char *name, int len); xfs_da_state_t *xfs_da_state_alloc(void); void xfs_da_state_free(xfs_da_state_t *state); extern struct kmem_zone *xfs_da_state_zone; extern const struct xfs_nameops xfs_default_nameops; #endif /* __XFS_DA_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_da_format.c0000644000175000017500000005632313570057155017534 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_dir2.h" /* * Shortform directory ops */ static int xfs_dir2_sf_entsize( struct xfs_dir2_sf_hdr *hdr, int len) { int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */ count += len; /* name */ count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */ return count; } static int xfs_dir3_sf_entsize( struct xfs_dir2_sf_hdr *hdr, int len) { return xfs_dir2_sf_entsize(hdr, len) + sizeof(uint8_t); } static struct xfs_dir2_sf_entry * xfs_dir2_sf_nextentry( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return (struct xfs_dir2_sf_entry *) ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen)); } static struct xfs_dir2_sf_entry * xfs_dir3_sf_nextentry( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return (struct xfs_dir2_sf_entry *) ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen)); } /* * For filetype enabled shortform directories, the file type field is stored at * the end of the name. Because it's only a single byte, endian conversion is * not necessary. For non-filetype enable directories, the type is always * unknown and we never store the value. */ static uint8_t xfs_dir2_sfe_get_ftype( struct xfs_dir2_sf_entry *sfep) { return XFS_DIR3_FT_UNKNOWN; } static void xfs_dir2_sfe_put_ftype( struct xfs_dir2_sf_entry *sfep, uint8_t ftype) { ASSERT(ftype < XFS_DIR3_FT_MAX); } static uint8_t xfs_dir3_sfe_get_ftype( struct xfs_dir2_sf_entry *sfep) { uint8_t ftype; ftype = sfep->name[sfep->namelen]; if (ftype >= XFS_DIR3_FT_MAX) return XFS_DIR3_FT_UNKNOWN; return ftype; } static void xfs_dir3_sfe_put_ftype( struct xfs_dir2_sf_entry *sfep, uint8_t ftype) { ASSERT(ftype < XFS_DIR3_FT_MAX); sfep->name[sfep->namelen] = ftype; } /* * Inode numbers in short-form directories can come in two versions, * either 4 bytes or 8 bytes wide. These helpers deal with the * two forms transparently by looking at the headers i8count field. * * For 64-bit inode number the most significant byte must be zero. */ static xfs_ino_t xfs_dir2_sf_get_ino( struct xfs_dir2_sf_hdr *hdr, uint8_t *from) { if (hdr->i8count) return get_unaligned_be64(from) & 0x00ffffffffffffffULL; else return get_unaligned_be32(from); } static void xfs_dir2_sf_put_ino( struct xfs_dir2_sf_hdr *hdr, uint8_t *to, xfs_ino_t ino) { ASSERT((ino & 0xff00000000000000ULL) == 0); if (hdr->i8count) put_unaligned_be64(ino, to); else put_unaligned_be32(ino, to); } static xfs_ino_t xfs_dir2_sf_get_parent_ino( struct xfs_dir2_sf_hdr *hdr) { return xfs_dir2_sf_get_ino(hdr, hdr->parent); } static void xfs_dir2_sf_put_parent_ino( struct xfs_dir2_sf_hdr *hdr, xfs_ino_t ino) { xfs_dir2_sf_put_ino(hdr, hdr->parent, ino); } /* * In short-form directory entries the inode numbers are stored at variable * offset behind the entry name. If the entry stores a filetype value, then it * sits between the name and the inode number. Hence the inode numbers may only * be accessed through the helpers below. */ static xfs_ino_t xfs_dir2_sfe_get_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen]); } static void xfs_dir2_sfe_put_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino) { xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen], ino); } static xfs_ino_t xfs_dir3_sfe_get_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen + 1]); } static void xfs_dir3_sfe_put_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino) { xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen + 1], ino); } /* * Directory data block operations */ /* * For special situations, the dirent size ends up fixed because we always know * what the size of the entry is. That's true for the "." and "..", and * therefore we know that they are a fixed size and hence their offsets are * constant, as is the first entry. * * Hence, this calculation is written as a macro to be able to be calculated at * compile time and so certain offsets can be calculated directly in the * structure initaliser via the macro. There are two macros - one for dirents * with ftype and without so there are no unresolvable conditionals in the * calculations. We also use round_up() as XFS_DIR2_DATA_ALIGN is always a power * of 2 and the compiler doesn't reject it (unlike roundup()). */ #define XFS_DIR2_DATA_ENTSIZE(n) \ round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ sizeof(xfs_dir2_data_off_t)), XFS_DIR2_DATA_ALIGN) #define XFS_DIR3_DATA_ENTSIZE(n) \ round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ sizeof(xfs_dir2_data_off_t) + sizeof(uint8_t)), \ XFS_DIR2_DATA_ALIGN) static int xfs_dir2_data_entsize( int n) { return XFS_DIR2_DATA_ENTSIZE(n); } static int xfs_dir3_data_entsize( int n) { return XFS_DIR3_DATA_ENTSIZE(n); } static uint8_t xfs_dir2_data_get_ftype( struct xfs_dir2_data_entry *dep) { return XFS_DIR3_FT_UNKNOWN; } static void xfs_dir2_data_put_ftype( struct xfs_dir2_data_entry *dep, uint8_t ftype) { ASSERT(ftype < XFS_DIR3_FT_MAX); } static uint8_t xfs_dir3_data_get_ftype( struct xfs_dir2_data_entry *dep) { uint8_t ftype = dep->name[dep->namelen]; if (ftype >= XFS_DIR3_FT_MAX) return XFS_DIR3_FT_UNKNOWN; return ftype; } static void xfs_dir3_data_put_ftype( struct xfs_dir2_data_entry *dep, uint8_t type) { ASSERT(type < XFS_DIR3_FT_MAX); ASSERT(dep->namelen != 0); dep->name[dep->namelen] = type; } /* * Pointer to an entry's tag word. */ static __be16 * xfs_dir2_data_entry_tag_p( struct xfs_dir2_data_entry *dep) { return (__be16 *)((char *)dep + xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); } static __be16 * xfs_dir3_data_entry_tag_p( struct xfs_dir2_data_entry *dep) { return (__be16 *)((char *)dep + xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16)); } /* * location of . and .. in data space (always block 0) */ static struct xfs_dir2_data_entry * xfs_dir2_data_dot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); } static struct xfs_dir2_data_entry * xfs_dir2_data_dotdot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1)); } static struct xfs_dir2_data_entry * xfs_dir2_data_first_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1) + XFS_DIR2_DATA_ENTSIZE(2)); } static struct xfs_dir2_data_entry * xfs_dir2_ftype_data_dotdot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1)); } static struct xfs_dir2_data_entry * xfs_dir2_ftype_data_first_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2)); } static struct xfs_dir2_data_entry * xfs_dir3_data_dot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); } static struct xfs_dir2_data_entry * xfs_dir3_data_dotdot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1)); } static struct xfs_dir2_data_entry * xfs_dir3_data_first_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2)); } static struct xfs_dir2_data_free * xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) { return hdr->bestfree; } static struct xfs_dir2_data_free * xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) { return ((struct xfs_dir3_data_hdr *)hdr)->best_free; } static struct xfs_dir2_data_entry * xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); } static struct xfs_dir2_data_unused * xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_unused *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); } static struct xfs_dir2_data_entry * xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); } static struct xfs_dir2_data_unused * xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_unused *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); } /* * Directory Leaf block operations */ static int xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) / (uint)sizeof(struct xfs_dir2_leaf_entry); } static struct xfs_dir2_leaf_entry * xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp) { return lp->__ents; } static int xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) / (uint)sizeof(struct xfs_dir2_leaf_entry); } static struct xfs_dir2_leaf_entry * xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) { return ((struct xfs_dir3_leaf *)lp)->__ents; } static void xfs_dir2_leaf_hdr_from_disk( struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from) { to->forw = be32_to_cpu(from->hdr.info.forw); to->back = be32_to_cpu(from->hdr.info.back); to->magic = be16_to_cpu(from->hdr.info.magic); to->count = be16_to_cpu(from->hdr.count); to->stale = be16_to_cpu(from->hdr.stale); ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC || to->magic == XFS_DIR2_LEAFN_MAGIC); } static void xfs_dir2_leaf_hdr_to_disk( struct xfs_dir2_leaf *to, struct xfs_dir3_icleaf_hdr *from) { ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC || from->magic == XFS_DIR2_LEAFN_MAGIC); to->hdr.info.forw = cpu_to_be32(from->forw); to->hdr.info.back = cpu_to_be32(from->back); to->hdr.info.magic = cpu_to_be16(from->magic); to->hdr.count = cpu_to_be16(from->count); to->hdr.stale = cpu_to_be16(from->stale); } static void xfs_dir3_leaf_hdr_from_disk( struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from) { struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from; to->forw = be32_to_cpu(hdr3->info.hdr.forw); to->back = be32_to_cpu(hdr3->info.hdr.back); to->magic = be16_to_cpu(hdr3->info.hdr.magic); to->count = be16_to_cpu(hdr3->count); to->stale = be16_to_cpu(hdr3->stale); ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC || to->magic == XFS_DIR3_LEAFN_MAGIC); } static void xfs_dir3_leaf_hdr_to_disk( struct xfs_dir2_leaf *to, struct xfs_dir3_icleaf_hdr *from) { struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to; ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC || from->magic == XFS_DIR3_LEAFN_MAGIC); hdr3->info.hdr.forw = cpu_to_be32(from->forw); hdr3->info.hdr.back = cpu_to_be32(from->back); hdr3->info.hdr.magic = cpu_to_be16(from->magic); hdr3->count = cpu_to_be16(from->count); hdr3->stale = cpu_to_be16(from->stale); } /* * Directory/Attribute Node block operations */ static struct xfs_da_node_entry * xfs_da2_node_tree_p(struct xfs_da_intnode *dap) { return dap->__btree; } static struct xfs_da_node_entry * xfs_da3_node_tree_p(struct xfs_da_intnode *dap) { return ((struct xfs_da3_intnode *)dap)->__btree; } static void xfs_da2_node_hdr_from_disk( struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from) { ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); to->forw = be32_to_cpu(from->hdr.info.forw); to->back = be32_to_cpu(from->hdr.info.back); to->magic = be16_to_cpu(from->hdr.info.magic); to->count = be16_to_cpu(from->hdr.__count); to->level = be16_to_cpu(from->hdr.__level); } static void xfs_da2_node_hdr_to_disk( struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from) { ASSERT(from->magic == XFS_DA_NODE_MAGIC); to->hdr.info.forw = cpu_to_be32(from->forw); to->hdr.info.back = cpu_to_be32(from->back); to->hdr.info.magic = cpu_to_be16(from->magic); to->hdr.__count = cpu_to_be16(from->count); to->hdr.__level = cpu_to_be16(from->level); } static void xfs_da3_node_hdr_from_disk( struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from) { struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from; ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); to->forw = be32_to_cpu(hdr3->info.hdr.forw); to->back = be32_to_cpu(hdr3->info.hdr.back); to->magic = be16_to_cpu(hdr3->info.hdr.magic); to->count = be16_to_cpu(hdr3->__count); to->level = be16_to_cpu(hdr3->__level); } static void xfs_da3_node_hdr_to_disk( struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from) { struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to; ASSERT(from->magic == XFS_DA3_NODE_MAGIC); hdr3->info.hdr.forw = cpu_to_be32(from->forw); hdr3->info.hdr.back = cpu_to_be32(from->back); hdr3->info.hdr.magic = cpu_to_be16(from->magic); hdr3->__count = cpu_to_be16(from->count); hdr3->__level = cpu_to_be16(from->level); } /* * Directory free space block operations */ static int xfs_dir2_free_max_bests(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) / sizeof(xfs_dir2_data_off_t); } static __be16 * xfs_dir2_free_bests_p(struct xfs_dir2_free *free) { return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr)); } /* * Convert data space db to the corresponding free db. */ static xfs_dir2_db_t xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + (db / xfs_dir2_free_max_bests(geo)); } /* * Convert data space db to the corresponding index in a free db. */ static int xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return db % xfs_dir2_free_max_bests(geo); } static int xfs_dir3_free_max_bests(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) / sizeof(xfs_dir2_data_off_t); } static __be16 * xfs_dir3_free_bests_p(struct xfs_dir2_free *free) { return (__be16 *)((char *)free + sizeof(struct xfs_dir3_free_hdr)); } /* * Convert data space db to the corresponding free db. */ static xfs_dir2_db_t xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + (db / xfs_dir3_free_max_bests(geo)); } /* * Convert data space db to the corresponding index in a free db. */ static int xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return db % xfs_dir3_free_max_bests(geo); } static void xfs_dir2_free_hdr_from_disk( struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from) { to->magic = be32_to_cpu(from->hdr.magic); to->firstdb = be32_to_cpu(from->hdr.firstdb); to->nvalid = be32_to_cpu(from->hdr.nvalid); to->nused = be32_to_cpu(from->hdr.nused); ASSERT(to->magic == XFS_DIR2_FREE_MAGIC); } static void xfs_dir2_free_hdr_to_disk( struct xfs_dir2_free *to, struct xfs_dir3_icfree_hdr *from) { ASSERT(from->magic == XFS_DIR2_FREE_MAGIC); to->hdr.magic = cpu_to_be32(from->magic); to->hdr.firstdb = cpu_to_be32(from->firstdb); to->hdr.nvalid = cpu_to_be32(from->nvalid); to->hdr.nused = cpu_to_be32(from->nused); } static void xfs_dir3_free_hdr_from_disk( struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from) { struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; to->magic = be32_to_cpu(hdr3->hdr.magic); to->firstdb = be32_to_cpu(hdr3->firstdb); to->nvalid = be32_to_cpu(hdr3->nvalid); to->nused = be32_to_cpu(hdr3->nused); ASSERT(to->magic == XFS_DIR3_FREE_MAGIC); } static void xfs_dir3_free_hdr_to_disk( struct xfs_dir2_free *to, struct xfs_dir3_icfree_hdr *from) { struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; ASSERT(from->magic == XFS_DIR3_FREE_MAGIC); hdr3->hdr.magic = cpu_to_be32(from->magic); hdr3->firstdb = cpu_to_be32(from->firstdb); hdr3->nvalid = cpu_to_be32(from->nvalid); hdr3->nused = cpu_to_be32(from->nused); } static const struct xfs_dir_ops xfs_dir2_ops = { .sf_entsize = xfs_dir2_sf_entsize, .sf_nextentry = xfs_dir2_sf_nextentry, .sf_get_ftype = xfs_dir2_sfe_get_ftype, .sf_put_ftype = xfs_dir2_sfe_put_ftype, .sf_get_ino = xfs_dir2_sfe_get_ino, .sf_put_ino = xfs_dir2_sfe_put_ino, .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, .data_entsize = xfs_dir2_data_entsize, .data_get_ftype = xfs_dir2_data_get_ftype, .data_put_ftype = xfs_dir2_data_put_ftype, .data_entry_tag_p = xfs_dir2_data_entry_tag_p, .data_bestfree_p = xfs_dir2_data_bestfree_p, .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1), .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1) + XFS_DIR2_DATA_ENTSIZE(2), .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), .data_dot_entry_p = xfs_dir2_data_dot_entry_p, .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, .data_first_entry_p = xfs_dir2_data_first_entry_p, .data_entry_p = xfs_dir2_data_entry_p, .data_unused_p = xfs_dir2_data_unused_p, .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, .leaf_max_ents = xfs_dir2_max_leaf_ents, .leaf_ents_p = xfs_dir2_leaf_ents_p, .node_hdr_size = sizeof(struct xfs_da_node_hdr), .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, .node_tree_p = xfs_da2_node_tree_p, .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, .free_max_bests = xfs_dir2_free_max_bests, .free_bests_p = xfs_dir2_free_bests_p, .db_to_fdb = xfs_dir2_db_to_fdb, .db_to_fdindex = xfs_dir2_db_to_fdindex, }; static const struct xfs_dir_ops xfs_dir2_ftype_ops = { .sf_entsize = xfs_dir3_sf_entsize, .sf_nextentry = xfs_dir3_sf_nextentry, .sf_get_ftype = xfs_dir3_sfe_get_ftype, .sf_put_ftype = xfs_dir3_sfe_put_ftype, .sf_get_ino = xfs_dir3_sfe_get_ino, .sf_put_ino = xfs_dir3_sfe_put_ino, .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, .data_entsize = xfs_dir3_data_entsize, .data_get_ftype = xfs_dir3_data_get_ftype, .data_put_ftype = xfs_dir3_data_put_ftype, .data_entry_tag_p = xfs_dir3_data_entry_tag_p, .data_bestfree_p = xfs_dir2_data_bestfree_p, .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1), .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2), .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), .data_dot_entry_p = xfs_dir2_data_dot_entry_p, .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p, .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p, .data_entry_p = xfs_dir2_data_entry_p, .data_unused_p = xfs_dir2_data_unused_p, .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, .leaf_max_ents = xfs_dir2_max_leaf_ents, .leaf_ents_p = xfs_dir2_leaf_ents_p, .node_hdr_size = sizeof(struct xfs_da_node_hdr), .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, .node_tree_p = xfs_da2_node_tree_p, .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, .free_max_bests = xfs_dir2_free_max_bests, .free_bests_p = xfs_dir2_free_bests_p, .db_to_fdb = xfs_dir2_db_to_fdb, .db_to_fdindex = xfs_dir2_db_to_fdindex, }; static const struct xfs_dir_ops xfs_dir3_ops = { .sf_entsize = xfs_dir3_sf_entsize, .sf_nextentry = xfs_dir3_sf_nextentry, .sf_get_ftype = xfs_dir3_sfe_get_ftype, .sf_put_ftype = xfs_dir3_sfe_put_ftype, .sf_get_ino = xfs_dir3_sfe_get_ino, .sf_put_ino = xfs_dir3_sfe_put_ino, .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, .data_entsize = xfs_dir3_data_entsize, .data_get_ftype = xfs_dir3_data_get_ftype, .data_put_ftype = xfs_dir3_data_put_ftype, .data_entry_tag_p = xfs_dir3_data_entry_tag_p, .data_bestfree_p = xfs_dir3_data_bestfree_p, .data_dot_offset = sizeof(struct xfs_dir3_data_hdr), .data_dotdot_offset = sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1), .data_first_offset = sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2), .data_entry_offset = sizeof(struct xfs_dir3_data_hdr), .data_dot_entry_p = xfs_dir3_data_dot_entry_p, .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p, .data_first_entry_p = xfs_dir3_data_first_entry_p, .data_entry_p = xfs_dir3_data_entry_p, .data_unused_p = xfs_dir3_data_unused_p, .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr), .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, .leaf_max_ents = xfs_dir3_max_leaf_ents, .leaf_ents_p = xfs_dir3_leaf_ents_p, .node_hdr_size = sizeof(struct xfs_da3_node_hdr), .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, .node_tree_p = xfs_da3_node_tree_p, .free_hdr_size = sizeof(struct xfs_dir3_free_hdr), .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, .free_max_bests = xfs_dir3_free_max_bests, .free_bests_p = xfs_dir3_free_bests_p, .db_to_fdb = xfs_dir3_db_to_fdb, .db_to_fdindex = xfs_dir3_db_to_fdindex, }; static const struct xfs_dir_ops xfs_dir2_nondir_ops = { .node_hdr_size = sizeof(struct xfs_da_node_hdr), .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, .node_tree_p = xfs_da2_node_tree_p, }; static const struct xfs_dir_ops xfs_dir3_nondir_ops = { .node_hdr_size = sizeof(struct xfs_da3_node_hdr), .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, .node_tree_p = xfs_da3_node_tree_p, }; /* * Return the ops structure according to the current config. If we are passed * an inode, then that overrides the default config we use which is based on * feature bits. */ const struct xfs_dir_ops * xfs_dir_get_ops( struct xfs_mount *mp, struct xfs_inode *dp) { if (dp) return dp->d_ops; if (mp->m_dir_inode_ops) return mp->m_dir_inode_ops; if (xfs_sb_version_hascrc(&mp->m_sb)) return &xfs_dir3_ops; if (xfs_sb_version_hasftype(&mp->m_sb)) return &xfs_dir2_ftype_ops; return &xfs_dir2_ops; } const struct xfs_dir_ops * xfs_nondir_get_ops( struct xfs_mount *mp, struct xfs_inode *dp) { if (dp) return dp->d_ops; if (mp->m_nondir_inode_ops) return mp->m_nondir_inode_ops; if (xfs_sb_version_hascrc(&mp->m_sb)) return &xfs_dir3_nondir_ops; return &xfs_dir2_nondir_ops; } xfsprogs-5.3.0/libxfs/xfs_da_format.h0000644000175000017500000007116613570057155017543 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_DA_FORMAT_H__ #define __XFS_DA_FORMAT_H__ /* * This structure is common to both leaf nodes and non-leaf nodes in the Btree. * * It is used to manage a doubly linked list of all blocks at the same * level in the Btree, and to identify which type of block this is. */ #define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ #define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ #define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ #define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ typedef struct xfs_da_blkinfo { __be32 forw; /* previous block in list */ __be32 back; /* following block in list */ __be16 magic; /* validity check on block */ __be16 pad; /* unused */ } xfs_da_blkinfo_t; /* * CRC enabled directory structure types * * The headers change size for the additional verification information, but * otherwise the tree layouts and contents are unchanged. Hence the da btree * code can use the struct xfs_da_blkinfo for manipulating the tree links and * magic numbers without modification for both v2 and v3 nodes. */ #define XFS_DA3_NODE_MAGIC 0x3ebe /* magic number: non-leaf blocks */ #define XFS_ATTR3_LEAF_MAGIC 0x3bee /* magic number: attribute leaf blks */ #define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */ #define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */ struct xfs_da3_blkinfo { /* * the node link manipulation code relies on the fact that the first * element of this structure is the struct xfs_da_blkinfo so it can * ignore the differences in the rest of the structures. */ struct xfs_da_blkinfo hdr; __be32 crc; /* CRC of block */ __be64 blkno; /* first block of the buffer */ __be64 lsn; /* sequence number of last write */ uuid_t uuid; /* filesystem we belong to */ __be64 owner; /* inode that owns the block */ }; /* * This is the structure of the root and intermediate nodes in the Btree. * The leaf nodes are defined above. * * Entries are not packed. * * Since we have duplicate keys, use a binary search but always follow * all match in the block, not just the first match found. */ #define XFS_DA_NODE_MAXDEPTH 5 /* max depth of Btree */ typedef struct xfs_da_node_hdr { struct xfs_da_blkinfo info; /* block type, links, etc. */ __be16 __count; /* count of active entries */ __be16 __level; /* level above leaves (leaf == 0) */ } xfs_da_node_hdr_t; struct xfs_da3_node_hdr { struct xfs_da3_blkinfo info; /* block type, links, etc. */ __be16 __count; /* count of active entries */ __be16 __level; /* level above leaves (leaf == 0) */ __be32 __pad32; }; #define XFS_DA3_NODE_CRC_OFF (offsetof(struct xfs_da3_node_hdr, info.crc)) typedef struct xfs_da_node_entry { __be32 hashval; /* hash value for this descendant */ __be32 before; /* Btree block before this key */ } xfs_da_node_entry_t; typedef struct xfs_da_intnode { struct xfs_da_node_hdr hdr; struct xfs_da_node_entry __btree[]; } xfs_da_intnode_t; struct xfs_da3_intnode { struct xfs_da3_node_hdr hdr; struct xfs_da_node_entry __btree[]; }; /* * In-core version of the node header to abstract the differences in the v2 and * v3 disk format of the headers. Callers need to convert to/from disk format as * appropriate. */ struct xfs_da3_icnode_hdr { uint32_t forw; uint32_t back; uint16_t magic; uint16_t count; uint16_t level; }; /* * Directory version 2. * * There are 4 possible formats: * - shortform - embedded into the inode * - single block - data with embedded leaf at the end * - multiple data blocks, single leaf+freeindex block * - data blocks, node and leaf blocks (btree), freeindex blocks * * Note: many node blocks structures and constants are shared with the attr * code and defined in xfs_da_btree.h. */ #define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: single block dirs */ #define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: multiblock dirs */ #define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ /* * Directory Version 3 With CRCs. * * The tree formats are the same as for version 2 directories. The difference * is in the block header and dirent formats. In many cases the v3 structures * use v2 definitions as they are no different and this makes code sharing much * easier. * * Also, the xfs_dir3_*() functions handle both v2 and v3 formats - if the * format is v2 then they switch to the existing v2 code, or the format is v3 * they implement the v3 functionality. This means the existing dir2 is a mix of * xfs_dir2/xfs_dir3 calls and functions. The xfs_dir3 functions are called * where there is a difference in the formats, otherwise the code is unchanged. * * Where it is possible, the code decides what to do based on the magic numbers * in the blocks rather than feature bits in the superblock. This means the code * is as independent of the external XFS code as possible as doesn't require * passing struct xfs_mount pointers into places where it isn't really * necessary. * * Version 3 includes: * * - a larger block header for CRC and identification purposes and so the * offsets of all the structures inside the blocks are different. * * - new magic numbers to be able to detect the v2/v3 types on the fly. */ #define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */ #define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */ #define XFS_DIR3_FREE_MAGIC 0x58444633 /* XDF3: free index blocks */ /* * Dirents in version 3 directories have a file type field. Additions to this * list are an on-disk format change, requiring feature bits. Valid values * are as follows: */ #define XFS_DIR3_FT_UNKNOWN 0 #define XFS_DIR3_FT_REG_FILE 1 #define XFS_DIR3_FT_DIR 2 #define XFS_DIR3_FT_CHRDEV 3 #define XFS_DIR3_FT_BLKDEV 4 #define XFS_DIR3_FT_FIFO 5 #define XFS_DIR3_FT_SOCK 6 #define XFS_DIR3_FT_SYMLINK 7 #define XFS_DIR3_FT_WHT 8 #define XFS_DIR3_FT_MAX 9 /* * Byte offset in data block and shortform entry. */ typedef uint16_t xfs_dir2_data_off_t; #define NULLDATAOFF 0xffffU typedef uint xfs_dir2_data_aoff_t; /* argument form */ /* * Offset in data space of a data entry. */ typedef uint32_t xfs_dir2_dataptr_t; #define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0xffffffff) #define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) /* * Byte offset in a directory. */ typedef xfs_off_t xfs_dir2_off_t; /* * Directory block number (logical dirblk in file) */ typedef uint32_t xfs_dir2_db_t; #define XFS_INO32_SIZE 4 #define XFS_INO64_SIZE 8 #define XFS_INO64_DIFF (XFS_INO64_SIZE - XFS_INO32_SIZE) #define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) /* * Directory layout when stored internal to an inode. * * Small directories are packed as tightly as possible so as to fit into the * literal area of the inode. These "shortform" directories consist of a * single xfs_dir2_sf_hdr header followed by zero or more xfs_dir2_sf_entry * structures. Due the different inode number storage size and the variable * length name field in the xfs_dir2_sf_entry all these structure are * variable length, and the accessors in this file should be used to iterate * over them. */ typedef struct xfs_dir2_sf_hdr { uint8_t count; /* count of entries */ uint8_t i8count; /* count of 8-byte inode #s */ uint8_t parent[8]; /* parent dir inode number */ } __packed xfs_dir2_sf_hdr_t; typedef struct xfs_dir2_sf_entry { __u8 namelen; /* actual name length */ __u8 offset[2]; /* saved offset */ __u8 name[]; /* name, variable size */ /* * A single byte containing the file type field follows the inode * number for version 3 directory entries. * * A 64-bit or 32-bit inode number follows here, at a variable offset * after the name. */ } xfs_dir2_sf_entry_t; static inline int xfs_dir2_sf_hdr_size(int i8count) { return sizeof(struct xfs_dir2_sf_hdr) - (i8count == 0) * XFS_INO64_DIFF; } static inline xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep) { return get_unaligned_be16(sfep->offset); } static inline void xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off) { put_unaligned_be16(off, sfep->offset); } static inline struct xfs_dir2_sf_entry * xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) { return (struct xfs_dir2_sf_entry *) ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); } /* * Data block structures. * * A pure data block looks like the following drawing on disk: * * +-------------------------------------------------+ * | xfs_dir2_data_hdr_t | * +-------------------------------------------------+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | ... | * +-------------------------------------------------+ * | unused space | * +-------------------------------------------------+ * * As all the entries are variable size structures the accessors below should * be used to iterate over them. * * In addition to the pure data blocks for the data and node formats, * most structures are also used for the combined data/freespace "block" * format below. */ #define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ #define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) #define XFS_DIR2_DATA_FREE_TAG 0xffff #define XFS_DIR2_DATA_FD_COUNT 3 /* * Directory address space divided into sections, * spaces separated by 32GB. */ #define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) #define XFS_DIR2_DATA_SPACE 0 #define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) /* * Describe a free area in the data block. * * The freespace will be formatted as a xfs_dir2_data_unused_t. */ typedef struct xfs_dir2_data_free { __be16 offset; /* start of freespace */ __be16 length; /* length of freespace */ } xfs_dir2_data_free_t; /* * Header for the data blocks. * * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. */ typedef struct xfs_dir2_data_hdr { __be32 magic; /* XFS_DIR2_DATA_MAGIC or */ /* XFS_DIR2_BLOCK_MAGIC */ xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; } xfs_dir2_data_hdr_t; /* * define a structure for all the verification fields we are adding to the * directory block structures. This will be used in several structures. * The magic number must be the first entry to align with all the dir2 * structures so we determine how to decode them just by the magic number. */ struct xfs_dir3_blk_hdr { __be32 magic; /* magic number */ __be32 crc; /* CRC of block */ __be64 blkno; /* first block of the buffer */ __be64 lsn; /* sequence number of last write */ uuid_t uuid; /* filesystem we belong to */ __be64 owner; /* inode that owns the block */ }; struct xfs_dir3_data_hdr { struct xfs_dir3_blk_hdr hdr; xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT]; __be32 pad; /* 64 bit alignment */ }; #define XFS_DIR3_DATA_CRC_OFF offsetof(struct xfs_dir3_data_hdr, hdr.crc) /* * Active entry in a data block. * * Aligned to 8 bytes. After the variable length name field there is a * 2 byte tag field, which can be accessed using xfs_dir3_data_entry_tag_p. * * For dir3 structures, there is file type field between the name and the tag. * This can only be manipulated by helper functions. It is packed hard against * the end of the name so any padding for rounding is between the file type and * the tag. */ typedef struct xfs_dir2_data_entry { __be64 inumber; /* inode number */ __u8 namelen; /* name length */ __u8 name[]; /* name bytes, no null */ /* __u8 filetype; */ /* type of inode we point to */ /* __be16 tag; */ /* starting offset of us */ } xfs_dir2_data_entry_t; /* * Unused entry in a data block. * * Aligned to 8 bytes. Tag appears as the last 2 bytes and must be accessed * using xfs_dir2_data_unused_tag_p. */ typedef struct xfs_dir2_data_unused { __be16 freetag; /* XFS_DIR2_DATA_FREE_TAG */ __be16 length; /* total free length */ /* variable offset */ __be16 tag; /* starting offset of us */ } xfs_dir2_data_unused_t; /* * Pointer to a freespace's tag word. */ static inline __be16 * xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup) { return (__be16 *)((char *)dup + be16_to_cpu(dup->length) - sizeof(__be16)); } /* * Leaf block structures. * * A pure leaf block looks like the following drawing on disk: * * +---------------------------+ * | xfs_dir2_leaf_hdr_t | * +---------------------------+ * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * | ... | * +---------------------------+ * | xfs_dir2_data_off_t | * | xfs_dir2_data_off_t | * | xfs_dir2_data_off_t | * | ... | * +---------------------------+ * | xfs_dir2_leaf_tail_t | * +---------------------------+ * * The xfs_dir2_data_off_t members (bests) and tail are at the end of the block * for single-leaf (magic = XFS_DIR2_LEAF1_MAGIC) blocks only, but not present * for directories with separate leaf nodes and free space blocks * (magic = XFS_DIR2_LEAFN_MAGIC). * * As all the entries are variable size structures the accessors below should * be used to iterate over them. */ /* * Offset of the leaf/node space. First block in this space * is the btree root. */ #define XFS_DIR2_LEAF_SPACE 1 #define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) /* * Leaf block header. */ typedef struct xfs_dir2_leaf_hdr { xfs_da_blkinfo_t info; /* header for da routines */ __be16 count; /* count of entries */ __be16 stale; /* count of stale entries */ } xfs_dir2_leaf_hdr_t; struct xfs_dir3_leaf_hdr { struct xfs_da3_blkinfo info; /* header for da routines */ __be16 count; /* count of entries */ __be16 stale; /* count of stale entries */ __be32 pad; /* 64 bit alignment */ }; struct xfs_dir3_icleaf_hdr { uint32_t forw; uint32_t back; uint16_t magic; uint16_t count; uint16_t stale; }; /* * Leaf block entry. */ typedef struct xfs_dir2_leaf_entry { __be32 hashval; /* hash value of name */ __be32 address; /* address of data entry */ } xfs_dir2_leaf_entry_t; /* * Leaf block tail. */ typedef struct xfs_dir2_leaf_tail { __be32 bestcount; } xfs_dir2_leaf_tail_t; /* * Leaf block. */ typedef struct xfs_dir2_leaf { xfs_dir2_leaf_hdr_t hdr; /* leaf header */ xfs_dir2_leaf_entry_t __ents[]; /* entries */ } xfs_dir2_leaf_t; struct xfs_dir3_leaf { struct xfs_dir3_leaf_hdr hdr; /* leaf header */ struct xfs_dir2_leaf_entry __ents[]; /* entries */ }; #define XFS_DIR3_LEAF_CRC_OFF offsetof(struct xfs_dir3_leaf_hdr, info.crc) /* * Get address of the bests array in the single-leaf block. */ static inline __be16 * xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp) { return (__be16 *)ltp - be32_to_cpu(ltp->bestcount); } /* * Free space block defintions for the node format. */ /* * Offset of the freespace index. */ #define XFS_DIR2_FREE_SPACE 2 #define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) typedef struct xfs_dir2_free_hdr { __be32 magic; /* XFS_DIR2_FREE_MAGIC */ __be32 firstdb; /* db of first entry */ __be32 nvalid; /* count of valid entries */ __be32 nused; /* count of used entries */ } xfs_dir2_free_hdr_t; typedef struct xfs_dir2_free { xfs_dir2_free_hdr_t hdr; /* block header */ __be16 bests[]; /* best free counts */ /* unused entries are -1 */ } xfs_dir2_free_t; struct xfs_dir3_free_hdr { struct xfs_dir3_blk_hdr hdr; __be32 firstdb; /* db of first entry */ __be32 nvalid; /* count of valid entries */ __be32 nused; /* count of used entries */ __be32 pad; /* 64 bit alignment */ }; struct xfs_dir3_free { struct xfs_dir3_free_hdr hdr; __be16 bests[]; /* best free counts */ /* unused entries are -1 */ }; #define XFS_DIR3_FREE_CRC_OFF offsetof(struct xfs_dir3_free, hdr.hdr.crc) /* * In core version of the free block header, abstracted away from on-disk format * differences. Use this in the code, and convert to/from the disk version using * xfs_dir3_free_hdr_from_disk/xfs_dir3_free_hdr_to_disk. */ struct xfs_dir3_icfree_hdr { uint32_t magic; uint32_t firstdb; uint32_t nvalid; uint32_t nused; }; /* * Single block format. * * The single block format looks like the following drawing on disk: * * +-------------------------------------------------+ * | xfs_dir2_data_hdr_t | * +-------------------------------------------------+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t : * | ... | * +-------------------------------------------------+ * | unused space | * +-------------------------------------------------+ * | ... | * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * +-------------------------------------------------+ * | xfs_dir2_block_tail_t | * +-------------------------------------------------+ * * As all the entries are variable size structures the accessors below should * be used to iterate over them. */ typedef struct xfs_dir2_block_tail { __be32 count; /* count of leaf entries */ __be32 stale; /* count of stale lf entries */ } xfs_dir2_block_tail_t; /* * Pointer to the leaf entries embedded in a data block (1-block format) */ static inline struct xfs_dir2_leaf_entry * xfs_dir2_block_leaf_p(struct xfs_dir2_block_tail *btp) { return ((struct xfs_dir2_leaf_entry *)btp) - be32_to_cpu(btp->count); } /* * Attribute storage layout * * Attribute lists are structured around Btrees where all the data * elements are in the leaf nodes. Attribute names are hashed into an int, * then that int is used as the index into the Btree. Since the hashval * of an attribute name may not be unique, we may have duplicate keys. The * internal links in the Btree are logical block offsets into the file. * * Struct leaf_entry's are packed from the top. Name/values grow from the * bottom but are not packed. The freemap contains run-length-encoded entries * for the free bytes after the leaf_entry's, but only the N largest such, * smaller runs are dropped. When the freemap doesn't show enough space * for an allocation, we compact the name/value area and try again. If we * still don't have enough space, then we have to split the block. The * name/value structs (both local and remote versions) must be 32bit aligned. * * Since we have duplicate hash keys, for each key that matches, compare * the actual name string. The root and intermediate node search always * takes the first-in-the-block key match found, so we should only have * to work "forw"ard. If none matches, continue with the "forw"ard leaf * nodes until the hash key changes or the attribute name is found. * * We store the fact that an attribute is a ROOT/USER/SECURE attribute in * the leaf_entry. The namespaces are independent only because we also look * at the namespace bit when we are looking for a matching attribute name. * * We also store an "incomplete" bit in the leaf_entry. It shows that an * attribute is in the middle of being created and should not be shown to * the user if we crash during the time that the bit is set. We clear the * bit when we have finished setting up the attribute. We do this because * we cannot create some large attributes inside a single transaction, and we * need some indication that we weren't finished if we crash in the middle. */ #define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */ /* * Entries are packed toward the top as tight as possible. */ typedef struct xfs_attr_shortform { struct xfs_attr_sf_hdr { /* constant-structure header block */ __be16 totsize; /* total bytes in shortform list */ __u8 count; /* count of active entries */ __u8 padding; } hdr; struct xfs_attr_sf_entry { uint8_t namelen; /* actual length of name (no NULL) */ uint8_t valuelen; /* actual length of value (no NULL) */ uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ uint8_t nameval[1]; /* name & value bytes concatenated */ } list[1]; /* variable sized array */ } xfs_attr_shortform_t; typedef struct xfs_attr_leaf_map { /* RLE map of free bytes */ __be16 base; /* base of free region */ __be16 size; /* length of free region */ } xfs_attr_leaf_map_t; typedef struct xfs_attr_leaf_hdr { /* constant-structure header block */ xfs_da_blkinfo_t info; /* block type, links, etc. */ __be16 count; /* count of active leaf_entry's */ __be16 usedbytes; /* num bytes of names/values stored */ __be16 firstused; /* first used byte in name area */ __u8 holes; /* != 0 if blk needs compaction */ __u8 pad1; xfs_attr_leaf_map_t freemap[XFS_ATTR_LEAF_MAPSIZE]; /* N largest free regions */ } xfs_attr_leaf_hdr_t; typedef struct xfs_attr_leaf_entry { /* sorted on key, not name */ __be32 hashval; /* hash value of name */ __be16 nameidx; /* index into buffer of name/value */ __u8 flags; /* LOCAL/ROOT/SECURE/INCOMPLETE flag */ __u8 pad2; /* unused pad byte */ } xfs_attr_leaf_entry_t; typedef struct xfs_attr_leaf_name_local { __be16 valuelen; /* number of bytes in value */ __u8 namelen; /* length of name bytes */ __u8 nameval[1]; /* name/value bytes */ } xfs_attr_leaf_name_local_t; typedef struct xfs_attr_leaf_name_remote { __be32 valueblk; /* block number of value bytes */ __be32 valuelen; /* number of bytes in value */ __u8 namelen; /* length of name bytes */ __u8 name[1]; /* name bytes */ } xfs_attr_leaf_name_remote_t; typedef struct xfs_attr_leafblock { xfs_attr_leaf_hdr_t hdr; /* constant-structure header block */ xfs_attr_leaf_entry_t entries[1]; /* sorted on key, not name */ /* * The rest of the block contains the following structures after the * leaf entries, growing from the bottom up. The variables are never * referenced and definining them can actually make gcc optimize away * accesses to the 'entries' array above index 0 so don't do that. * * xfs_attr_leaf_name_local_t namelist; * xfs_attr_leaf_name_remote_t valuelist; */ } xfs_attr_leafblock_t; /* * CRC enabled leaf structures. Called "version 3" structures to match the * version number of the directory and dablk structures for this feature, and * attr2 is already taken by the variable inode attribute fork size feature. */ struct xfs_attr3_leaf_hdr { struct xfs_da3_blkinfo info; __be16 count; __be16 usedbytes; __be16 firstused; __u8 holes; __u8 pad1; struct xfs_attr_leaf_map freemap[XFS_ATTR_LEAF_MAPSIZE]; __be32 pad2; /* 64 bit alignment */ }; #define XFS_ATTR3_LEAF_CRC_OFF (offsetof(struct xfs_attr3_leaf_hdr, info.crc)) struct xfs_attr3_leafblock { struct xfs_attr3_leaf_hdr hdr; struct xfs_attr_leaf_entry entries[1]; /* * The rest of the block contains the following structures after the * leaf entries, growing from the bottom up. The variables are never * referenced, the locations accessed purely from helper functions. * * struct xfs_attr_leaf_name_local * struct xfs_attr_leaf_name_remote */ }; /* * incore, neutral version of the attribute leaf header */ struct xfs_attr3_icleaf_hdr { uint32_t forw; uint32_t back; uint16_t magic; uint16_t count; uint16_t usedbytes; /* * firstused is 32-bit here instead of 16-bit like the on-disk variant * to support maximum fsb size of 64k without overflow issues throughout * the attr code. Instead, the overflow condition is handled on * conversion to/from disk. */ uint32_t firstused; __u8 holes; struct { uint16_t base; uint16_t size; } freemap[XFS_ATTR_LEAF_MAPSIZE]; }; /* * Special value to represent fs block size in the leaf header firstused field. * Only used when block size overflows the 2-bytes available on disk. */ #define XFS_ATTR3_LEAF_NULLOFF 0 /* * Flags used in the leaf_entry[i].flags field. * NOTE: the INCOMPLETE bit must not collide with the flags bits specified * on the system call, they are "or"ed together for various operations. */ #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ #define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT) #define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT) #define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT) #define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) /* * Conversion macros for converting namespace bits from argument flags * to ondisk flags. */ #define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE) #define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE) #define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK) #define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK) #define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\ ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0)) #define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\ ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0)) /* * Alignment for namelist and valuelist entries (since they are mixed * there can be only one alignment value) */ #define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) static inline int xfs_attr3_leaf_hdr_size(struct xfs_attr_leafblock *leafp) { if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) return sizeof(struct xfs_attr3_leaf_hdr); return sizeof(struct xfs_attr_leaf_hdr); } static inline struct xfs_attr_leaf_entry * xfs_attr3_leaf_entryp(xfs_attr_leafblock_t *leafp) { if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) return &((struct xfs_attr3_leafblock *)leafp)->entries[0]; return &leafp->entries[0]; } /* * Cast typed pointers for "local" and "remote" name/value structs. */ static inline char * xfs_attr3_leaf_name(xfs_attr_leafblock_t *leafp, int idx) { struct xfs_attr_leaf_entry *entries = xfs_attr3_leaf_entryp(leafp); return &((char *)leafp)[be16_to_cpu(entries[idx].nameidx)]; } static inline xfs_attr_leaf_name_remote_t * xfs_attr3_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) { return (xfs_attr_leaf_name_remote_t *)xfs_attr3_leaf_name(leafp, idx); } static inline xfs_attr_leaf_name_local_t * xfs_attr3_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx) { return (xfs_attr_leaf_name_local_t *)xfs_attr3_leaf_name(leafp, idx); } /* * Calculate total bytes used (including trailing pad for alignment) for * a "local" name/value structure, a "remote" name/value structure, and * a pointer which might be either. */ static inline int xfs_attr_leaf_entsize_remote(int nlen) { return ((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \ XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1); } static inline int xfs_attr_leaf_entsize_local(int nlen, int vlen) { return ((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1); } static inline int xfs_attr_leaf_entsize_local_max(int bsize) { return (((bsize) >> 1) + ((bsize) >> 2)); } /* * Remote attribute block format definition * * There is one of these headers per filesystem block in a remote attribute. * This is done to ensure there is a 1:1 mapping between the attribute value * length and the number of blocks needed to store the attribute. This makes the * verification of a buffer a little more complex, but greatly simplifies the * allocation, reading and writing of these attributes as we don't have to guess * the number of blocks needed to store the attribute data. */ #define XFS_ATTR3_RMT_MAGIC 0x5841524d /* XARM */ struct xfs_attr3_rmt_hdr { __be32 rm_magic; __be32 rm_offset; __be32 rm_bytes; __be32 rm_crc; uuid_t rm_uuid; __be64 rm_owner; __be64 rm_blkno; __be64 rm_lsn; }; #define XFS_ATTR3_RMT_CRC_OFF offsetof(struct xfs_attr3_rmt_hdr, rm_crc) #define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \ ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ sizeof(struct xfs_attr3_rmt_hdr) : 0)) /* Number of bytes in a directory block. */ static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp) { return 1 << (sbp->sb_blocklog + sbp->sb_dirblklog); } xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp, struct xfs_da3_blkinfo *hdr3); #endif /* __XFS_DA_FORMAT_H__ */ xfsprogs-5.3.0/libxfs/xfs_defer.c0000644000175000017500000004246313570057155016665 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_log_format.h" #include "xfs_defer.h" #include "xfs_trans.h" #include "xfs_trace.h" /* * Deferred Operations in XFS * * Due to the way locking rules work in XFS, certain transactions (block * mapping and unmapping, typically) have permanent reservations so that * we can roll the transaction to adhere to AG locking order rules and * to unlock buffers between metadata updates. Prior to rmap/reflink, * the mapping code had a mechanism to perform these deferrals for * extents that were going to be freed; this code makes that facility * more generic. * * When adding the reverse mapping and reflink features, it became * necessary to perform complex remapping multi-transactions to comply * with AG locking order rules, and to be able to spread a single * refcount update operation (an operation on an n-block extent can * update as many as n records!) among multiple transactions. XFS can * roll a transaction to facilitate this, but using this facility * requires us to log "intent" items in case log recovery needs to * redo the operation, and to log "done" items to indicate that redo * is not necessary. * * Deferred work is tracked in xfs_defer_pending items. Each pending * item tracks one type of deferred work. Incoming work items (which * have not yet had an intent logged) are attached to a pending item * on the dop_intake list, where they wait for the caller to finish * the deferred operations. * * Finishing a set of deferred operations is an involved process. To * start, we define "rolling a deferred-op transaction" as follows: * * > For each xfs_defer_pending item on the dop_intake list, * - Sort the work items in AG order. XFS locking * order rules require us to lock buffers in AG order. * - Create a log intent item for that type. * - Attach it to the pending item. * - Move the pending item from the dop_intake list to the * dop_pending list. * > Roll the transaction. * * NOTE: To avoid exceeding the transaction reservation, we limit the * number of items that we attach to a given xfs_defer_pending. * * The actual finishing process looks like this: * * > For each xfs_defer_pending in the dop_pending list, * - Roll the deferred-op transaction as above. * - Create a log done item for that type, and attach it to the * log intent item. * - For each work item attached to the log intent item, * * Perform the described action. * * Attach the work item to the log done item. * * If the result of doing the work was -EAGAIN, ->finish work * wants a new transaction. See the "Requesting a Fresh * Transaction while Finishing Deferred Work" section below for * details. * * The key here is that we must log an intent item for all pending * work items every time we roll the transaction, and that we must log * a done item as soon as the work is completed. With this mechanism * we can perform complex remapping operations, chaining intent items * as needed. * * Requesting a Fresh Transaction while Finishing Deferred Work * * If ->finish_item decides that it needs a fresh transaction to * finish the work, it must ask its caller (xfs_defer_finish) for a * continuation. The most likely cause of this circumstance are the * refcount adjust functions deciding that they've logged enough items * to be at risk of exceeding the transaction reservation. * * To get a fresh transaction, we want to log the existing log done * item to prevent the log intent item from replaying, immediately log * a new log intent item with the unfinished work items, roll the * transaction, and re-call ->finish_item wherever it left off. The * log done item and the new log intent item must be in the same * transaction or atomicity cannot be guaranteed; defer_finish ensures * that this happens. * * This requires some coordination between ->finish_item and * defer_finish. Upon deciding to request a new transaction, * ->finish_item should update the current work item to reflect the * unfinished work. Next, it should reset the log done item's list * count to the number of items finished, and return -EAGAIN. * defer_finish sees the -EAGAIN, logs the new log intent item * with the remaining work items, and leaves the xfs_defer_pending * item at the head of the dop_work queue. Then it rolls the * transaction and picks up processing where it left off. It is * required that ->finish_item must be careful to leave enough * transaction reservation to fit the new log intent item. * * This is an example of remapping the extent (E, E+B) into file X at * offset A and dealing with the extent (C, C+B) already being mapped * there: * +-------------------------------------------------+ * | Unmap file X startblock C offset A length B | t0 * | Intent to reduce refcount for extent (C, B) | * | Intent to remove rmap (X, C, A, B) | * | Intent to free extent (D, 1) (bmbt block) | * | Intent to map (X, A, B) at startblock E | * +-------------------------------------------------+ * | Map file X startblock E offset A length B | t1 * | Done mapping (X, E, A, B) | * | Intent to increase refcount for extent (E, B) | * | Intent to add rmap (X, E, A, B) | * +-------------------------------------------------+ * | Reduce refcount for extent (C, B) | t2 * | Done reducing refcount for extent (C, 9) | * | Intent to reduce refcount for extent (C+9, B-9) | * | (ran out of space after 9 refcount updates) | * +-------------------------------------------------+ * | Reduce refcount for extent (C+9, B+9) | t3 * | Done reducing refcount for extent (C+9, B-9) | * | Increase refcount for extent (E, B) | * | Done increasing refcount for extent (E, B) | * | Intent to free extent (C, B) | * | Intent to free extent (F, 1) (refcountbt block) | * | Intent to remove rmap (F, 1, REFC) | * +-------------------------------------------------+ * | Remove rmap (X, C, A, B) | t4 * | Done removing rmap (X, C, A, B) | * | Add rmap (X, E, A, B) | * | Done adding rmap (X, E, A, B) | * | Remove rmap (F, 1, REFC) | * | Done removing rmap (F, 1, REFC) | * +-------------------------------------------------+ * | Free extent (C, B) | t5 * | Done freeing extent (C, B) | * | Free extent (D, 1) | * | Done freeing extent (D, 1) | * | Free extent (F, 1) | * | Done freeing extent (F, 1) | * +-------------------------------------------------+ * * If we should crash before t2 commits, log recovery replays * the following intent items: * * - Intent to reduce refcount for extent (C, B) * - Intent to remove rmap (X, C, A, B) * - Intent to free extent (D, 1) (bmbt block) * - Intent to increase refcount for extent (E, B) * - Intent to add rmap (X, E, A, B) * * In the process of recovering, it should also generate and take care * of these intent items: * * - Intent to free extent (C, B) * - Intent to free extent (F, 1) (refcountbt block) * - Intent to remove rmap (F, 1, REFC) * * Note that the continuation requested between t2 and t3 is likely to * reoccur. */ static const struct xfs_defer_op_type *defer_op_types[] = { [XFS_DEFER_OPS_TYPE_BMAP] = &xfs_bmap_update_defer_type, [XFS_DEFER_OPS_TYPE_REFCOUNT] = &xfs_refcount_update_defer_type, [XFS_DEFER_OPS_TYPE_RMAP] = &xfs_rmap_update_defer_type, [XFS_DEFER_OPS_TYPE_FREE] = &xfs_extent_free_defer_type, [XFS_DEFER_OPS_TYPE_AGFL_FREE] = &xfs_agfl_free_defer_type, }; /* * For each pending item in the intake list, log its intent item and the * associated extents, then add the entire intake list to the end of * the pending list. */ STATIC void xfs_defer_create_intents( struct xfs_trans *tp) { struct list_head *li; struct xfs_defer_pending *dfp; const struct xfs_defer_op_type *ops; list_for_each_entry(dfp, &tp->t_dfops, dfp_list) { ops = defer_op_types[dfp->dfp_type]; dfp->dfp_intent = ops->create_intent(tp, dfp->dfp_count); trace_xfs_defer_create_intent(tp->t_mountp, dfp); list_sort(tp->t_mountp, &dfp->dfp_work, ops->diff_items); list_for_each(li, &dfp->dfp_work) ops->log_item(tp, dfp->dfp_intent, li); } } /* Abort all the intents that were committed. */ STATIC void xfs_defer_trans_abort( struct xfs_trans *tp, struct list_head *dop_pending) { struct xfs_defer_pending *dfp; const struct xfs_defer_op_type *ops; trace_xfs_defer_trans_abort(tp, _RET_IP_); /* Abort intent items that don't have a done item. */ list_for_each_entry(dfp, dop_pending, dfp_list) { ops = defer_op_types[dfp->dfp_type]; trace_xfs_defer_pending_abort(tp->t_mountp, dfp); if (dfp->dfp_intent && !dfp->dfp_done) { ops->abort_intent(dfp->dfp_intent); dfp->dfp_intent = NULL; } } } /* Roll a transaction so we can do some deferred op processing. */ STATIC int xfs_defer_trans_roll( struct xfs_trans **tpp) { struct xfs_trans *tp = *tpp; struct xfs_buf_log_item *bli; struct xfs_inode_log_item *ili; struct xfs_log_item *lip; struct xfs_buf *bplist[XFS_DEFER_OPS_NR_BUFS]; struct xfs_inode *iplist[XFS_DEFER_OPS_NR_INODES]; int bpcount = 0, ipcount = 0; int i; int error; list_for_each_entry(lip, &tp->t_items, li_trans) { switch (lip->li_type) { case XFS_LI_BUF: bli = container_of(lip, struct xfs_buf_log_item, bli_item); if (bli->bli_flags & XFS_BLI_HOLD) { if (bpcount >= XFS_DEFER_OPS_NR_BUFS) { ASSERT(0); return -EFSCORRUPTED; } xfs_trans_dirty_buf(tp, bli->bli_buf); bplist[bpcount++] = bli->bli_buf; } break; case XFS_LI_INODE: ili = container_of(lip, struct xfs_inode_log_item, ili_item); if (ili->ili_lock_flags == 0) { if (ipcount >= XFS_DEFER_OPS_NR_INODES) { ASSERT(0); return -EFSCORRUPTED; } xfs_trans_log_inode(tp, ili->ili_inode, XFS_ILOG_CORE); iplist[ipcount++] = ili->ili_inode; } break; default: break; } } trace_xfs_defer_trans_roll(tp, _RET_IP_); /* * Roll the transaction. Rolling always given a new transaction (even * if committing the old one fails!) to hand back to the caller, so we * join the held resources to the new transaction so that we always * return with the held resources joined to @tpp, no matter what * happened. */ error = xfs_trans_roll(tpp); tp = *tpp; /* Rejoin the joined inodes. */ for (i = 0; i < ipcount; i++) xfs_trans_ijoin(tp, iplist[i], 0); /* Rejoin the buffers and dirty them so the log moves forward. */ for (i = 0; i < bpcount; i++) { xfs_trans_bjoin(tp, bplist[i]); xfs_trans_bhold(tp, bplist[i]); } if (error) trace_xfs_defer_trans_roll_error(tp, error); return error; } /* * Reset an already used dfops after finish. */ static void xfs_defer_reset( struct xfs_trans *tp) { ASSERT(list_empty(&tp->t_dfops)); /* * Low mode state transfers across transaction rolls to mirror dfops * lifetime. Clear it now that dfops is reset. */ tp->t_flags &= ~XFS_TRANS_LOWMODE; } /* * Free up any items left in the list. */ static void xfs_defer_cancel_list( struct xfs_mount *mp, struct list_head *dop_list) { struct xfs_defer_pending *dfp; struct xfs_defer_pending *pli; struct list_head *pwi; struct list_head *n; const struct xfs_defer_op_type *ops; /* * Free the pending items. Caller should already have arranged * for the intent items to be released. */ list_for_each_entry_safe(dfp, pli, dop_list, dfp_list) { ops = defer_op_types[dfp->dfp_type]; trace_xfs_defer_cancel_list(mp, dfp); list_del(&dfp->dfp_list); list_for_each_safe(pwi, n, &dfp->dfp_work) { list_del(pwi); dfp->dfp_count--; ops->cancel_item(pwi); } ASSERT(dfp->dfp_count == 0); kmem_free(dfp); } } /* * Finish all the pending work. This involves logging intent items for * any work items that wandered in since the last transaction roll (if * one has even happened), rolling the transaction, and finishing the * work items in the first item on the logged-and-pending list. * * If an inode is provided, relog it to the new transaction. */ int xfs_defer_finish_noroll( struct xfs_trans **tp) { struct xfs_defer_pending *dfp; struct list_head *li; struct list_head *n; void *state; int error = 0; const struct xfs_defer_op_type *ops; LIST_HEAD(dop_pending); ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); trace_xfs_defer_finish(*tp, _RET_IP_); /* Until we run out of pending work to finish... */ while (!list_empty(&dop_pending) || !list_empty(&(*tp)->t_dfops)) { /* log intents and pull in intake items */ xfs_defer_create_intents(*tp); list_splice_tail_init(&(*tp)->t_dfops, &dop_pending); /* * Roll the transaction. */ error = xfs_defer_trans_roll(tp); if (error) goto out; /* Log an intent-done item for the first pending item. */ dfp = list_first_entry(&dop_pending, struct xfs_defer_pending, dfp_list); ops = defer_op_types[dfp->dfp_type]; trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp); dfp->dfp_done = ops->create_done(*tp, dfp->dfp_intent, dfp->dfp_count); /* Finish the work items. */ state = NULL; list_for_each_safe(li, n, &dfp->dfp_work) { list_del(li); dfp->dfp_count--; error = ops->finish_item(*tp, li, dfp->dfp_done, &state); if (error == -EAGAIN) { /* * Caller wants a fresh transaction; * put the work item back on the list * and jump out. */ list_add(li, &dfp->dfp_work); dfp->dfp_count++; break; } else if (error) { /* * Clean up after ourselves and jump out. * xfs_defer_cancel will take care of freeing * all these lists and stuff. */ if (ops->finish_cleanup) ops->finish_cleanup(*tp, state, error); goto out; } } if (error == -EAGAIN) { /* * Caller wants a fresh transaction, so log a * new log intent item to replace the old one * and roll the transaction. See "Requesting * a Fresh Transaction while Finishing * Deferred Work" above. */ dfp->dfp_intent = ops->create_intent(*tp, dfp->dfp_count); dfp->dfp_done = NULL; list_for_each(li, &dfp->dfp_work) ops->log_item(*tp, dfp->dfp_intent, li); } else { /* Done with the dfp, free it. */ list_del(&dfp->dfp_list); kmem_free(dfp); } if (ops->finish_cleanup) ops->finish_cleanup(*tp, state, error); } out: if (error) { xfs_defer_trans_abort(*tp, &dop_pending); xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); trace_xfs_defer_finish_error(*tp, error); xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending); xfs_defer_cancel(*tp); return error; } trace_xfs_defer_finish_done(*tp, _RET_IP_); return 0; } int xfs_defer_finish( struct xfs_trans **tp) { int error; /* * Finish and roll the transaction once more to avoid returning to the * caller with a dirty transaction. */ error = xfs_defer_finish_noroll(tp); if (error) return error; if ((*tp)->t_flags & XFS_TRANS_DIRTY) { error = xfs_defer_trans_roll(tp); if (error) { xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); return error; } } xfs_defer_reset(*tp); return 0; } void xfs_defer_cancel( struct xfs_trans *tp) { struct xfs_mount *mp = tp->t_mountp; trace_xfs_defer_cancel(tp, _RET_IP_); xfs_defer_cancel_list(mp, &tp->t_dfops); } /* Add an item for later deferred processing. */ void xfs_defer_add( struct xfs_trans *tp, enum xfs_defer_ops_type type, struct list_head *li) { struct xfs_defer_pending *dfp = NULL; const struct xfs_defer_op_type *ops; ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); BUILD_BUG_ON(ARRAY_SIZE(defer_op_types) != XFS_DEFER_OPS_TYPE_MAX); /* * Add the item to a pending item at the end of the intake list. * If the last pending item has the same type, reuse it. Else, * create a new pending item at the end of the intake list. */ if (!list_empty(&tp->t_dfops)) { dfp = list_last_entry(&tp->t_dfops, struct xfs_defer_pending, dfp_list); ops = defer_op_types[dfp->dfp_type]; if (dfp->dfp_type != type || (ops->max_items && dfp->dfp_count >= ops->max_items)) dfp = NULL; } if (!dfp) { dfp = kmem_alloc(sizeof(struct xfs_defer_pending), KM_SLEEP | KM_NOFS); dfp->dfp_type = type; dfp->dfp_intent = NULL; dfp->dfp_done = NULL; dfp->dfp_count = 0; INIT_LIST_HEAD(&dfp->dfp_work); list_add_tail(&dfp->dfp_list, &tp->t_dfops); } list_add_tail(li, &dfp->dfp_work); dfp->dfp_count++; } /* * Move deferred ops from one transaction to another and reset the source to * initial state. This is primarily used to carry state forward across * transaction rolls with pending dfops. */ void xfs_defer_move( struct xfs_trans *dtp, struct xfs_trans *stp) { list_splice_init(&stp->t_dfops, &dtp->t_dfops); /* * Low free space mode was historically controlled by a dfops field. * This meant that low mode state potentially carried across multiple * transaction rolls. Transfer low mode on a dfops move to preserve * that behavior. */ dtp->t_flags |= (stp->t_flags & XFS_TRANS_LOWMODE); xfs_defer_reset(stp); } xfsprogs-5.3.0/libxfs/xfs_defer.h0000644000175000017500000000413713466663244016674 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_DEFER_H__ #define __XFS_DEFER_H__ struct xfs_defer_op_type; /* * Header for deferred operation list. */ enum xfs_defer_ops_type { XFS_DEFER_OPS_TYPE_BMAP, XFS_DEFER_OPS_TYPE_REFCOUNT, XFS_DEFER_OPS_TYPE_RMAP, XFS_DEFER_OPS_TYPE_FREE, XFS_DEFER_OPS_TYPE_AGFL_FREE, XFS_DEFER_OPS_TYPE_MAX, }; /* * Save a log intent item and a list of extents, so that we can replay * whatever action had to happen to the extent list and file the log done * item. */ struct xfs_defer_pending { struct list_head dfp_list; /* pending items */ struct list_head dfp_work; /* work items */ void *dfp_intent; /* log intent item */ void *dfp_done; /* log done item */ unsigned int dfp_count; /* # extent items */ enum xfs_defer_ops_type dfp_type; }; void xfs_defer_add(struct xfs_trans *tp, enum xfs_defer_ops_type type, struct list_head *h); int xfs_defer_finish_noroll(struct xfs_trans **tp); int xfs_defer_finish(struct xfs_trans **tp); void xfs_defer_cancel(struct xfs_trans *); void xfs_defer_move(struct xfs_trans *dtp, struct xfs_trans *stp); /* Description of a deferred type. */ struct xfs_defer_op_type { void (*abort_intent)(void *); void *(*create_done)(struct xfs_trans *, void *, unsigned int); int (*finish_item)(struct xfs_trans *, struct list_head *, void *, void **); void (*finish_cleanup)(struct xfs_trans *, void *, int); void (*cancel_item)(struct list_head *); int (*diff_items)(void *, struct list_head *, struct list_head *); void *(*create_intent)(struct xfs_trans *, uint); void (*log_item)(struct xfs_trans *, void *, struct list_head *); unsigned int max_items; }; extern const struct xfs_defer_op_type xfs_bmap_update_defer_type; extern const struct xfs_defer_op_type xfs_refcount_update_defer_type; extern const struct xfs_defer_op_type xfs_rmap_update_defer_type; extern const struct xfs_defer_op_type xfs_extent_free_defer_type; extern const struct xfs_defer_op_type xfs_agfl_free_defer_type; #endif /* __XFS_DEFER_H__ */ xfsprogs-5.3.0/libxfs/xfs_dir2.c0000644000175000017500000004056213570057155016436 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR }; /* * Convert inode mode to directory entry filetype */ unsigned char xfs_mode_to_ftype( int mode) { switch (mode & S_IFMT) { case S_IFREG: return XFS_DIR3_FT_REG_FILE; case S_IFDIR: return XFS_DIR3_FT_DIR; case S_IFCHR: return XFS_DIR3_FT_CHRDEV; case S_IFBLK: return XFS_DIR3_FT_BLKDEV; case S_IFIFO: return XFS_DIR3_FT_FIFO; case S_IFSOCK: return XFS_DIR3_FT_SOCK; case S_IFLNK: return XFS_DIR3_FT_SYMLINK; default: return XFS_DIR3_FT_UNKNOWN; } } /* * ASCII case-insensitive (ie. A-Z) support for directories that was * used in IRIX. */ STATIC xfs_dahash_t xfs_ascii_ci_hashname( struct xfs_name *name) { xfs_dahash_t hash; int i; for (i = 0, hash = 0; i < name->len; i++) hash = tolower(name->name[i]) ^ rol32(hash, 7); return hash; } STATIC enum xfs_dacmp xfs_ascii_ci_compname( struct xfs_da_args *args, const unsigned char *name, int len) { enum xfs_dacmp result; int i; if (args->namelen != len) return XFS_CMP_DIFFERENT; result = XFS_CMP_EXACT; for (i = 0; i < len; i++) { if (args->name[i] == name[i]) continue; if (tolower(args->name[i]) != tolower(name[i])) return XFS_CMP_DIFFERENT; result = XFS_CMP_CASE; } return result; } static const struct xfs_nameops xfs_ascii_ci_nameops = { .hashname = xfs_ascii_ci_hashname, .compname = xfs_ascii_ci_compname, }; int xfs_da_mount( struct xfs_mount *mp) { struct xfs_da_geometry *dageo; int nodehdr_size; ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT); ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE); mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL); mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL); nodehdr_size = mp->m_dir_inode_ops->node_hdr_size; mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry), KM_SLEEP | KM_MAYFAIL); mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry), KM_SLEEP | KM_MAYFAIL); if (!mp->m_dir_geo || !mp->m_attr_geo) { kmem_free(mp->m_dir_geo); kmem_free(mp->m_attr_geo); return -ENOMEM; } /* set up directory geometry */ dageo = mp->m_dir_geo; dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog; dageo->fsblog = mp->m_sb.sb_blocklog; dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb); dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog; /* * Now we've set up the block conversion variables, we can calculate the * segment block constants using the geometry structure. */ dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET); dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET); dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET); dageo->node_ents = (dageo->blksize - nodehdr_size) / (uint)sizeof(xfs_da_node_entry_t); dageo->magicpct = (dageo->blksize * 37) / 100; /* set up attribute geometry - single fsb only */ dageo = mp->m_attr_geo; dageo->blklog = mp->m_sb.sb_blocklog; dageo->fsblog = mp->m_sb.sb_blocklog; dageo->blksize = 1 << dageo->blklog; dageo->fsbcount = 1; dageo->node_ents = (dageo->blksize - nodehdr_size) / (uint)sizeof(xfs_da_node_entry_t); dageo->magicpct = (dageo->blksize * 37) / 100; if (xfs_sb_version_hasasciici(&mp->m_sb)) mp->m_dirnameops = &xfs_ascii_ci_nameops; else mp->m_dirnameops = &xfs_default_nameops; return 0; } void xfs_da_unmount( struct xfs_mount *mp) { kmem_free(mp->m_dir_geo); kmem_free(mp->m_attr_geo); } /* * Return 1 if directory contains only "." and "..". */ int xfs_dir_isempty( xfs_inode_t *dp) { xfs_dir2_sf_hdr_t *sfp; ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); if (dp->i_d.di_size == 0) /* might happen during shutdown. */ return 1; if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) return 0; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; return !sfp->count; } /* * Validate a given inode number. */ int xfs_dir_ino_validate( xfs_mount_t *mp, xfs_ino_t ino) { bool ino_ok = xfs_verify_dir_ino(mp, ino); if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) { xfs_warn(mp, "Invalid inode number 0x%Lx", (unsigned long long) ino); XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } return 0; } /* * Initialize a directory with its "." and ".." entries. */ int xfs_dir_init( xfs_trans_t *tp, xfs_inode_t *dp, xfs_inode_t *pdp) { struct xfs_da_args *args; int error; ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino); if (error) return error; args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->dp = dp; args->trans = tp; error = xfs_dir2_sf_create(args, pdp->i_ino); kmem_free(args); return error; } /* * Enter a name in a directory, or check for available space. * If inum is 0, only the available space test is performed. */ int xfs_dir_createname( struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t inum, /* new entry inode number */ xfs_extlen_t total) /* bmap's total block count */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); if (inum) { rval = xfs_dir_ino_validate(tp->t_mountp, inum); if (rval) return rval; XFS_STATS_INC(dp->i_mount, xs_dir_create); } args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->inumber = inum; args->dp = dp; args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; if (!inum) args->op_flags |= XFS_DA_OP_JUSTCHECK; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_addname(args); goto out_free; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_addname(args); goto out_free; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_addname(args); else rval = xfs_dir2_node_addname(args); out_free: kmem_free(args); return rval; } /* * If doing a CI lookup and case-insensitive match, dup actual name into * args.value. Return EEXIST for success (ie. name found) or an error. */ int xfs_dir_cilookup_result( struct xfs_da_args *args, const unsigned char *name, int len) { if (args->cmpresult == XFS_CMP_DIFFERENT) return -ENOENT; if (args->cmpresult != XFS_CMP_CASE || !(args->op_flags & XFS_DA_OP_CILOOKUP)) return -EEXIST; args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL); if (!args->value) return -ENOMEM; memcpy(args->value, name, len); args->valuelen = len; return -EEXIST; } /* * Lookup a name in a directory, give back the inode number. * If ci_name is not NULL, returns the actual name in ci_name if it differs * to name, or ci_name->name is set to NULL for an exact match. */ int xfs_dir_lookup( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name, xfs_ino_t *inum, /* out: inode number */ struct xfs_name *ci_name) /* out: actual name if CI match */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ int lock_mode; ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); XFS_STATS_INC(dp->i_mount, xs_dir_lookup); /* * We need to use KM_NOFS here so that lockdep will not throw false * positive deadlock warnings on a non-transactional lookup path. It is * safe to recurse into inode recalim in that case, but lockdep can't * easily be taught about it. Hence KM_NOFS avoids having to add more * lockdep Doing this avoids having to add a bunch of lockdep class * annotations into the reclaim path for the ilock. */ args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->dp = dp; args->whichfork = XFS_DATA_FORK; args->trans = tp; args->op_flags = XFS_DA_OP_OKNOENT; if (ci_name) args->op_flags |= XFS_DA_OP_CILOOKUP; lock_mode = xfs_ilock_data_map_shared(dp); if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_lookup(args); goto out_check_rval; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_lookup(args); goto out_check_rval; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_lookup(args); else rval = xfs_dir2_node_lookup(args); out_check_rval: if (rval == -EEXIST) rval = 0; if (!rval) { *inum = args->inumber; if (ci_name) { ci_name->name = args->value; ci_name->len = args->valuelen; } } out_free: xfs_iunlock(dp, lock_mode); kmem_free(args); return rval; } /* * Remove an entry from a directory. */ int xfs_dir_removename( struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t ino, xfs_extlen_t total) /* bmap's total block count */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); XFS_STATS_INC(dp->i_mount, xs_dir_remove); args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->inumber = ino; args->dp = dp; args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_removename(args); goto out_free; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_removename(args); goto out_free; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_removename(args); else rval = xfs_dir2_node_removename(args); out_free: kmem_free(args); return rval; } /* * Replace the inode number of a directory entry. */ int xfs_dir_replace( struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, /* name of entry to replace */ xfs_ino_t inum, /* new inode number */ xfs_extlen_t total) /* bmap's total block count */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); rval = xfs_dir_ino_validate(tp->t_mountp, inum); if (rval) return rval; args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->inumber = inum; args->dp = dp; args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_replace(args); goto out_free; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_replace(args); goto out_free; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_replace(args); else rval = xfs_dir2_node_replace(args); out_free: kmem_free(args); return rval; } /* * See if this entry can be added to the directory without allocating space. */ int xfs_dir_canenter( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name) /* name of entry to add */ { return xfs_dir_createname(tp, dp, name, 0, 0); } /* * Utility routines. */ /* * Add a block to the directory. * * This routine is for data and free blocks, not leaf/node blocks which are * handled by xfs_da_grow_inode. */ int xfs_dir2_grow_inode( struct xfs_da_args *args, int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ xfs_dir2_db_t *dbp) /* out: block number added */ { struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; xfs_fileoff_t bno; /* directory offset of new block */ int count; /* count of filesystem blocks */ int error; trace_xfs_dir2_grow_inode(args, space); /* * Set lowest possible block in the space requested. */ bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); count = args->geo->fsbcount; error = xfs_da_grow_inode_int(args, &bno, count); if (error) return error; *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno); /* * Update file's size if this is the data space and it grew. */ if (space == XFS_DIR2_DATA_SPACE) { xfs_fsize_t size; /* directory file (data) size */ size = XFS_FSB_TO_B(mp, bno + count); if (size > dp->i_d.di_size) { dp->i_d.di_size = size; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); } } return 0; } /* * See if the directory is a single-block form directory. */ int xfs_dir2_isblock( struct xfs_da_args *args, int *vp) /* out: 1 is block, 0 is not block */ { xfs_fileoff_t last; /* last file offset */ int rval; if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) return rval; rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize; if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize) return -EFSCORRUPTED; *vp = rval; return 0; } /* * See if the directory is a single-leaf form directory. */ int xfs_dir2_isleaf( struct xfs_da_args *args, int *vp) /* out: 1 is block, 0 is not block */ { xfs_fileoff_t last; /* last file offset */ int rval; if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) return rval; *vp = last == args->geo->leafblk + args->geo->fsbcount; return 0; } /* * Remove the given block from the directory. * This routine is used for data and free blocks, leaf/node are done * by xfs_da_shrink_inode. */ int xfs_dir2_shrink_inode( struct xfs_da_args *args, xfs_dir2_db_t db, struct xfs_buf *bp) { xfs_fileoff_t bno; /* directory file offset */ xfs_dablk_t da; /* directory file offset */ int done; /* bunmap is finished */ struct xfs_inode *dp; int error; struct xfs_mount *mp; struct xfs_trans *tp; trace_xfs_dir2_shrink_inode(args, db); dp = args->dp; mp = dp->i_mount; tp = args->trans; da = xfs_dir2_db_to_da(args->geo, db); /* Unmap the fsblock(s). */ error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done); if (error) { /* * ENOSPC actually can happen if we're in a removename with no * space reservation, and the resulting block removal would * cause a bmap btree split or conversion from extents to btree. * This can only happen for un-fragmented directory blocks, * since you need to be punching out the middle of an extent. * In this case we need to leave the block in the file, and not * binval it. So the block has to be in a consistent empty * state and appropriately logged. We don't free up the buffer, * the caller can tell it hasn't happened since it got an error * back. */ return error; } ASSERT(done); /* * Invalidate the buffer from the transaction. */ xfs_trans_binval(tp, bp); /* * If it's not a data block, we're done. */ if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)) return 0; /* * If the block isn't the last one in the directory, we're done. */ if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0)) return 0; bno = da; if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { /* * This can't really happen unless there's kernel corruption. */ return error; } if (db == args->geo->datablk) ASSERT(bno == 0); else ASSERT(bno > 0); /* * Set the size to the new last block. */ dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); return 0; } /* Returns true if the directory entry name is valid. */ bool xfs_dir2_namecheck( const void *name, size_t length) { /* * MAXNAMELEN includes the trailing null, but (name/length) leave it * out, so use >= for the length check. */ if (length >= MAXNAMELEN) return false; /* There shouldn't be any slashes or nulls here */ return !memchr(name, '/', length) && !memchr(name, 0, length); } xfsprogs-5.3.0/libxfs/xfs_dir2.h0000644000175000017500000002443113570057155016440 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_DIR2_H__ #define __XFS_DIR2_H__ #include "xfs_da_format.h" #include "xfs_da_btree.h" struct xfs_da_args; struct xfs_inode; struct xfs_mount; struct xfs_trans; struct xfs_dir2_sf_hdr; struct xfs_dir2_sf_entry; struct xfs_dir2_data_hdr; struct xfs_dir2_data_entry; struct xfs_dir2_data_unused; extern struct xfs_name xfs_name_dotdot; /* * Convert inode mode to directory entry filetype */ extern unsigned char xfs_mode_to_ftype(int mode); /* * directory operations vector for encode/decode routines */ struct xfs_dir_ops { int (*sf_entsize)(struct xfs_dir2_sf_hdr *hdr, int len); struct xfs_dir2_sf_entry * (*sf_nextentry)(struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep); uint8_t (*sf_get_ftype)(struct xfs_dir2_sf_entry *sfep); void (*sf_put_ftype)(struct xfs_dir2_sf_entry *sfep, uint8_t ftype); xfs_ino_t (*sf_get_ino)(struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep); void (*sf_put_ino)(struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino); xfs_ino_t (*sf_get_parent_ino)(struct xfs_dir2_sf_hdr *hdr); void (*sf_put_parent_ino)(struct xfs_dir2_sf_hdr *hdr, xfs_ino_t ino); int (*data_entsize)(int len); uint8_t (*data_get_ftype)(struct xfs_dir2_data_entry *dep); void (*data_put_ftype)(struct xfs_dir2_data_entry *dep, uint8_t ftype); __be16 * (*data_entry_tag_p)(struct xfs_dir2_data_entry *dep); struct xfs_dir2_data_free * (*data_bestfree_p)(struct xfs_dir2_data_hdr *hdr); xfs_dir2_data_aoff_t data_dot_offset; xfs_dir2_data_aoff_t data_dotdot_offset; xfs_dir2_data_aoff_t data_first_offset; size_t data_entry_offset; struct xfs_dir2_data_entry * (*data_dot_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_entry * (*data_dotdot_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_entry * (*data_first_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_entry * (*data_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_unused * (*data_unused_p)(struct xfs_dir2_data_hdr *hdr); int leaf_hdr_size; void (*leaf_hdr_to_disk)(struct xfs_dir2_leaf *to, struct xfs_dir3_icleaf_hdr *from); void (*leaf_hdr_from_disk)(struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from); int (*leaf_max_ents)(struct xfs_da_geometry *geo); struct xfs_dir2_leaf_entry * (*leaf_ents_p)(struct xfs_dir2_leaf *lp); int node_hdr_size; void (*node_hdr_to_disk)(struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from); void (*node_hdr_from_disk)(struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from); struct xfs_da_node_entry * (*node_tree_p)(struct xfs_da_intnode *dap); int free_hdr_size; void (*free_hdr_to_disk)(struct xfs_dir2_free *to, struct xfs_dir3_icfree_hdr *from); void (*free_hdr_from_disk)(struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from); int (*free_max_bests)(struct xfs_da_geometry *geo); __be16 * (*free_bests_p)(struct xfs_dir2_free *free); xfs_dir2_db_t (*db_to_fdb)(struct xfs_da_geometry *geo, xfs_dir2_db_t db); int (*db_to_fdindex)(struct xfs_da_geometry *geo, xfs_dir2_db_t db); }; extern const struct xfs_dir_ops * xfs_dir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp); extern const struct xfs_dir_ops * xfs_nondir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp); /* * Generic directory interface routines */ extern void xfs_dir_startup(void); extern int xfs_da_mount(struct xfs_mount *mp); extern void xfs_da_unmount(struct xfs_mount *mp); extern int xfs_dir_isempty(struct xfs_inode *dp); extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_inode *pdp); extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t inum, xfs_extlen_t tot); extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t *inum, struct xfs_name *ci_name); extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t ino, xfs_extlen_t tot); extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t inum, xfs_extlen_t tot); extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name); /* * Direct call from the bmap code, bypassing the generic directory layer. */ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args); /* * Interface routines used by userspace utilities */ extern int xfs_dir2_isblock(struct xfs_da_args *args, int *r); extern int xfs_dir2_isleaf(struct xfs_da_args *args, int *r); extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, struct xfs_buf *bp); extern void xfs_dir2_data_freescan_int(struct xfs_da_geometry *geo, const struct xfs_dir_ops *ops, struct xfs_dir2_data_hdr *hdr, int *loghead); extern void xfs_dir2_data_freescan(struct xfs_inode *dp, struct xfs_dir2_data_hdr *hdr, int *loghead); extern void xfs_dir2_data_log_entry(struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_entry *dep); extern void xfs_dir2_data_log_header(struct xfs_da_args *args, struct xfs_buf *bp); extern void xfs_dir2_data_log_unused(struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_unused *dup); extern void xfs_dir2_data_make_free(struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp); extern int xfs_dir2_data_use_free(struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_unused *dup, xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp); extern struct xfs_dir2_data_free *xfs_dir2_data_freefind( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup); extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); extern const struct xfs_buf_ops xfs_dir3_block_buf_ops; extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops; extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops; extern const struct xfs_buf_ops xfs_dir3_free_buf_ops; extern const struct xfs_buf_ops xfs_dir3_data_buf_ops; /* * Directory offset/block conversion functions. * * DB blocks here are logical directory block numbers, not filesystem blocks. */ /* * Convert dataptr to byte in file space */ static inline xfs_dir2_off_t xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp) { return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG; } /* * Convert byte in file space to dataptr. It had better be aligned. */ static inline xfs_dir2_dataptr_t xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by) { return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG); } /* * Convert byte in space to (DB) block */ static inline xfs_dir2_db_t xfs_dir2_byte_to_db(struct xfs_da_geometry *geo, xfs_dir2_off_t by) { return (xfs_dir2_db_t)(by >> geo->blklog); } /* * Convert dataptr to a block number */ static inline xfs_dir2_db_t xfs_dir2_dataptr_to_db(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp) { return xfs_dir2_byte_to_db(geo, xfs_dir2_dataptr_to_byte(dp)); } /* * Convert byte in space to offset in a block */ static inline xfs_dir2_data_aoff_t xfs_dir2_byte_to_off(struct xfs_da_geometry *geo, xfs_dir2_off_t by) { return (xfs_dir2_data_aoff_t)(by & (geo->blksize - 1)); } /* * Convert dataptr to a byte offset in a block */ static inline xfs_dir2_data_aoff_t xfs_dir2_dataptr_to_off(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp) { return xfs_dir2_byte_to_off(geo, xfs_dir2_dataptr_to_byte(dp)); } /* * Convert block and offset to byte in space */ static inline xfs_dir2_off_t xfs_dir2_db_off_to_byte(struct xfs_da_geometry *geo, xfs_dir2_db_t db, xfs_dir2_data_aoff_t o) { return ((xfs_dir2_off_t)db << geo->blklog) + o; } /* * Convert block (DB) to block (dablk) */ static inline xfs_dablk_t xfs_dir2_db_to_da(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return (xfs_dablk_t)(db << (geo->blklog - geo->fsblog)); } /* * Convert byte in space to (DA) block */ static inline xfs_dablk_t xfs_dir2_byte_to_da(struct xfs_da_geometry *geo, xfs_dir2_off_t by) { return xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, by)); } /* * Convert block and offset to dataptr */ static inline xfs_dir2_dataptr_t xfs_dir2_db_off_to_dataptr(struct xfs_da_geometry *geo, xfs_dir2_db_t db, xfs_dir2_data_aoff_t o) { return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(geo, db, o)); } /* * Convert block (dablk) to block (DB) */ static inline xfs_dir2_db_t xfs_dir2_da_to_db(struct xfs_da_geometry *geo, xfs_dablk_t da) { return (xfs_dir2_db_t)(da >> (geo->blklog - geo->fsblog)); } /* * Convert block (dablk) to byte offset in space */ static inline xfs_dir2_off_t xfs_dir2_da_to_byte(struct xfs_da_geometry *geo, xfs_dablk_t da) { return xfs_dir2_db_off_to_byte(geo, xfs_dir2_da_to_db(geo, da), 0); } /* * Directory tail pointer accessor functions. Based on block geometry. */ static inline struct xfs_dir2_block_tail * xfs_dir2_block_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr) { return ((struct xfs_dir2_block_tail *) ((char *)hdr + geo->blksize)) - 1; } static inline struct xfs_dir2_leaf_tail * xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp) { return (struct xfs_dir2_leaf_tail *) ((char *)lp + geo->blksize - sizeof(struct xfs_dir2_leaf_tail)); } /* * The Linux API doesn't pass down the total size of the buffer * we read into down to the filesystem. With the filldir concept * it's not needed for correct information, but the XFS dir2 leaf * code wants an estimate of the buffer size to calculate it's * readahead window and size the buffers used for mapping to * physical blocks. * * Try to give it an estimate that's good enough, maybe at some * point we can change the ->readdir prototype to include the * buffer size. For now we use the current glibc buffer size. * musl libc hardcodes 2k and dietlibc uses PAGE_SIZE. */ #define XFS_READDIR_BUFSIZE (32768) unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp, uint8_t filetype); void *xfs_dir3_data_endp(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr); bool xfs_dir2_namecheck(const void *name, size_t length); #endif /* __XFS_DIR2_H__ */ xfsprogs-5.3.0/libxfs/xfs_dir2_block.c0000644000175000017500000010527313570057155017611 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" /* * Local function prototypes. */ static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, struct xfs_buf *bp, int first, int last); static void xfs_dir2_block_log_tail(xfs_trans_t *tp, struct xfs_buf *bp); static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, struct xfs_buf **bpp, int *entno); static int xfs_dir2_block_sort(const void *a, const void *b); static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; /* * One-time startup routine called from xfs_init(). */ void xfs_dir_startup(void) { xfs_dir_hash_dot = xfs_da_hashname((unsigned char *)".", 1); xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); } static xfs_failaddr_t xfs_dir3_block_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (!xfs_verify_magic(bp, hdr3->magic)) return __this_address; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) return __this_address; } return __xfs_dir3_data_check(NULL, bp); } static void xfs_dir3_block_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_dir3_block_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_dir3_block_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_dir3_block_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_block_buf_ops = { .name = "xfs_dir3_block", .magic = { cpu_to_be32(XFS_DIR2_BLOCK_MAGIC), cpu_to_be32(XFS_DIR3_BLOCK_MAGIC) }, .verify_read = xfs_dir3_block_read_verify, .verify_write = xfs_dir3_block_write_verify, .verify_struct = xfs_dir3_block_verify, }; int xfs_dir3_block_read( struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_buf **bpp) { struct xfs_mount *mp = dp->i_mount; int err; err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp, XFS_DATA_FORK, &xfs_dir3_block_buf_ops); if (!err && tp && *bpp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF); return err; } static void xfs_dir3_block_init( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *dp) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; bp->b_ops = &xfs_dir3_block_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_BLOCK_BUF); if (xfs_sb_version_hascrc(&mp->m_sb)) { memset(hdr3, 0, sizeof(*hdr3)); hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); hdr3->blkno = cpu_to_be64(bp->b_bn); hdr3->owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); return; } hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); } static void xfs_dir2_block_need_space( struct xfs_inode *dp, struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_block_tail *btp, struct xfs_dir2_leaf_entry *blp, __be16 **tagpp, struct xfs_dir2_data_unused **dupp, struct xfs_dir2_data_unused **enddupp, int *compact, int len) { struct xfs_dir2_data_free *bf; __be16 *tagp = NULL; struct xfs_dir2_data_unused *dup = NULL; struct xfs_dir2_data_unused *enddup = NULL; *compact = 0; bf = dp->d_ops->data_bestfree_p(hdr); /* * If there are stale entries we'll use one for the leaf. */ if (btp->stale) { if (be16_to_cpu(bf[0].length) >= len) { /* * The biggest entry enough to avoid compaction. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); goto out; } /* * Will need to compact to make this work. * Tag just before the first leaf entry. */ *compact = 1; tagp = (__be16 *)blp - 1; /* Data object just before the first leaf entry. */ dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); /* * If it's not free then the data will go where the * leaf data starts now, if it works at all. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len) dup = NULL; } else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len) dup = NULL; else dup = (xfs_dir2_data_unused_t *)blp; goto out; } /* * no stale entries, so just use free space. * Tag just before the first leaf entry. */ tagp = (__be16 *)blp - 1; /* Data object just before the first leaf entry. */ enddup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); /* * If it's not free then can't do this add without cleaning up: * the space before the first leaf entry needs to be free so it * can be expanded to hold the pointer to the new entry. */ if (be16_to_cpu(enddup->freetag) == XFS_DIR2_DATA_FREE_TAG) { /* * Check out the biggest freespace and see if it's the same one. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); if (dup != enddup) { /* * Not the same free entry, just check its length. */ if (be16_to_cpu(dup->length) < len) dup = NULL; goto out; } /* * It is the biggest freespace, can it hold the leaf too? */ if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) { /* * Yes, use the second-largest entry instead if it works. */ if (be16_to_cpu(bf[1].length) >= len) dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[1].offset)); else dup = NULL; } } out: *tagpp = tagp; *dupp = dup; *enddupp = enddup; } /* * compact the leaf entries. * Leave the highest-numbered stale entry stale. * XXX should be the one closest to mid but mid is not yet computed. */ static void xfs_dir2_block_compact( struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_block_tail *btp, struct xfs_dir2_leaf_entry *blp, int *needlog, int *lfloghigh, int *lfloglow) { int fromidx; /* source leaf index */ int toidx; /* target leaf index */ int needscan = 0; int highstale; /* high stale index */ fromidx = toidx = be32_to_cpu(btp->count) - 1; highstale = *lfloghigh = -1; for (; fromidx >= 0; fromidx--) { if (blp[fromidx].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) { if (highstale == -1) highstale = toidx; else { if (*lfloghigh == -1) *lfloghigh = toidx; continue; } } if (fromidx < toidx) blp[toidx] = blp[fromidx]; toidx--; } *lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1); *lfloghigh -= be32_to_cpu(btp->stale) - 1; be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1)); xfs_dir2_data_make_free(args, bp, (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)), needlog, &needscan); btp->stale = cpu_to_be32(1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. */ if (needscan) xfs_dir2_data_freescan(args->dp, hdr, needlog); } /* * Add an entry to a block directory. */ int /* error */ xfs_dir2_block_addname( xfs_da_args_t *args) /* directory op arguments */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* buffer for block */ xfs_dir2_block_tail_t *btp; /* block tail */ int compact; /* need to compact leaf ents */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* directory inode */ xfs_dir2_data_unused_t *dup; /* block unused entry */ int error; /* error return value */ xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ xfs_dahash_t hash; /* hash value of found entry */ int high; /* high index for binary srch */ int highstale; /* high stale index */ int lfloghigh=0; /* last final leaf to log */ int lfloglow=0; /* first final leaf to log */ int len; /* length of the new entry */ int low; /* low index for binary srch */ int lowstale; /* low stale index */ int mid=0; /* midpoint for binary srch */ int needlog; /* need to log header */ int needscan; /* need to rescan freespace */ __be16 *tagp; /* pointer to tag value */ xfs_trans_t *tp; /* transaction structure */ trace_xfs_dir2_block_addname(args); dp = args->dp; tp = args->trans; /* Read the (one and only) directory block into bp. */ error = xfs_dir3_block_read(tp, dp, &bp); if (error) return error; len = dp->d_ops->data_entsize(args->namelen); /* * Set up pointers to parts of the block. */ hdr = bp->b_addr; btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Find out if we can reuse stale entries or whether we need extra * space for entry and new leaf. */ xfs_dir2_block_need_space(dp, hdr, btp, blp, &tagp, &dup, &enddup, &compact, len); /* * Done everything we need for a space check now. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) { xfs_trans_brelse(tp, bp); if (!dup) return -ENOSPC; return 0; } /* * If we don't have space for the new entry & leaf ... */ if (!dup) { /* Don't have a space reservation: return no-space. */ if (args->total == 0) return -ENOSPC; /* * Convert to the next larger format. * Then add the new entry in that format. */ error = xfs_dir2_block_to_leaf(args, bp); if (error) return error; return xfs_dir2_leaf_addname(args); } needlog = needscan = 0; /* * If need to compact the leaf entries, do it now. */ if (compact) { xfs_dir2_block_compact(args, bp, hdr, btp, blp, &needlog, &lfloghigh, &lfloglow); /* recalculate blp post-compaction */ blp = xfs_dir2_block_leaf_p(btp); } else if (btp->stale) { /* * Set leaf logging boundaries to impossible state. * For the no-stale case they're set explicitly. */ lfloglow = be32_to_cpu(btp->count); lfloghigh = -1; } /* * Find the slot that's first lower than our hash value, -1 if none. */ for (low = 0, high = be32_to_cpu(btp->count) - 1; low <= high; ) { mid = (low + high) >> 1; if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval) break; if (hash < args->hashval) low = mid + 1; else high = mid - 1; } while (mid >= 0 && be32_to_cpu(blp[mid].hashval) >= args->hashval) { mid--; } /* * No stale entries, will use enddup space to hold new leaf. */ if (!btp->stale) { xfs_dir2_data_aoff_t aoff; /* * Mark the space needed for the new leaf entry, now in use. */ aoff = (xfs_dir2_data_aoff_t)((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) - sizeof(*blp)); error = xfs_dir2_data_use_free(args, bp, enddup, aoff, (xfs_dir2_data_aoff_t)sizeof(*blp), &needlog, &needscan); if (error) return error; /* * Update the tail (entry count). */ be32_add_cpu(&btp->count, 1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. */ if (needscan) { xfs_dir2_data_freescan(dp, hdr, &needlog); needscan = 0; } /* * Adjust pointer to the first leaf entry, we're about to move * the table up one to open up space for the new leaf entry. * Then adjust our index to match. */ blp--; mid++; if (mid) memmove(blp, &blp[1], mid * sizeof(*blp)); lfloglow = 0; lfloghigh = mid; } /* * Use a stale leaf for our new entry. */ else { for (lowstale = mid; lowstale >= 0 && blp[lowstale].address != cpu_to_be32(XFS_DIR2_NULL_DATAPTR); lowstale--) continue; for (highstale = mid + 1; highstale < be32_to_cpu(btp->count) && blp[highstale].address != cpu_to_be32(XFS_DIR2_NULL_DATAPTR) && (lowstale < 0 || mid - lowstale > highstale - mid); highstale++) continue; /* * Move entries toward the low-numbered stale entry. */ if (lowstale >= 0 && (highstale == be32_to_cpu(btp->count) || mid - lowstale <= highstale - mid)) { if (mid - lowstale) memmove(&blp[lowstale], &blp[lowstale + 1], (mid - lowstale) * sizeof(*blp)); lfloglow = min(lowstale, lfloglow); lfloghigh = max(mid, lfloghigh); } /* * Move entries toward the high-numbered stale entry. */ else { ASSERT(highstale < be32_to_cpu(btp->count)); mid++; if (highstale - mid) memmove(&blp[mid + 1], &blp[mid], (highstale - mid) * sizeof(*blp)); lfloglow = min(mid, lfloglow); lfloghigh = max(highstale, lfloghigh); } be32_add_cpu(&btp->stale, -1); } /* * Point to the new data entry. */ dep = (xfs_dir2_data_entry_t *)dup; /* * Fill in the leaf entry. */ blp[mid].hashval = cpu_to_be32(args->hashval); blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); /* * Mark space for the data entry used. */ error = xfs_dir2_data_use_free(args, bp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), (xfs_dir2_data_aoff_t)len, &needlog, &needscan); if (error) return error; /* * Create the new data entry. */ dep->inumber = cpu_to_be64(args->inumber); dep->namelen = args->namelen; memcpy(dep->name, args->name, args->namelen); dp->d_ops->data_put_ftype(dep, args->filetype); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); /* * Clean up the bestfree array and log the header, tail, and entry. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, bp); xfs_dir2_block_log_tail(tp, bp); xfs_dir2_data_log_entry(args, bp, dep); xfs_dir3_data_check(dp, bp); return 0; } /* * Log leaf entries from the block. */ static void xfs_dir2_block_log_leaf( xfs_trans_t *tp, /* transaction structure */ struct xfs_buf *bp, /* block buffer */ int first, /* index of first logged leaf */ int last) /* index of last logged leaf */ { xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_leaf_entry_t *blp; xfs_dir2_block_tail_t *btp; btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr); blp = xfs_dir2_block_leaf_p(btp); xfs_trans_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr), (uint)((char *)&blp[last + 1] - (char *)hdr - 1)); } /* * Log the block tail. */ static void xfs_dir2_block_log_tail( xfs_trans_t *tp, /* transaction structure */ struct xfs_buf *bp) /* block buffer */ { xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_block_tail_t *btp; btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr); xfs_trans_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr), (uint)((char *)(btp + 1) - (char *)hdr - 1)); } /* * Look up an entry in the block. This is the external routine, * xfs_dir2_block_lookup_int does the real work. */ int /* error */ xfs_dir2_block_lookup( xfs_da_args_t *args) /* dir lookup arguments */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int ent; /* entry index */ int error; /* error return value */ trace_xfs_dir2_block_lookup(args); /* * Get the buffer, look up the entry. * If not found (ENOENT) then return, have no buffer. */ if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) return error; dp = args->dp; hdr = bp->b_addr; xfs_dir3_data_check(dp, bp); btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Get the offset from the leaf entry, to point to the data. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(blp[ent].address))); /* * Fill in inode number, CI name if appropriate, release the block. */ args->inumber = be64_to_cpu(dep->inumber); args->filetype = dp->d_ops->data_get_ftype(dep); error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); xfs_trans_brelse(args->trans, bp); return error; } /* * Internal block lookup routine. */ static int /* error */ xfs_dir2_block_lookup_int( xfs_da_args_t *args, /* dir lookup arguments */ struct xfs_buf **bpp, /* returned block buffer */ int *entno) /* returned entry number */ { xfs_dir2_dataptr_t addr; /* data entry address */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int error; /* error return value */ xfs_dahash_t hash; /* found hash value */ int high; /* binary search high index */ int low; /* binary search low index */ int mid; /* binary search current idx */ xfs_mount_t *mp; /* filesystem mount point */ xfs_trans_t *tp; /* transaction pointer */ enum xfs_dacmp cmp; /* comparison result */ dp = args->dp; tp = args->trans; mp = dp->i_mount; error = xfs_dir3_block_read(tp, dp, &bp); if (error) return error; hdr = bp->b_addr; xfs_dir3_data_check(dp, bp); btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Loop doing a binary search for our hash value. * Find our entry, ENOENT if it's not there. */ for (low = 0, high = be32_to_cpu(btp->count) - 1; ; ) { ASSERT(low <= high); mid = (low + high) >> 1; if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval) break; if (hash < args->hashval) low = mid + 1; else high = mid - 1; if (low > high) { ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); xfs_trans_brelse(tp, bp); return -ENOENT; } } /* * Back up to the first one with the right hash value. */ while (mid > 0 && be32_to_cpu(blp[mid - 1].hashval) == args->hashval) { mid--; } /* * Now loop forward through all the entries with the * right hash value looking for our name. */ do { if ((addr = be32_to_cpu(blp[mid].address)) == XFS_DIR2_NULL_DATAPTR) continue; /* * Get pointer to the entry from the leaf. */ dep = (xfs_dir2_data_entry_t *) ((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, addr)); /* * Compare name and if it's an exact match, return the index * and buffer. If it's the first case-insensitive match, store * the index and buffer and continue looking for an exact match. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; *bpp = bp; *entno = mid; if (cmp == XFS_CMP_EXACT) return 0; } } while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash); ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or replace). * If a case-insensitive match was found earlier, return success. */ if (args->cmpresult == XFS_CMP_CASE) return 0; /* * No match, release the buffer and return ENOENT. */ xfs_trans_brelse(tp, bp); return -ENOENT; } /* * Remove an entry from a block format directory. * If that makes the block small enough to fit in shortform, transform it. */ int /* error */ xfs_dir2_block_removename( xfs_da_args_t *args) /* directory operation args */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int ent; /* block leaf entry index */ int error; /* error return value */ int needlog; /* need to log block header */ int needscan; /* need to fixup bestfree */ xfs_dir2_sf_hdr_t sfh; /* shortform header */ int size; /* shortform size */ xfs_trans_t *tp; /* transaction pointer */ trace_xfs_dir2_block_removename(args); /* * Look up the entry in the block. Gets the buffer and entry index. * It will always be there, the vnodeops level does a lookup first. */ if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { return error; } dp = args->dp; tp = args->trans; hdr = bp->b_addr; btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Point to the data entry using the leaf entry. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(blp[ent].address))); /* * Mark the data entry's space free. */ needlog = needscan = 0; xfs_dir2_data_make_free(args, bp, (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); /* * Fix up the block tail. */ be32_add_cpu(&btp->stale, 1); xfs_dir2_block_log_tail(tp, bp); /* * Remove the leaf entry by marking it stale. */ blp[ent].address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir2_block_log_leaf(tp, bp, ent, ent); /* * Fix up bestfree, log the header if necessary. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, bp); xfs_dir3_data_check(dp, bp); /* * See if the size as a shortform is good enough. */ size = xfs_dir2_block_sfsize(dp, hdr, &sfh); if (size > XFS_IFORK_DSIZE(dp)) return 0; /* * If it works, do the conversion. */ return xfs_dir2_block_to_sf(args, bp, size, &sfh); } /* * Replace an entry in a V2 block directory. * Change the inode number to the new value. */ int /* error */ xfs_dir2_block_replace( xfs_da_args_t *args) /* directory operation args */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int ent; /* leaf entry index */ int error; /* error return value */ trace_xfs_dir2_block_replace(args); /* * Lookup the entry in the directory. Get buffer and entry index. * This will always succeed since the caller has already done a lookup. */ if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { return error; } dp = args->dp; hdr = bp->b_addr; btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Point to the data entry we need to change. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(blp[ent].address))); ASSERT(be64_to_cpu(dep->inumber) != args->inumber); /* * Change the inode number to the new value. */ dep->inumber = cpu_to_be64(args->inumber); dp->d_ops->data_put_ftype(dep, args->filetype); xfs_dir2_data_log_entry(args, bp, dep); xfs_dir3_data_check(dp, bp); return 0; } /* * Qsort comparison routine for the block leaf entries. */ static int /* sort order */ xfs_dir2_block_sort( const void *a, /* first leaf entry */ const void *b) /* second leaf entry */ { const xfs_dir2_leaf_entry_t *la; /* first leaf entry */ const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */ la = a; lb = b; return be32_to_cpu(la->hashval) < be32_to_cpu(lb->hashval) ? -1 : (be32_to_cpu(la->hashval) > be32_to_cpu(lb->hashval) ? 1 : 0); } /* * Convert a V2 leaf directory to a V2 block directory if possible. */ int /* error */ xfs_dir2_leaf_to_block( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp, /* leaf buffer */ struct xfs_buf *dbp) /* data buffer */ { __be16 *bestsp; /* leaf bests table */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* unused data entry */ int error; /* error return value */ int from; /* leaf from index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_mount_t *mp; /* file system mount point */ int needlog; /* need to log data header */ int needscan; /* need to scan for bestfree */ xfs_dir2_sf_hdr_t sfh; /* shortform header */ int size; /* bytes used */ __be16 *tagp; /* end of entry (tag) */ int to; /* block/leaf to index */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_leaf_to_block(args); dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = lbp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC || leafhdr.magic == XFS_DIR3_LEAF1_MAGIC); /* * If there are data blocks other than the first one, take this * opportunity to remove trailing empty data blocks that may have * been left behind during no-space-reservation operations. * These will show up in the leaf bests table. */ while (dp->i_d.di_size > args->geo->blksize) { int hdrsz; hdrsz = dp->d_ops->data_entry_offset; bestsp = xfs_dir2_leaf_bests_p(ltp); if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == args->geo->blksize - hdrsz) { if ((error = xfs_dir2_leaf_trim_data(args, lbp, (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) return error; } else return 0; } /* * Read the data block if we don't already have it, give up if it fails. */ if (!dbp) { error = xfs_dir3_data_read(tp, dp, args->geo->datablk, -1, &dbp); if (error) return error; } hdr = dbp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); /* * Size of the "leaf" area in the block. */ size = (uint)sizeof(xfs_dir2_block_tail_t) + (uint)sizeof(*lep) * (leafhdr.count - leafhdr.stale); /* * Look at the last data entry. */ tagp = (__be16 *)((char *)hdr + args->geo->blksize) - 1; dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); /* * If it's not free or is too short we can't do it. */ if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG || be16_to_cpu(dup->length) < size) return 0; /* * Start converting it to block form. */ xfs_dir3_block_init(mp, tp, dbp, dp); needlog = 1; needscan = 0; /* * Use up the space at the end of the block (blp/btp). */ error = xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size, &needlog, &needscan); if (error) return error; /* * Initialize the block tail. */ btp = xfs_dir2_block_tail_p(args->geo, hdr); btp->count = cpu_to_be32(leafhdr.count - leafhdr.stale); btp->stale = 0; xfs_dir2_block_log_tail(tp, dbp); /* * Initialize the block leaf area. We compact out stale entries. */ lep = xfs_dir2_block_leaf_p(btp); for (from = to = 0; from < leafhdr.count; from++) { if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) continue; lep[to++] = ents[from]; } ASSERT(to == be32_to_cpu(btp->count)); xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1); /* * Scan the bestfree if we need it and log the data block header. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, dbp); /* * Pitch the old leaf block. */ error = xfs_da_shrink_inode(args, args->geo->leafblk, lbp); if (error) return error; /* * Now see if the resulting block can be shrunken to shortform. */ size = xfs_dir2_block_sfsize(dp, hdr, &sfh); if (size > XFS_IFORK_DSIZE(dp)) return 0; return xfs_dir2_block_to_sf(args, dbp, size, &sfh); } /* * Convert the shortform directory to block form. */ int /* error */ xfs_dir2_sf_to_block( xfs_da_args_t *args) /* operation arguments */ { xfs_dir2_db_t blkno; /* dir-relative block # (0) */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail pointer */ xfs_dir2_data_entry_t *dep; /* data entry pointer */ xfs_inode_t *dp; /* incore directory inode */ int dummy; /* trash */ xfs_dir2_data_unused_t *dup; /* unused entry pointer */ int endoffset; /* end of data objects */ int error; /* error return value */ int i; /* index */ xfs_mount_t *mp; /* filesystem mount point */ int needlog; /* need to log block header */ int needscan; /* need to scan block freespc */ int newoffset; /* offset from current entry */ int offset; /* target block offset */ xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */ xfs_dir2_sf_hdr_t *oldsfp; /* old shortform header */ xfs_dir2_sf_hdr_t *sfp; /* shortform header */ __be16 *tagp; /* end of data entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_name name; struct xfs_ifork *ifp; trace_xfs_dir2_sf_to_block(args); dp = args->dp; tp = args->trans; mp = dp->i_mount; ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); ASSERT(ifp->if_flags & XFS_IFINLINE); /* * Bomb out if the shortform directory is way too short. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(mp)); return -EIO; } oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data; ASSERT(ifp->if_bytes == dp->i_d.di_size); ASSERT(ifp->if_u1.if_data != NULL); ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count)); ASSERT(dp->i_d.di_nextents == 0); /* * Copy the directory into a temporary buffer. * Then pitch the incore inode data so we can make extents. */ sfp = kmem_alloc(ifp->if_bytes, KM_SLEEP); memcpy(sfp, oldsfp, ifp->if_bytes); xfs_idata_realloc(dp, -ifp->if_bytes, XFS_DATA_FORK); xfs_bmap_local_to_extents_empty(dp, XFS_DATA_FORK); dp->i_d.di_size = 0; /* * Add block 0 to the inode. */ error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); if (error) goto out_free; /* * Initialize the data block, then convert it to block format. */ error = xfs_dir3_data_init(args, blkno, &bp); if (error) goto out_free; xfs_dir3_block_init(mp, tp, bp, dp); hdr = bp->b_addr; /* * Compute size of block "tail" area. */ i = (uint)sizeof(*btp) + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t); /* * The whole thing is initialized to free by the init routine. * Say we're using the leaf and tail area. */ dup = dp->d_ops->data_unused_p(hdr); needlog = needscan = 0; error = xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i, i, &needlog, &needscan); if (error) goto out_free; ASSERT(needscan == 0); /* * Fill in the tail. */ btp = xfs_dir2_block_tail_p(args->geo, hdr); btp->count = cpu_to_be32(sfp->count + 2); /* ., .. */ btp->stale = 0; blp = xfs_dir2_block_leaf_p(btp); endoffset = (uint)((char *)blp - (char *)hdr); /* * Remove the freespace, we'll manage it. */ error = xfs_dir2_data_use_free(args, bp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), be16_to_cpu(dup->length), &needlog, &needscan); if (error) goto out_free; /* * Create entry for . */ dep = dp->d_ops->data_dot_entry_p(hdr); dep->inumber = cpu_to_be64(dp->i_ino); dep->namelen = 1; dep->name[0] = '.'; dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, bp, dep); blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot); blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); /* * Create entry for .. */ dep = dp->d_ops->data_dotdot_entry_p(hdr); dep->inumber = cpu_to_be64(dp->d_ops->sf_get_parent_ino(sfp)); dep->namelen = 2; dep->name[0] = dep->name[1] = '.'; dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, bp, dep); blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); offset = dp->d_ops->data_first_offset; /* * Loop over existing entries, stuff them in. */ i = 0; if (!sfp->count) sfep = NULL; else sfep = xfs_dir2_sf_firstentry(sfp); /* * Need to preserve the existing offset values in the sf directory. * Insert holes (unused entries) where necessary. */ while (offset < endoffset) { /* * sfep is null when we reach the end of the list. */ if (sfep == NULL) newoffset = endoffset; else newoffset = xfs_dir2_sf_get_offset(sfep); /* * There should be a hole here, make one. */ if (offset < newoffset) { dup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); dup->length = cpu_to_be16(newoffset - offset); *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16( ((char *)dup - (char *)hdr)); xfs_dir2_data_log_unused(args, bp, dup); xfs_dir2_data_freeinsert(hdr, dp->d_ops->data_bestfree_p(hdr), dup, &dummy); offset += be16_to_cpu(dup->length); continue; } /* * Copy a real entry. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset); dep->inumber = cpu_to_be64(dp->d_ops->sf_get_ino(sfp, sfep)); dep->namelen = sfep->namelen; dp->d_ops->data_put_ftype(dep, dp->d_ops->sf_get_ftype(sfep)); memcpy(dep->name, sfep->name, dep->namelen); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, bp, dep); name.name = sfep->name; name.len = sfep->namelen; blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops-> hashname(&name)); blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); offset = (int)((char *)(tagp + 1) - (char *)hdr); if (++i == sfp->count) sfep = NULL; else sfep = dp->d_ops->sf_nextentry(sfp, sfep); } /* Done with the temporary buffer */ kmem_free(sfp); /* * Sort the leaf entries by hash value. */ xfs_sort(blp, be32_to_cpu(btp->count), sizeof(*blp), xfs_dir2_block_sort); /* * Log the leaf entry area and tail. * Already logged the header in data_init, ignore needlog. */ ASSERT(needscan == 0); xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1); xfs_dir2_block_log_tail(tp, bp); xfs_dir3_data_check(dp, bp); return 0; out_free: kmem_free(sfp); return error; } xfsprogs-5.3.0/libxfs/xfs_dir2_data.c0000644000175000017500000010032613570057155017422 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_dir2.h" #include "xfs_trans.h" static xfs_failaddr_t xfs_dir2_data_freefind_verify( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup, struct xfs_dir2_data_free **bf_ent); /* * Check the consistency of the data block. * The input can also be a block-format directory. * Return NULL if the buffer is good, otherwise the address of the error. */ xfs_failaddr_t __xfs_dir3_data_check( struct xfs_inode *dp, /* incore inode pointer */ struct xfs_buf *bp) /* data block's buffer */ { xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ xfs_dir2_data_free_t *bf; /* bestfree table */ xfs_dir2_block_tail_t *btp=NULL; /* block tail */ int count; /* count of entries found */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_free_t *dfp; /* bestfree entry */ xfs_dir2_data_unused_t *dup; /* unused entry */ char *endp; /* end of useful data */ int freeseen; /* mask of bestfrees seen */ xfs_dahash_t hash; /* hash of current name */ int i; /* leaf index */ int lastfree; /* last entry was unused */ xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ struct xfs_mount *mp = bp->b_mount; char *p; /* current data position */ int stale; /* count of stale leaves */ struct xfs_name name; const struct xfs_dir_ops *ops; struct xfs_da_geometry *geo; geo = mp->m_dir_geo; /* * We can be passed a null dp here from a verifier, so we need to go the * hard way to get them. */ ops = xfs_dir_get_ops(mp, dp); /* * If this isn't a directory, or we don't get handed the dir ops, * something is seriously wrong. Bail out. */ if ((dp && !S_ISDIR(VFS_I(dp)->i_mode)) || ops != xfs_dir_get_ops(mp, NULL)) return __this_address; hdr = bp->b_addr; p = (char *)ops->data_entry_p(hdr); switch (hdr->magic) { case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): btp = xfs_dir2_block_tail_p(geo, hdr); lep = xfs_dir2_block_leaf_p(btp); /* * The number of leaf entries is limited by the size of the * block and the amount of space used by the data entries. * We don't know how much space is used by the data entries yet, * so just ensure that the count falls somewhere inside the * block right now. */ if (be32_to_cpu(btp->count) >= ((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry)) return __this_address; break; case cpu_to_be32(XFS_DIR3_DATA_MAGIC): case cpu_to_be32(XFS_DIR2_DATA_MAGIC): break; default: return __this_address; } endp = xfs_dir3_data_endp(geo, hdr); if (!endp) return __this_address; /* * Account for zero bestfree entries. */ bf = ops->data_bestfree_p(hdr); count = lastfree = freeseen = 0; if (!bf[0].length) { if (bf[0].offset) return __this_address; freeseen |= 1 << 0; } if (!bf[1].length) { if (bf[1].offset) return __this_address; freeseen |= 1 << 1; } if (!bf[2].length) { if (bf[2].offset) return __this_address; freeseen |= 1 << 2; } if (be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length)) return __this_address; if (be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length)) return __this_address; /* * Loop over the data/unused entries. */ while (p < endp) { dup = (xfs_dir2_data_unused_t *)p; /* * If it's unused, look for the space in the bestfree table. * If we find it, account for that, else make sure it * doesn't need to be there. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { xfs_failaddr_t fa; if (lastfree != 0) return __this_address; if (endp < p + be16_to_cpu(dup->length)) return __this_address; if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) != (char *)dup - (char *)hdr) return __this_address; fa = xfs_dir2_data_freefind_verify(hdr, bf, dup, &dfp); if (fa) return fa; if (dfp) { i = (int)(dfp - bf); if ((freeseen & (1 << i)) != 0) return __this_address; freeseen |= 1 << i; } else { if (be16_to_cpu(dup->length) > be16_to_cpu(bf[2].length)) return __this_address; } p += be16_to_cpu(dup->length); lastfree = 1; continue; } /* * It's a real entry. Validate the fields. * If this is a block directory then make sure it's * in the leaf section of the block. * The linear search is crude but this is DEBUG code. */ dep = (xfs_dir2_data_entry_t *)p; if (dep->namelen == 0) return __this_address; if (xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))) return __this_address; if (endp < p + ops->data_entsize(dep->namelen)) return __this_address; if (be16_to_cpu(*ops->data_entry_tag_p(dep)) != (char *)dep - (char *)hdr) return __this_address; if (ops->data_get_ftype(dep) >= XFS_DIR3_FT_MAX) return __this_address; count++; lastfree = 0; if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, (xfs_dir2_data_aoff_t) ((char *)dep - (char *)hdr)); name.name = dep->name; name.len = dep->namelen; hash = mp->m_dirnameops->hashname(&name); for (i = 0; i < be32_to_cpu(btp->count); i++) { if (be32_to_cpu(lep[i].address) == addr && be32_to_cpu(lep[i].hashval) == hash) break; } if (i >= be32_to_cpu(btp->count)) return __this_address; } p += ops->data_entsize(dep->namelen); } /* * Need to have seen all the entries and all the bestfree slots. */ if (freeseen != 7) return __this_address; if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { if (lep[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) stale++; if (i > 0 && be32_to_cpu(lep[i].hashval) < be32_to_cpu(lep[i - 1].hashval)) return __this_address; } if (count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) return __this_address; if (stale != be32_to_cpu(btp->stale)) return __this_address; } return NULL; } #ifdef DEBUG void xfs_dir3_data_check( struct xfs_inode *dp, struct xfs_buf *bp) { xfs_failaddr_t fa; fa = __xfs_dir3_data_check(dp, bp); if (!fa) return; xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount, bp->b_addr, BBTOB(bp->b_length), __FILE__, __LINE__, fa); ASSERT(0); } #endif static xfs_failaddr_t xfs_dir3_data_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (!xfs_verify_magic(bp, hdr3->magic)) return __this_address; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) return __this_address; } return __xfs_dir3_data_check(NULL, bp); } /* * Readahead of the first block of the directory when it is opened is completely * oblivious to the format of the directory. Hence we can either get a block * format buffer or a data format buffer on readahead. */ static void xfs_dir3_data_reada_verify( struct xfs_buf *bp) { struct xfs_dir2_data_hdr *hdr = bp->b_addr; switch (hdr->magic) { case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): bp->b_ops = &xfs_dir3_block_buf_ops; bp->b_ops->verify_read(bp); return; case cpu_to_be32(XFS_DIR2_DATA_MAGIC): case cpu_to_be32(XFS_DIR3_DATA_MAGIC): bp->b_ops = &xfs_dir3_data_buf_ops; bp->b_ops->verify_read(bp); return; default: xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); break; } } static void xfs_dir3_data_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_dir3_data_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_dir3_data_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_dir3_data_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_data_buf_ops = { .name = "xfs_dir3_data", .magic = { cpu_to_be32(XFS_DIR2_DATA_MAGIC), cpu_to_be32(XFS_DIR3_DATA_MAGIC) }, .verify_read = xfs_dir3_data_read_verify, .verify_write = xfs_dir3_data_write_verify, .verify_struct = xfs_dir3_data_verify, }; static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = { .name = "xfs_dir3_data_reada", .magic = { cpu_to_be32(XFS_DIR2_DATA_MAGIC), cpu_to_be32(XFS_DIR3_DATA_MAGIC) }, .verify_read = xfs_dir3_data_reada_verify, .verify_write = xfs_dir3_data_write_verify, }; int xfs_dir3_data_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp, XFS_DATA_FORK, &xfs_dir3_data_buf_ops); if (!err && tp && *bpp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF); return err; } int xfs_dir3_data_readahead( struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno) { return xfs_da_reada_buf(dp, bno, mapped_bno, XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops); } /* * Find the bestfree entry that exactly coincides with unused directory space * or a verifier error because the bestfree data are bad. */ static xfs_failaddr_t xfs_dir2_data_freefind_verify( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup, struct xfs_dir2_data_free **bf_ent) { struct xfs_dir2_data_free *dfp; xfs_dir2_data_aoff_t off; bool matched = false; bool seenzero = false; *bf_ent = NULL; off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); /* * Validate some consistency in the bestfree table. * Check order, non-overlapping entries, and if we find the * one we're looking for it has to be exact. */ for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { if (!dfp->offset) { if (dfp->length) return __this_address; seenzero = true; continue; } if (seenzero) return __this_address; if (be16_to_cpu(dfp->offset) == off) { matched = true; if (dfp->length != dup->length) return __this_address; } else if (be16_to_cpu(dfp->offset) > off) { if (off + be16_to_cpu(dup->length) > be16_to_cpu(dfp->offset)) return __this_address; } else { if (be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) > off) return __this_address; } if (!matched && be16_to_cpu(dfp->length) < be16_to_cpu(dup->length)) return __this_address; if (dfp > &bf[0] && be16_to_cpu(dfp[-1].length) < be16_to_cpu(dfp[0].length)) return __this_address; } /* Looks ok so far; now try to match up with a bestfree entry. */ *bf_ent = xfs_dir2_data_freefind(hdr, bf, dup); return NULL; } /* * Given a data block and an unused entry from that block, * return the bestfree entry if any that corresponds to it. */ xfs_dir2_data_free_t * xfs_dir2_data_freefind( struct xfs_dir2_data_hdr *hdr, /* data block header */ struct xfs_dir2_data_free *bf, /* bestfree table pointer */ struct xfs_dir2_data_unused *dup) /* unused space */ { xfs_dir2_data_free_t *dfp; /* bestfree entry */ xfs_dir2_data_aoff_t off; /* offset value needed */ off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); /* * If this is smaller than the smallest bestfree entry, * it can't be there since they're sorted. */ if (be16_to_cpu(dup->length) < be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) return NULL; /* * Look at the three bestfree entries for our guy. */ for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { if (!dfp->offset) return NULL; if (be16_to_cpu(dfp->offset) == off) return dfp; } /* * Didn't find it. This only happens if there are duplicate lengths. */ return NULL; } /* * Insert an unused-space entry into the bestfree table. */ xfs_dir2_data_free_t * /* entry inserted */ xfs_dir2_data_freeinsert( struct xfs_dir2_data_hdr *hdr, /* data block pointer */ struct xfs_dir2_data_free *dfp, /* bestfree table pointer */ struct xfs_dir2_data_unused *dup, /* unused space */ int *loghead) /* log the data header (out) */ { xfs_dir2_data_free_t new; /* new bestfree entry */ ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); new.length = dup->length; new.offset = cpu_to_be16((char *)dup - (char *)hdr); /* * Insert at position 0, 1, or 2; or not at all. */ if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) { dfp[2] = dfp[1]; dfp[1] = dfp[0]; dfp[0] = new; *loghead = 1; return &dfp[0]; } if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) { dfp[2] = dfp[1]; dfp[1] = new; *loghead = 1; return &dfp[1]; } if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) { dfp[2] = new; *loghead = 1; return &dfp[2]; } return NULL; } /* * Remove a bestfree entry from the table. */ STATIC void xfs_dir2_data_freeremove( struct xfs_dir2_data_hdr *hdr, /* data block header */ struct xfs_dir2_data_free *bf, /* bestfree table pointer */ struct xfs_dir2_data_free *dfp, /* bestfree entry pointer */ int *loghead) /* out: log data header */ { ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); /* * It's the first entry, slide the next 2 up. */ if (dfp == &bf[0]) { bf[0] = bf[1]; bf[1] = bf[2]; } /* * It's the second entry, slide the 3rd entry up. */ else if (dfp == &bf[1]) bf[1] = bf[2]; /* * Must be the last entry. */ else ASSERT(dfp == &bf[2]); /* * Clear the 3rd entry, must be zero now. */ bf[2].length = 0; bf[2].offset = 0; *loghead = 1; } /* * Given a data block, reconstruct its bestfree map. */ void xfs_dir2_data_freescan_int( struct xfs_da_geometry *geo, const struct xfs_dir_ops *ops, struct xfs_dir2_data_hdr *hdr, int *loghead) { xfs_dir2_data_entry_t *dep; /* active data entry */ xfs_dir2_data_unused_t *dup; /* unused data entry */ struct xfs_dir2_data_free *bf; char *endp; /* end of block's data */ char *p; /* current entry pointer */ ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); /* * Start by clearing the table. */ bf = ops->data_bestfree_p(hdr); memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT); *loghead = 1; /* * Set up pointers. */ p = (char *)ops->data_entry_p(hdr); endp = xfs_dir3_data_endp(geo, hdr); /* * Loop over the block's entries. */ while (p < endp) { dup = (xfs_dir2_data_unused_t *)p; /* * If it's a free entry, insert it. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); xfs_dir2_data_freeinsert(hdr, bf, dup, loghead); p += be16_to_cpu(dup->length); } /* * For active entries, check their tags and skip them. */ else { dep = (xfs_dir2_data_entry_t *)p; ASSERT((char *)dep - (char *)hdr == be16_to_cpu(*ops->data_entry_tag_p(dep))); p += ops->data_entsize(dep->namelen); } } } void xfs_dir2_data_freescan( struct xfs_inode *dp, struct xfs_dir2_data_hdr *hdr, int *loghead) { return xfs_dir2_data_freescan_int(dp->i_mount->m_dir_geo, dp->d_ops, hdr, loghead); } /* * Initialize a data block at the given block number in the directory. * Give back the buffer for the created block. */ int /* error */ xfs_dir3_data_init( xfs_da_args_t *args, /* directory operation args */ xfs_dir2_db_t blkno, /* logical dir block number */ struct xfs_buf **bpp) /* output block buffer */ { struct xfs_buf *bp; /* block buffer */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* unused entry pointer */ struct xfs_dir2_data_free *bf; int error; /* error return value */ int i; /* bestfree index */ xfs_mount_t *mp; /* filesystem mount point */ xfs_trans_t *tp; /* transaction pointer */ int t; /* temp */ dp = args->dp; mp = dp->i_mount; tp = args->trans; /* * Get the buffer set up for the block. */ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno), -1, &bp, XFS_DATA_FORK); if (error) return error; bp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF); /* * Initialize the header. */ hdr = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; memset(hdr3, 0, sizeof(*hdr3)); hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); hdr3->blkno = cpu_to_be64(bp->b_bn); hdr3->owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); } else hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); bf = dp->d_ops->data_bestfree_p(hdr); bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset); for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { bf[i].length = 0; bf[i].offset = 0; } /* * Set up an unused entry for the block's body. */ dup = dp->d_ops->data_unused_p(hdr); dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); t = args->geo->blksize - (uint)dp->d_ops->data_entry_offset; bf[0].length = cpu_to_be16(t); dup->length = cpu_to_be16(t); *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); /* * Log it and return it. */ xfs_dir2_data_log_header(args, bp); xfs_dir2_data_log_unused(args, bp, dup); *bpp = bp; return 0; } /* * Log an active data entry from the block. */ void xfs_dir2_data_log_entry( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_entry_t *dep) /* data entry pointer */ { struct xfs_dir2_data_hdr *hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr), (uint)((char *)(args->dp->d_ops->data_entry_tag_p(dep) + 1) - (char *)hdr - 1)); } /* * Log a data block header. */ void xfs_dir2_data_log_header( struct xfs_da_args *args, struct xfs_buf *bp) { #ifdef DEBUG struct xfs_dir2_data_hdr *hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); #endif xfs_trans_log_buf(args->trans, bp, 0, args->dp->d_ops->data_entry_offset - 1); } /* * Log a data unused entry. */ void xfs_dir2_data_log_unused( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_unused_t *dup) /* data unused pointer */ { xfs_dir2_data_hdr_t *hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); /* * Log the first part of the unused entry. */ xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr), (uint)((char *)&dup->length + sizeof(dup->length) - 1 - (char *)hdr)); /* * Log the end (tag) of the unused entry. */ xfs_trans_log_buf(args->trans, bp, (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr), (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr + sizeof(xfs_dir2_data_off_t) - 1)); } /* * Make a byte range in the data block unused. * Its current contents are unimportant. */ void xfs_dir2_data_make_free( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_aoff_t offset, /* starting byte offset */ xfs_dir2_data_aoff_t len, /* length in bytes */ int *needlogp, /* out: log header */ int *needscanp) /* out: regen bestfree */ { xfs_dir2_data_hdr_t *hdr; /* data block pointer */ xfs_dir2_data_free_t *dfp; /* bestfree pointer */ char *endptr; /* end of data area */ int needscan; /* need to regen bestfree */ xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *postdup; /* unused entry after us */ xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ struct xfs_dir2_data_free *bf; hdr = bp->b_addr; /* * Figure out where the end of the data area is. */ endptr = xfs_dir3_data_endp(args->geo, hdr); ASSERT(endptr != NULL); /* * If this isn't the start of the block, then back up to * the previous entry and see if it's free. */ if (offset > args->dp->d_ops->data_entry_offset) { __be16 *tagp; /* tag just before us */ tagp = (__be16 *)((char *)hdr + offset) - 1; prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG) prevdup = NULL; } else prevdup = NULL; /* * If this isn't the end of the block, see if the entry after * us is free. */ if ((char *)hdr + offset + len < endptr) { postdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG) postdup = NULL; } else postdup = NULL; ASSERT(*needscanp == 0); needscan = 0; /* * Previous and following entries are both free, * merge everything into a single free entry. */ bf = args->dp->d_ops->data_bestfree_p(hdr); if (prevdup && postdup) { xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ /* * See if prevdup and/or postdup are in bestfree table. */ dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup); /* * We need a rescan unless there are exactly 2 free entries * namely our two. Then we know what's happening, otherwise * since the third bestfree is there, there might be more * entries. */ needscan = (bf[2].length != 0); /* * Fix up the new big freespace. */ be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length)); *xfs_dir2_data_unused_tag_p(prevdup) = cpu_to_be16((char *)prevdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, prevdup); if (!needscan) { /* * Has to be the case that entries 0 and 1 are * dfp and dfp2 (don't know which is which), and * entry 2 is empty. * Remove entry 1 first then entry 0. */ ASSERT(dfp && dfp2); if (dfp == &bf[1]) { dfp = &bf[0]; ASSERT(dfp2 == dfp); dfp2 = &bf[1]; } xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp); xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); /* * Now insert the new entry. */ dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); ASSERT(dfp == &bf[0]); ASSERT(dfp->length == prevdup->length); ASSERT(!dfp[1].length); ASSERT(!dfp[2].length); } } /* * The entry before us is free, merge with it. */ else if (prevdup) { dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); be16_add_cpu(&prevdup->length, len); *xfs_dir2_data_unused_tag_p(prevdup) = cpu_to_be16((char *)prevdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, prevdup); /* * If the previous entry was in the table, the new entry * is longer, so it will be in the table too. Remove * the old one and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); } /* * Otherwise we need a scan if the new entry is big enough. */ else { needscan = be16_to_cpu(prevdup->length) > be16_to_cpu(bf[2].length); } } /* * The following entry is free, merge with it. */ else if (postdup) { dfp = xfs_dir2_data_freefind(hdr, bf, postdup); newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length)); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); /* * If the following entry was in the table, the new entry * is longer, so it will be in the table too. Remove * the old one and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); } /* * Otherwise we need a scan if the new entry is big enough. */ else { needscan = be16_to_cpu(newdup->length) > be16_to_cpu(bf[2].length); } } /* * Neither neighbor is free. Make a new entry. */ else { newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup->length = cpu_to_be16(len); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); } *needscanp = needscan; } /* Check our free data for obvious signs of corruption. */ static inline xfs_failaddr_t xfs_dir2_data_check_free( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_unused *dup, xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len) { if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) && hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) && hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) && hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) return __this_address; if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG) return __this_address; if (offset < (char *)dup - (char *)hdr) return __this_address; if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr) return __this_address; if ((char *)dup - (char *)hdr != be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))) return __this_address; return NULL; } /* Sanity-check a new bestfree entry. */ static inline xfs_failaddr_t xfs_dir2_data_check_new_free( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *dfp, struct xfs_dir2_data_unused *newdup) { if (dfp == NULL) return __this_address; if (dfp->length != newdup->length) return __this_address; if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr) return __this_address; return NULL; } /* * Take a byte range out of an existing unused space and make it un-free. */ int xfs_dir2_data_use_free( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_unused_t *dup, /* unused entry */ xfs_dir2_data_aoff_t offset, /* starting offset to use */ xfs_dir2_data_aoff_t len, /* length to use */ int *needlogp, /* out: need to log header */ int *needscanp) /* out: need regen bestfree */ { xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_free_t *dfp; /* bestfree pointer */ xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ struct xfs_dir2_data_free *bf; xfs_failaddr_t fa; int matchback; /* matches end of freespace */ int matchfront; /* matches start of freespace */ int needscan; /* need to regen bestfree */ int oldlen; /* old unused entry's length */ hdr = bp->b_addr; fa = xfs_dir2_data_check_free(hdr, dup, offset, len); if (fa) goto corrupt; /* * Look up the entry in the bestfree table. */ oldlen = be16_to_cpu(dup->length); bf = args->dp->d_ops->data_bestfree_p(hdr); dfp = xfs_dir2_data_freefind(hdr, bf, dup); ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length)); /* * Check for alignment with front and back of the entry. */ matchfront = (char *)dup - (char *)hdr == offset; matchback = (char *)dup + oldlen - (char *)hdr == offset + len; ASSERT(*needscanp == 0); needscan = 0; /* * If we matched it exactly we just need to get rid of it from * the bestfree table. */ if (matchfront && matchback) { if (dfp) { needscan = (bf[2].offset != 0); if (!needscan) xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); } } /* * We match the first part of the entry. * Make a new entry with the remaining freespace. */ else if (matchfront) { newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup->length = cpu_to_be16(oldlen - len); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); /* * If it was in the table, remove it and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup); if (fa) goto corrupt; /* * If we got inserted at the last slot, * that means we don't know if there was a better * choice for the last slot, or not. Rescan. */ needscan = dfp == &bf[2]; } } /* * We match the last part of the entry. * Trim the allocated space off the tail of the entry. */ else if (matchback) { newdup = dup; newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); /* * If it was in the table, remove it and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup); if (fa) goto corrupt; /* * If we got inserted at the last slot, * that means we don't know if there was a better * choice for the last slot, or not. Rescan. */ needscan = dfp == &bf[2]; } } /* * Poking out the middle of an entry. * Make two new entries. */ else { newdup = dup; newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length)); *xfs_dir2_data_unused_tag_p(newdup2) = cpu_to_be16((char *)newdup2 - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup2); /* * If the old entry was in the table, we need to scan * if the 3rd entry was valid, since these entries * are smaller than the old one. * If we don't need to scan that means there were 1 or 2 * entries in the table, and removing the old and adding * the 2 new will work. */ if (dfp) { needscan = (bf[2].length != 0); if (!needscan) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); xfs_dir2_data_freeinsert(hdr, bf, newdup2, needlogp); } } } *needscanp = needscan; return 0; corrupt: xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount, hdr, sizeof(*hdr), __FILE__, __LINE__, fa); return -EFSCORRUPTED; } /* Find the end of the entry data in a data/block format dir block. */ void * xfs_dir3_data_endp( struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr) { switch (hdr->magic) { case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): return xfs_dir2_block_leaf_p(xfs_dir2_block_tail_p(geo, hdr)); case cpu_to_be32(XFS_DIR3_DATA_MAGIC): case cpu_to_be32(XFS_DIR2_DATA_MAGIC): return (char *)hdr + geo->blksize; default: return NULL; } } xfsprogs-5.3.0/libxfs/xfs_dir2_leaf.c0000644000175000017500000014127513570057155017430 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" #include "xfs_trans.h" /* * Local function declarations. */ static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp, int *indexp, struct xfs_buf **dbpp); static void xfs_dir3_leaf_log_bests(struct xfs_da_args *args, struct xfs_buf *bp, int first, int last); static void xfs_dir3_leaf_log_tail(struct xfs_da_args *args, struct xfs_buf *bp); /* * Check the internal consistency of a leaf1 block. * Pop an assert if something is wrong. */ #ifdef DEBUG static xfs_failaddr_t xfs_dir3_leaf1_check( struct xfs_inode *dp, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir3_icleaf_hdr leafhdr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) return __this_address; } else if (leafhdr.magic != XFS_DIR2_LEAF1_MAGIC) return __this_address; return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf); } static inline void xfs_dir3_leaf_check( struct xfs_inode *dp, struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_dir3_leaf1_check(dp, bp); if (!fa) return; xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount, bp->b_addr, BBTOB(bp->b_length), __FILE__, __LINE__, fa); ASSERT(0); } #else #define xfs_dir3_leaf_check(dp, bp) #endif xfs_failaddr_t xfs_dir3_leaf_check_int( struct xfs_mount *mp, struct xfs_inode *dp, struct xfs_dir3_icleaf_hdr *hdr, struct xfs_dir2_leaf *leaf) { struct xfs_dir2_leaf_entry *ents; xfs_dir2_leaf_tail_t *ltp; int stale; int i; const struct xfs_dir_ops *ops; struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_da_geometry *geo = mp->m_dir_geo; /* * we can be passed a null dp here from a verifier, so we need to go the * hard way to get them. */ ops = xfs_dir_get_ops(mp, dp); if (!hdr) { ops->leaf_hdr_from_disk(&leafhdr, leaf); hdr = &leafhdr; } ents = ops->leaf_ents_p(leaf); ltp = xfs_dir2_leaf_tail_p(geo, leaf); /* * XXX (dgc): This value is not restrictive enough. * Should factor in the size of the bests table as well. * We can deduce a value for that from di_size. */ if (hdr->count > ops->leaf_max_ents(geo)) return __this_address; /* Leaves and bests don't overlap in leaf format. */ if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC || hdr->magic == XFS_DIR3_LEAF1_MAGIC) && (char *)&ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp)) return __this_address; /* Check hash value order, count stale entries. */ for (i = stale = 0; i < hdr->count; i++) { if (i + 1 < hdr->count) { if (be32_to_cpu(ents[i].hashval) > be32_to_cpu(ents[i + 1].hashval)) return __this_address; } if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) stale++; } if (hdr->stale != stale) return __this_address; return NULL; } /* * We verify the magic numbers before decoding the leaf header so that on debug * kernels we don't get assertion failures in xfs_dir3_leaf_hdr_from_disk() due * to incorrect magic numbers. */ static xfs_failaddr_t xfs_dir3_leaf_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_dir2_leaf *leaf = bp->b_addr; xfs_failaddr_t fa; fa = xfs_da3_blkinfo_verify(bp, bp->b_addr); if (fa) return fa; return xfs_dir3_leaf_check_int(mp, NULL, NULL, leaf); } static void xfs_dir3_leaf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_LEAF_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_dir3_leaf_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_dir3_leaf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_dir3_leaf_hdr *hdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_dir3_leaf_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_LEAF_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = { .name = "xfs_dir3_leaf1", .magic16 = { cpu_to_be16(XFS_DIR2_LEAF1_MAGIC), cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) }, .verify_read = xfs_dir3_leaf_read_verify, .verify_write = xfs_dir3_leaf_write_verify, .verify_struct = xfs_dir3_leaf_verify, }; const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = { .name = "xfs_dir3_leafn", .magic16 = { cpu_to_be16(XFS_DIR2_LEAFN_MAGIC), cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) }, .verify_read = xfs_dir3_leaf_read_verify, .verify_write = xfs_dir3_leaf_write_verify, .verify_struct = xfs_dir3_leaf_verify, }; int xfs_dir3_leaf_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops); if (!err && tp && *bpp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF); return err; } int xfs_dir3_leafn_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops); if (!err && tp && *bpp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF); return err; } /* * Initialize a new leaf block, leaf1 or leafn magic accepted. */ static void xfs_dir3_leaf_init( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *bp, xfs_ino_t owner, uint16_t type) { struct xfs_dir2_leaf *leaf = bp->b_addr; ASSERT(type == XFS_DIR2_LEAF1_MAGIC || type == XFS_DIR2_LEAFN_MAGIC); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; memset(leaf3, 0, sizeof(*leaf3)); leaf3->info.hdr.magic = (type == XFS_DIR2_LEAF1_MAGIC) ? cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); leaf3->info.blkno = cpu_to_be64(bp->b_bn); leaf3->info.owner = cpu_to_be64(owner); uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid); } else { memset(leaf, 0, sizeof(*leaf)); leaf->hdr.info.magic = cpu_to_be16(type); } /* * If it's a leaf-format directory initialize the tail. * Caller is responsible for initialising the bests table. */ if (type == XFS_DIR2_LEAF1_MAGIC) { struct xfs_dir2_leaf_tail *ltp; ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); ltp->bestcount = 0; bp->b_ops = &xfs_dir3_leaf1_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAF1_BUF); } else { bp->b_ops = &xfs_dir3_leafn_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); } } int xfs_dir3_leaf_get_buf( xfs_da_args_t *args, xfs_dir2_db_t bno, struct xfs_buf **bpp, uint16_t magic) { struct xfs_inode *dp = args->dp; struct xfs_trans *tp = args->trans; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp; int error; ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); ASSERT(bno >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET) && bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)); error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno), -1, &bp, XFS_DATA_FORK); if (error) return error; xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic); xfs_dir3_leaf_log_header(args, bp); if (magic == XFS_DIR2_LEAF1_MAGIC) xfs_dir3_leaf_log_tail(args, bp); *bpp = bp; return 0; } /* * Convert a block form directory to a leaf form directory. */ int /* error */ xfs_dir2_block_to_leaf( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *dbp) /* input block's buffer */ { __be16 *bestsp; /* leaf's bestsp entries */ xfs_dablk_t blkno; /* leaf block's bno */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block's leaf entries */ xfs_dir2_block_tail_t *btp; /* block's tail */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ struct xfs_buf *lbp; /* leaf block's buffer */ xfs_dir2_db_t ldb; /* leaf block's bno */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf's tail */ int needlog; /* need to log block header */ int needscan; /* need to rescan bestfree */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_data_free *bf; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_block_to_leaf(args); dp = args->dp; tp = args->trans; /* * Add the leaf block to the inode. * This interface will only put blocks in the leaf/node range. * Since that's empty now, we'll get the root (block 0 in range). */ if ((error = xfs_da_grow_inode(args, &blkno))) { return error; } ldb = xfs_dir2_da_to_db(args->geo, blkno); ASSERT(ldb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)); /* * Initialize the leaf block, get a buffer for it. */ error = xfs_dir3_leaf_get_buf(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC); if (error) return error; leaf = lbp->b_addr; hdr = dbp->b_addr; xfs_dir3_data_check(dp, dbp); btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); bf = dp->d_ops->data_bestfree_p(hdr); ents = dp->d_ops->leaf_ents_p(leaf); /* * Set the counts in the leaf header. */ dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); leafhdr.count = be32_to_cpu(btp->count); leafhdr.stale = be32_to_cpu(btp->stale); dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); /* * Could compact these but I think we always do the conversion * after squeezing out stale entries. */ memcpy(ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, lbp, 0, leafhdr.count - 1); needscan = 0; needlog = 1; /* * Make the space formerly occupied by the leaf entries and block * tail be free. */ xfs_dir2_data_make_free(args, dbp, (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), (xfs_dir2_data_aoff_t)((char *)hdr + args->geo->blksize - (char *)blp), &needlog, &needscan); /* * Fix up the block header, make it a data block. */ dbp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, dbp, XFS_BLFT_DIR_DATA_BUF); if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); else hdr->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); /* * Set up leaf tail and bests table. */ ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ltp->bestcount = cpu_to_be32(1); bestsp = xfs_dir2_leaf_bests_p(ltp); bestsp[0] = bf[0].length; /* * Log the data header and leaf bests table. */ if (needlog) xfs_dir2_data_log_header(args, dbp); xfs_dir3_leaf_check(dp, lbp); xfs_dir3_data_check(dp, dbp); xfs_dir3_leaf_log_bests(args, lbp, 0, 0); return 0; } STATIC void xfs_dir3_leaf_find_stale( struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int index, int *lowstale, int *highstale) { /* * Find the first stale entry before our index, if any. */ for (*lowstale = index - 1; *lowstale >= 0; --*lowstale) { if (ents[*lowstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) break; } /* * Find the first stale entry at or after our index, if any. * Stop if the result would require moving more entries than using * lowstale. */ for (*highstale = index; *highstale < leafhdr->count; ++*highstale) { if (ents[*highstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) break; if (*lowstale >= 0 && index - *lowstale <= *highstale - index) break; } } struct xfs_dir2_leaf_entry * xfs_dir3_leaf_find_entry( struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int index, /* leaf table position */ int compact, /* need to compact leaves */ int lowstale, /* index of prev stale leaf */ int highstale, /* index of next stale leaf */ int *lfloglow, /* low leaf logging index */ int *lfloghigh) /* high leaf logging index */ { if (!leafhdr->stale) { xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ /* * Now we need to make room to insert the leaf entry. * * If there are no stale entries, just insert a hole at index. */ lep = &ents[index]; if (index < leafhdr->count) memmove(lep + 1, lep, (leafhdr->count - index) * sizeof(*lep)); /* * Record low and high logging indices for the leaf. */ *lfloglow = index; *lfloghigh = leafhdr->count++; return lep; } /* * There are stale entries. * * We will use one of them for the new entry. It's probably not at * the right location, so we'll have to shift some up or down first. * * If we didn't compact before, we need to find the nearest stale * entries before and after our insertion point. */ if (compact == 0) xfs_dir3_leaf_find_stale(leafhdr, ents, index, &lowstale, &highstale); /* * If the low one is better, use it. */ if (lowstale >= 0 && (highstale == leafhdr->count || index - lowstale - 1 < highstale - index)) { ASSERT(index - lowstale - 1 >= 0); ASSERT(ents[lowstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)); /* * Copy entries up to cover the stale entry and make room * for the new entry. */ if (index - lowstale - 1 > 0) { memmove(&ents[lowstale], &ents[lowstale + 1], (index - lowstale - 1) * sizeof(xfs_dir2_leaf_entry_t)); } *lfloglow = min(lowstale, *lfloglow); *lfloghigh = max(index - 1, *lfloghigh); leafhdr->stale--; return &ents[index - 1]; } /* * The high one is better, so use that one. */ ASSERT(highstale - index >= 0); ASSERT(ents[highstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)); /* * Copy entries down to cover the stale entry and make room for the * new entry. */ if (highstale - index > 0) { memmove(&ents[index + 1], &ents[index], (highstale - index) * sizeof(xfs_dir2_leaf_entry_t)); } *lfloglow = min(index, *lfloglow); *lfloghigh = max(highstale, *lfloghigh); leafhdr->stale--; return &ents[index]; } /* * Add an entry to a leaf form directory. */ int /* error */ xfs_dir2_leaf_addname( struct xfs_da_args *args) /* operation arguments */ { struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_trans *tp = args->trans; __be16 *bestsp; /* freespace table in leaf */ __be16 *tagp; /* end of data entry */ struct xfs_buf *dbp; /* data block buffer */ struct xfs_buf *lbp; /* leaf's buffer */ struct xfs_dir2_leaf *leaf; /* leaf structure */ struct xfs_inode *dp = args->dp; /* incore directory inode */ struct xfs_dir2_data_hdr *hdr; /* data block header */ struct xfs_dir2_data_entry *dep; /* data block entry */ struct xfs_dir2_leaf_entry *lep; /* leaf entry table pointer */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir2_data_unused *dup; /* data unused entry */ struct xfs_dir2_leaf_tail *ltp; /* leaf tail pointer */ struct xfs_dir2_data_free *bf; /* bestfree table */ int compact; /* need to compact leaves */ int error; /* error return value */ int grown; /* allocated new data block */ int highstale = 0; /* index of next stale leaf */ int i; /* temporary, index */ int index; /* leaf table position */ int length; /* length of new entry */ int lfloglow; /* low leaf logging index */ int lfloghigh; /* high leaf logging index */ int lowstale = 0; /* index of prev stale leaf */ int needbytes; /* leaf block bytes needed */ int needlog; /* need to log data header */ int needscan; /* need to rescan data free */ xfs_dir2_db_t use_block; /* data block number */ trace_xfs_dir2_leaf_addname(args); error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp); if (error) return error; /* * Look up the entry by hash value and name. * We know it's not there, our caller has already done a lookup. * So the index is of the entry to insert in front of. * But if there are dup hash values the index is of the first of those. */ index = xfs_dir2_leaf_search_hash(args, lbp); leaf = lbp->b_addr; ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ents = dp->d_ops->leaf_ents_p(leaf); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); bestsp = xfs_dir2_leaf_bests_p(ltp); length = dp->d_ops->data_entsize(args->namelen); /* * See if there are any entries with the same hash value * and space in their block for the new entry. * This is good because it puts multiple same-hash value entries * in a data block, improving the lookup of those entries. */ for (use_block = -1, lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; index++, lep++) { if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; i = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); ASSERT(i < be32_to_cpu(ltp->bestcount)); ASSERT(bestsp[i] != cpu_to_be16(NULLDATAOFF)); if (be16_to_cpu(bestsp[i]) >= length) { use_block = i; break; } } /* * Didn't find a block yet, linear search all the data blocks. */ if (use_block == -1) { for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) { /* * Remember a block we see that's missing. */ if (bestsp[i] == cpu_to_be16(NULLDATAOFF) && use_block == -1) use_block = i; else if (be16_to_cpu(bestsp[i]) >= length) { use_block = i; break; } } } /* * How many bytes do we need in the leaf block? */ needbytes = 0; if (!leafhdr.stale) needbytes += sizeof(xfs_dir2_leaf_entry_t); if (use_block == -1) needbytes += sizeof(xfs_dir2_data_off_t); /* * Now kill use_block if it refers to a missing block, so we * can use it as an indication of allocation needed. */ if (use_block != -1 && bestsp[use_block] == cpu_to_be16(NULLDATAOFF)) use_block = -1; /* * If we don't have enough free bytes but we can make enough * by compacting out stale entries, we'll do that. */ if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes && leafhdr.stale > 1) compact = 1; /* * Otherwise if we don't have enough free bytes we need to * convert to node form. */ else if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes) { /* * Just checking or no space reservation, give up. */ if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) { xfs_trans_brelse(tp, lbp); return -ENOSPC; } /* * Convert to node form. */ error = xfs_dir2_leaf_to_node(args, lbp); if (error) return error; /* * Then add the new entry. */ return xfs_dir2_node_addname(args); } /* * Otherwise it will fit without compaction. */ else compact = 0; /* * If just checking, then it will fit unless we needed to allocate * a new data block. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) { xfs_trans_brelse(tp, lbp); return use_block == -1 ? -ENOSPC : 0; } /* * If no allocations are allowed, return now before we've * changed anything. */ if (args->total == 0 && use_block == -1) { xfs_trans_brelse(tp, lbp); return -ENOSPC; } /* * Need to compact the leaf entries, removing stale ones. * Leave one stale entry behind - the one closest to our * insertion index - and we'll shift that one to our insertion * point later. */ if (compact) { xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, &highstale, &lfloglow, &lfloghigh); } /* * There are stale entries, so we'll need log-low and log-high * impossibly bad values later. */ else if (leafhdr.stale) { lfloglow = leafhdr.count; lfloghigh = -1; } /* * If there was no data block space found, we need to allocate * a new one. */ if (use_block == -1) { /* * Add the new data block. */ if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &use_block))) { xfs_trans_brelse(tp, lbp); return error; } /* * Initialize the block. */ if ((error = xfs_dir3_data_init(args, use_block, &dbp))) { xfs_trans_brelse(tp, lbp); return error; } /* * If we're adding a new data block on the end we need to * extend the bests table. Copy it up one entry. */ if (use_block >= be32_to_cpu(ltp->bestcount)) { bestsp--; memmove(&bestsp[0], &bestsp[1], be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0])); be32_add_cpu(<p->bestcount, 1); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } /* * If we're filling in a previously empty block just log it. */ else xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block); hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); bestsp[use_block] = bf[0].length; grown = 1; } else { /* * Already had space in some data block. * Just read that one in. */ error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, use_block), -1, &dbp); if (error) { xfs_trans_brelse(tp, lbp); return error; } hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); grown = 0; } /* * Point to the biggest freespace in our data block. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); needscan = needlog = 0; /* * Mark the initial part of our freespace in use for the new entry. */ error = xfs_dir2_data_use_free(args, dbp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, &needlog, &needscan); if (error) { xfs_trans_brelse(tp, lbp); return error; } /* * Initialize our new entry (at last). */ dep = (xfs_dir2_data_entry_t *)dup; dep->inumber = cpu_to_be64(args->inumber); dep->namelen = args->namelen; memcpy(dep->name, args->name, dep->namelen); dp->d_ops->data_put_ftype(dep, args->filetype); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); /* * Need to scan fix up the bestfree table. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); /* * Need to log the data block's header. */ if (needlog) xfs_dir2_data_log_header(args, dbp); xfs_dir2_data_log_entry(args, dbp, dep); /* * If the bests table needs to be changed, do it. * Log the change unless we've already done that. */ if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(bf[0].length)) { bestsp[use_block] = bf[0].length; if (!grown) xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block); } lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, highstale, &lfloglow, &lfloghigh); /* * Fill in the new leaf entry. */ lep->hashval = cpu_to_be32(args->hashval); lep->address = cpu_to_be32( xfs_dir2_db_off_to_dataptr(args->geo, use_block, be16_to_cpu(*tagp))); /* * Log the leaf fields and give up the buffers. */ dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); xfs_dir3_leaf_log_ents(args, lbp, lfloglow, lfloghigh); xfs_dir3_leaf_check(dp, lbp); xfs_dir3_data_check(dp, dbp); return 0; } /* * Compact out any stale entries in the leaf. * Log the header and changed leaf entries, if any. */ void xfs_dir3_leaf_compact( xfs_da_args_t *args, /* operation arguments */ struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_buf *bp) /* leaf buffer */ { int from; /* source leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int loglow; /* first leaf entry to log */ int to; /* target leaf index */ struct xfs_dir2_leaf_entry *ents; struct xfs_inode *dp = args->dp; leaf = bp->b_addr; if (!leafhdr->stale) return; /* * Compress out the stale entries in place. */ ents = dp->d_ops->leaf_ents_p(leaf); for (from = to = 0, loglow = -1; from < leafhdr->count; from++) { if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) continue; /* * Only actually copy the entries that are different. */ if (from > to) { if (loglow == -1) loglow = to; ents[to] = ents[from]; } to++; } /* * Update and log the header, log the leaf entries. */ ASSERT(leafhdr->stale == from - to); leafhdr->count -= leafhdr->stale; leafhdr->stale = 0; dp->d_ops->leaf_hdr_to_disk(leaf, leafhdr); xfs_dir3_leaf_log_header(args, bp); if (loglow != -1) xfs_dir3_leaf_log_ents(args, bp, loglow, to - 1); } /* * Compact the leaf entries, removing stale ones. * Leave one stale entry behind - the one closest to our * insertion index - and the caller will shift that one to our insertion * point later. * Return new insertion index, where the remaining stale entry is, * and leaf logging indices. */ void xfs_dir3_leaf_compact_x1( struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int *indexp, /* insertion index */ int *lowstalep, /* out: stale entry before us */ int *highstalep, /* out: stale entry after us */ int *lowlogp, /* out: low log index */ int *highlogp) /* out: high log index */ { int from; /* source copy index */ int highstale; /* stale entry at/after index */ int index; /* insertion index */ int keepstale; /* source index of kept stale */ int lowstale; /* stale entry before index */ int newindex=0; /* new insertion index */ int to; /* destination copy index */ ASSERT(leafhdr->stale > 1); index = *indexp; xfs_dir3_leaf_find_stale(leafhdr, ents, index, &lowstale, &highstale); /* * Pick the better of lowstale and highstale. */ if (lowstale >= 0 && (highstale == leafhdr->count || index - lowstale <= highstale - index)) keepstale = lowstale; else keepstale = highstale; /* * Copy the entries in place, removing all the stale entries * except keepstale. */ for (from = to = 0; from < leafhdr->count; from++) { /* * Notice the new value of index. */ if (index == from) newindex = to; if (from != keepstale && ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) { if (from == to) *lowlogp = to; continue; } /* * Record the new keepstale value for the insertion. */ if (from == keepstale) lowstale = highstale = to; /* * Copy only the entries that have moved. */ if (from > to) ents[to] = ents[from]; to++; } ASSERT(from > to); /* * If the insertion point was past the last entry, * set the new insertion point accordingly. */ if (index == from) newindex = to; *indexp = newindex; /* * Adjust the leaf header values. */ leafhdr->count -= from - to; leafhdr->stale = 1; /* * Remember the low/high stale value only in the "right" * direction. */ if (lowstale >= newindex) lowstale = -1; else highstale = leafhdr->count; *highlogp = leafhdr->count - 1; *lowstalep = lowstale; *highstalep = highstale; } /* * Log the bests entries indicated from a leaf1 block. */ static void xfs_dir3_leaf_log_bests( struct xfs_da_args *args, struct xfs_buf *bp, /* leaf buffer */ int first, /* first entry to log */ int last) /* last entry to log */ { __be16 *firstb; /* pointer to first entry */ __be16 *lastb; /* pointer to last entry */ struct xfs_dir2_leaf *leaf = bp->b_addr; xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC)); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); firstb = xfs_dir2_leaf_bests_p(ltp) + first; lastb = xfs_dir2_leaf_bests_p(ltp) + last; xfs_trans_log_buf(args->trans, bp, (uint)((char *)firstb - (char *)leaf), (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1)); } /* * Log the leaf entries indicated from a leaf1 or leafn block. */ void xfs_dir3_leaf_log_ents( struct xfs_da_args *args, struct xfs_buf *bp, int first, int last) { xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir2_leaf_entry *ents; ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); ents = args->dp->d_ops->leaf_ents_p(leaf); firstlep = &ents[first]; lastlep = &ents[last]; xfs_trans_log_buf(args->trans, bp, (uint)((char *)firstlep - (char *)leaf), (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1)); } /* * Log the header of the leaf1 or leafn block. */ void xfs_dir3_leaf_log_header( struct xfs_da_args *args, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); xfs_trans_log_buf(args->trans, bp, (uint)((char *)&leaf->hdr - (char *)leaf), args->dp->d_ops->leaf_hdr_size - 1); } /* * Log the tail of the leaf1 block. */ STATIC void xfs_dir3_leaf_log_tail( struct xfs_da_args *args, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); xfs_trans_log_buf(args->trans, bp, (uint)((char *)ltp - (char *)leaf), (uint)(args->geo->blksize - 1)); } /* * Look up the entry referred to by args in the leaf format directory. * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which * is also used by the node-format code. */ int xfs_dir2_leaf_lookup( xfs_da_args_t *args) /* operation arguments */ { struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* found entry index */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leaf_lookup(args); /* * Look up name in the leaf block, returning both buffers and index. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } tp = args->trans; dp = args->dp; xfs_dir3_leaf_check(dp, lbp); leaf = lbp->b_addr; ents = dp->d_ops->leaf_ents_p(leaf); /* * Get to the leaf entry and contained data entry address. */ lep = &ents[index]; /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *) ((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); /* * Return the found inode number & CI name if appropriate */ args->inumber = be64_to_cpu(dep->inumber); args->filetype = dp->d_ops->data_get_ftype(dep); error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); xfs_trans_brelse(tp, dbp); xfs_trans_brelse(tp, lbp); return error; } /* * Look up name/hash in the leaf block. * Fill in indexp with the found index, and dbpp with the data buffer. * If not found dbpp will be NULL, and ENOENT comes back. * lbpp will always be filled in with the leaf buffer unless there's an error. */ static int /* error */ xfs_dir2_leaf_lookup_int( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf **lbpp, /* out: leaf buffer */ int *indexp, /* out: index in leaf block */ struct xfs_buf **dbpp) /* out: data buffer */ { xfs_dir2_db_t curdb = -1; /* current data block number */ struct xfs_buf *dbp = NULL; /* data buffer */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* index in leaf block */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_trans_t *tp; /* transaction pointer */ xfs_dir2_db_t cidb = -1; /* case match data block no. */ enum xfs_dacmp cmp; /* name compare result */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp = args->dp; tp = args->trans; mp = dp->i_mount; error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp); if (error) return error; *lbpp = lbp; leaf = lbp->b_addr; xfs_dir3_leaf_check(dp, lbp); ents = dp->d_ops->leaf_ents_p(leaf); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); /* * Look for the first leaf entry with our hash value. */ index = xfs_dir2_leaf_search_hash(args, lbp); /* * Loop over all the entries with the right hash value * looking to match the name. */ for (lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip over stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Get the new data block number. */ newdb = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); /* * If it's not the same as the old data block number, * need to pitch the old one and read the new one. */ if (newdb != curdb) { if (dbp) xfs_trans_brelse(tp, dbp); error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, newdb), -1, &dbp); if (error) { xfs_trans_brelse(tp, lbp); return error; } curdb = newdb; } /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); /* * Compare name and if it's an exact match, return the index * and buffer. If it's the first case-insensitive match, store * the index and buffer and continue looking for an exact match. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; *indexp = index; /* case exact match: return the current buffer. */ if (cmp == XFS_CMP_EXACT) { *dbpp = dbp; return 0; } cidb = curdb; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or remove). * If a case-insensitive match was found earlier, re-read the * appropriate data block if required and return it. */ if (args->cmpresult == XFS_CMP_CASE) { ASSERT(cidb != -1); if (cidb != curdb) { xfs_trans_brelse(tp, dbp); error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, cidb), -1, &dbp); if (error) { xfs_trans_brelse(tp, lbp); return error; } } *dbpp = dbp; return 0; } /* * No match found, return -ENOENT. */ ASSERT(cidb == -1); if (dbp) xfs_trans_brelse(tp, dbp); xfs_trans_brelse(tp, lbp); return -ENOENT; } /* * Remove an entry from a leaf format directory. */ int /* error */ xfs_dir2_leaf_removename( xfs_da_args_t *args) /* operation arguments */ { __be16 *bestsp; /* leaf block best freespace */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_db_t db; /* data block number */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data entry structure */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dir2_db_t i; /* temporary data block # */ int index; /* index into leaf entries */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ xfs_dir2_data_off_t oldbest; /* old value of best free */ struct xfs_dir2_data_free *bf; /* bestfree table */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_leaf_removename(args); /* * Lookup the leaf entry, get the leaf and data blocks read in. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } dp = args->dp; leaf = lbp->b_addr; hdr = dbp->b_addr; xfs_dir3_data_check(dp, dbp); bf = dp->d_ops->data_bestfree_p(hdr); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); /* * Point to the leaf entry, use that to point to the data entry. */ lep = &ents[index]; db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); needscan = needlog = 0; oldbest = be16_to_cpu(bf[0].length); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); bestsp = xfs_dir2_leaf_bests_p(ltp); if (be16_to_cpu(bestsp[db]) != oldbest) return -EFSCORRUPTED; /* * Mark the former data entry unused. */ xfs_dir2_data_make_free(args, dbp, (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); /* * We just mark the leaf entry stale by putting a null in it. */ leafhdr.stale++; dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir3_leaf_log_ents(args, lbp, index, index); /* * Scan the freespace in the data block again if necessary, * log the data block header if necessary. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, dbp); /* * If the longest freespace in the data block has changed, * put the new value in the bests table and log that. */ if (be16_to_cpu(bf[0].length) != oldbest) { bestsp[db] = bf[0].length; xfs_dir3_leaf_log_bests(args, lbp, db, db); } xfs_dir3_data_check(dp, dbp); /* * If the data block is now empty then get rid of the data block. */ if (be16_to_cpu(bf[0].length) == args->geo->blksize - dp->d_ops->data_entry_offset) { ASSERT(db != args->geo->datablk); if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { /* * Nope, can't get rid of it because it caused * allocation of a bmap btree block to do so. * Just go on, returning success, leaving the * empty block in place. */ if (error == -ENOSPC && args->total == 0) error = 0; xfs_dir3_leaf_check(dp, lbp); return error; } dbp = NULL; /* * If this is the last data block then compact the * bests table by getting rid of entries. */ if (db == be32_to_cpu(ltp->bestcount) - 1) { /* * Look for the last active entry (i). */ for (i = db - 1; i > 0; i--) { if (bestsp[i] != cpu_to_be16(NULLDATAOFF)) break; } /* * Copy the table down so inactive entries at the * end are removed. */ memmove(&bestsp[db - i], bestsp, (be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp)); be32_add_cpu(<p->bestcount, -(db - i)); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } else bestsp[db] = cpu_to_be16(NULLDATAOFF); } /* * If the data block was not the first one, drop it. */ else if (db != args->geo->datablk) dbp = NULL; xfs_dir3_leaf_check(dp, lbp); /* * See if we can convert to block form. */ return xfs_dir2_leaf_to_block(args, lbp, dbp); } /* * Replace the inode number in a leaf format directory entry. */ int /* error */ xfs_dir2_leaf_replace( xfs_da_args_t *args) /* operation arguments */ { struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* index of leaf entry */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leaf_replace(args); /* * Look up the entry. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } dp = args->dp; leaf = lbp->b_addr; ents = dp->d_ops->leaf_ents_p(leaf); /* * Point to the leaf entry, get data address from it. */ lep = &ents[index]; /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *) ((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); ASSERT(args->inumber != be64_to_cpu(dep->inumber)); /* * Put the new inode number in, log it. */ dep->inumber = cpu_to_be64(args->inumber); dp->d_ops->data_put_ftype(dep, args->filetype); tp = args->trans; xfs_dir2_data_log_entry(args, dbp, dep); xfs_dir3_leaf_check(dp, lbp); xfs_trans_brelse(tp, lbp); return 0; } /* * Return index in the leaf block (lbp) which is either the first * one with this hash value, or if there are none, the insert point * for that hash value. */ int /* index value */ xfs_dir2_leaf_search_hash( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp) /* leaf buffer */ { xfs_dahash_t hash=0; /* hash from this entry */ xfs_dahash_t hashwant; /* hash value looking for */ int high; /* high leaf index */ int low; /* low leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ int mid=0; /* current leaf index */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; leaf = lbp->b_addr; ents = args->dp->d_ops->leaf_ents_p(leaf); args->dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); /* * Note, the table cannot be empty, so we have to go through the loop. * Binary search the leaf entries looking for our hash value. */ for (lep = ents, low = 0, high = leafhdr.count - 1, hashwant = args->hashval; low <= high; ) { mid = (low + high) >> 1; if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) break; if (hash < hashwant) low = mid + 1; else high = mid - 1; } /* * Found one, back up through all the equal hash values. */ if (hash == hashwant) { while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) { mid--; } } /* * Need to point to an entry higher than ours. */ else if (hash < hashwant) mid++; return mid; } /* * Trim off a trailing data block. We know it's empty since the leaf * freespace table says so. */ int /* error */ xfs_dir2_leaf_trim_data( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp, /* leaf buffer */ xfs_dir2_db_t db) /* data block number */ { __be16 *bestsp; /* leaf bests table */ struct xfs_buf *dbp; /* data block buffer */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_trans_t *tp; /* transaction pointer */ dp = args->dp; tp = args->trans; /* * Read the offending data block. We need its buffer. */ error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, db), -1, &dbp); if (error) return error; leaf = lbp->b_addr; ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); #ifdef DEBUG { struct xfs_dir2_data_hdr *hdr = dbp->b_addr; struct xfs_dir2_data_free *bf = dp->d_ops->data_bestfree_p(hdr); ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); ASSERT(be16_to_cpu(bf[0].length) == args->geo->blksize - dp->d_ops->data_entry_offset); ASSERT(db == be32_to_cpu(ltp->bestcount) - 1); } #endif /* * Get rid of the data block. */ if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { ASSERT(error != -ENOSPC); xfs_trans_brelse(tp, dbp); return error; } /* * Eliminate the last bests entry from the table. */ bestsp = xfs_dir2_leaf_bests_p(ltp); be32_add_cpu(<p->bestcount, -1); memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp)); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); return 0; } static inline size_t xfs_dir3_leaf_size( struct xfs_dir3_icleaf_hdr *hdr, int counts) { int entries; int hdrsize; entries = hdr->count - hdr->stale; if (hdr->magic == XFS_DIR2_LEAF1_MAGIC || hdr->magic == XFS_DIR2_LEAFN_MAGIC) hdrsize = sizeof(struct xfs_dir2_leaf_hdr); else hdrsize = sizeof(struct xfs_dir3_leaf_hdr); return hdrsize + entries * sizeof(xfs_dir2_leaf_entry_t) + counts * sizeof(xfs_dir2_data_off_t) + sizeof(xfs_dir2_leaf_tail_t); } /* * Convert node form directory to leaf form directory. * The root of the node form dir needs to already be a LEAFN block. * Just return if we can't do anything. */ int /* error */ xfs_dir2_node_to_leaf( xfs_da_state_t *state) /* directory operation state */ { xfs_da_args_t *args; /* operation arguments */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ struct xfs_buf *fbp; /* buffer for freespace block */ xfs_fileoff_t fo; /* freespace file offset */ xfs_dir2_free_t *free; /* freespace structure */ struct xfs_buf *lbp; /* buffer for leaf block */ xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_mount_t *mp; /* filesystem mount point */ int rval; /* successful free trim? */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir3_icfree_hdr freehdr; /* * There's more than a leaf level in the btree, so there must * be multiple leafn blocks. Give up. */ if (state->path.active > 1) return 0; args = state->args; trace_xfs_dir2_node_to_leaf(args); mp = state->mp; dp = args->dp; tp = args->trans; /* * Get the last offset in the file. */ if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) { return error; } fo -= args->geo->fsbcount; /* * If there are freespace blocks other than the first one, * take this opportunity to remove trailing empty freespace blocks * that may have been left behind during no-space-reservation * operations. */ while (fo > args->geo->freeblk) { if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { return error; } if (rval) fo -= args->geo->fsbcount; else return 0; } /* * Now find the block just before the freespace block. */ if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { return error; } /* * If it's not the single leaf block, give up. */ if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + args->geo->blksize) return 0; lbp = state->path.blk[0].bp; leaf = lbp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); /* * Read the freespace block. */ error = xfs_dir2_free_read(tp, dp, args->geo->freeblk, &fbp); if (error) return error; free = fbp->b_addr; dp->d_ops->free_hdr_from_disk(&freehdr, free); ASSERT(!freehdr.firstdb); /* * Now see if the leafn and free data will fit in a leaf1. * If not, release the buffer and give up. */ if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > args->geo->blksize) { xfs_trans_brelse(tp, fbp); return 0; } /* * If the leaf has any stale entries in it, compress them out. */ if (leafhdr.stale) xfs_dir3_leaf_compact(args, &leafhdr, lbp); lbp->b_ops = &xfs_dir3_leaf1_buf_ops; xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAF1_BUF); leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC) ? XFS_DIR2_LEAF1_MAGIC : XFS_DIR3_LEAF1_MAGIC; /* * Set up the leaf tail from the freespace block. */ ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ltp->bestcount = cpu_to_be32(freehdr.nvalid); /* * Set up the leaf bests table. */ memcpy(xfs_dir2_leaf_bests_p(ltp), dp->d_ops->free_bests_p(free), freehdr.nvalid * sizeof(xfs_dir2_data_off_t)); dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_check(dp, lbp); /* * Get rid of the freespace block. */ error = xfs_dir2_shrink_inode(args, xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET), fbp); if (error) { /* * This can't fail here because it can only happen when * punching out the middle of an extent, and this is an * isolated block. */ ASSERT(error != -ENOSPC); return error; } fbp = NULL; /* * Now see if we can convert the single-leaf directory * down to a block form directory. * This routine always kills the dabuf for the leaf, so * eliminate it from the path. */ error = xfs_dir2_leaf_to_block(args, lbp, NULL); state->path.blk[0].bp = NULL; return error; } xfsprogs-5.3.0/libxfs/xfs_dir2_node.c0000644000175000017500000017571413570057155017453 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" #include "xfs_trans.h" /* * Function declarations. */ static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args, int index); static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2); static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp, int index, xfs_da_state_blk_t *dblk, int *rval); static int xfs_dir2_node_addname_int(xfs_da_args_t *args, xfs_da_state_blk_t *fblk); /* * Check internal consistency of a leafn block. */ #ifdef DEBUG static xfs_failaddr_t xfs_dir3_leafn_check( struct xfs_inode *dp, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir3_icleaf_hdr leafhdr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) return __this_address; } else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC) return __this_address; return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf); } static inline void xfs_dir3_leaf_check( struct xfs_inode *dp, struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_dir3_leafn_check(dp, bp); if (!fa) return; xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount, bp->b_addr, BBTOB(bp->b_length), __FILE__, __LINE__, fa); ASSERT(0); } #else #define xfs_dir3_leaf_check(dp, bp) #endif static xfs_failaddr_t xfs_dir3_free_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_dir2_free_hdr *hdr = bp->b_addr; if (!xfs_verify_magic(bp, hdr->magic)) return __this_address; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) return __this_address; } /* XXX: should bounds check the xfs_dir3_icfree_hdr here */ return NULL; } static void xfs_dir3_free_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_FREE_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_dir3_free_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_dir3_free_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_dir3_free_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_FREE_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_free_buf_ops = { .name = "xfs_dir3_free", .magic = { cpu_to_be32(XFS_DIR2_FREE_MAGIC), cpu_to_be32(XFS_DIR3_FREE_MAGIC) }, .verify_read = xfs_dir3_free_read_verify, .verify_write = xfs_dir3_free_write_verify, .verify_struct = xfs_dir3_free_verify, }; /* Everything ok in the free block header? */ static xfs_failaddr_t xfs_dir3_free_header_check( struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf *bp) { struct xfs_mount *mp = dp->i_mount; unsigned int firstdb; int maxbests; maxbests = dp->d_ops->free_max_bests(mp->m_dir_geo); firstdb = (xfs_dir2_da_to_db(mp->m_dir_geo, fbno) - xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) * maxbests; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; if (be32_to_cpu(hdr3->firstdb) != firstdb) return __this_address; if (be32_to_cpu(hdr3->nvalid) > maxbests) return __this_address; if (be32_to_cpu(hdr3->nvalid) < be32_to_cpu(hdr3->nused)) return __this_address; } else { struct xfs_dir2_free_hdr *hdr = bp->b_addr; if (be32_to_cpu(hdr->firstdb) != firstdb) return __this_address; if (be32_to_cpu(hdr->nvalid) > maxbests) return __this_address; if (be32_to_cpu(hdr->nvalid) < be32_to_cpu(hdr->nused)) return __this_address; } return NULL; } static int __xfs_dir3_free_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { xfs_failaddr_t fa; int err; err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, XFS_DATA_FORK, &xfs_dir3_free_buf_ops); if (err || !*bpp) return err; /* Check things that we can't do in the verifier. */ fa = xfs_dir3_free_header_check(dp, fbno, *bpp); if (fa) { xfs_verifier_error(*bpp, -EFSCORRUPTED, fa); xfs_trans_brelse(tp, *bpp); return -EFSCORRUPTED; } /* try read returns without an error or *bpp if it lands in a hole */ if (tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); return 0; } int xfs_dir2_free_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf **bpp) { return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp); } static int xfs_dir2_free_try_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf **bpp) { return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp); } static int xfs_dir3_free_get_buf( xfs_da_args_t *args, xfs_dir2_db_t fbno, struct xfs_buf **bpp) { struct xfs_trans *tp = args->trans; struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp; int error; struct xfs_dir3_icfree_hdr hdr; error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), -1, &bp, XFS_DATA_FORK); if (error) return error; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF); bp->b_ops = &xfs_dir3_free_buf_ops; /* * Initialize the new block to be empty, and remember * its first slot as our empty slot. */ memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr)); memset(&hdr, 0, sizeof(hdr)); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; hdr.magic = XFS_DIR3_FREE_MAGIC; hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); hdr3->hdr.owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid); } else hdr.magic = XFS_DIR2_FREE_MAGIC; dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr); *bpp = bp; return 0; } /* * Log entries from a freespace block. */ STATIC void xfs_dir2_free_log_bests( struct xfs_da_args *args, struct xfs_buf *bp, int first, /* first entry to log */ int last) /* last entry to log */ { xfs_dir2_free_t *free; /* freespace structure */ __be16 *bests; free = bp->b_addr; bests = args->dp->d_ops->free_bests_p(free); ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); xfs_trans_log_buf(args->trans, bp, (uint)((char *)&bests[first] - (char *)free), (uint)((char *)&bests[last] - (char *)free + sizeof(bests[0]) - 1)); } /* * Log header from a freespace block. */ static void xfs_dir2_free_log_header( struct xfs_da_args *args, struct xfs_buf *bp) { #ifdef DEBUG xfs_dir2_free_t *free; /* freespace structure */ free = bp->b_addr; ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); #endif xfs_trans_log_buf(args->trans, bp, 0, args->dp->d_ops->free_hdr_size - 1); } /* * Convert a leaf-format directory to a node-format directory. * We need to change the magic number of the leaf block, and copy * the freespace table out of the leaf block into its own block. */ int /* error */ xfs_dir2_leaf_to_node( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp) /* leaf buffer */ { xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ struct xfs_buf *fbp; /* freespace buffer */ xfs_dir2_db_t fdb; /* freespace block number */ xfs_dir2_free_t *free; /* freespace structure */ __be16 *from; /* pointer to freespace entry */ int i; /* leaf freespace index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ int n; /* count of live freespc ents */ xfs_dir2_data_off_t off; /* freespace entry value */ __be16 *to; /* pointer to freespace entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir3_icfree_hdr freehdr; trace_xfs_dir2_leaf_to_node(args); dp = args->dp; tp = args->trans; /* * Add a freespace block to the directory. */ if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { return error; } ASSERT(fdb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)); /* * Get the buffer for the new freespace block. */ error = xfs_dir3_free_get_buf(args, fdb, &fbp); if (error) return error; free = fbp->b_addr; dp->d_ops->free_hdr_from_disk(&freehdr, free); leaf = lbp->b_addr; ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); if (be32_to_cpu(ltp->bestcount) > (uint)dp->i_d.di_size / args->geo->blksize) return -EFSCORRUPTED; /* * Copy freespace entries from the leaf block to the new block. * Count active entries. */ from = xfs_dir2_leaf_bests_p(ltp); to = dp->d_ops->free_bests_p(free); for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) { if ((off = be16_to_cpu(*from)) != NULLDATAOFF) n++; *to = cpu_to_be16(off); } /* * Now initialize the freespace block header. */ freehdr.nused = n; freehdr.nvalid = be32_to_cpu(ltp->bestcount); dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr); xfs_dir2_free_log_bests(args, fbp, 0, freehdr.nvalid - 1); xfs_dir2_free_log_header(args, fbp); /* * Converting the leaf to a leafnode is just a matter of changing the * magic number and the ops. Do the change directly to the buffer as * it's less work (and less code) than decoding the header to host * format and back again. */ if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC)) leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC); else leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); lbp->b_ops = &xfs_dir3_leafn_buf_ops; xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF); xfs_dir3_leaf_log_header(args, lbp); xfs_dir3_leaf_check(dp, lbp); return 0; } /* * Add a leaf entry to a leaf block in a node-form directory. * The other work necessary is done from the caller. */ static int /* error */ xfs_dir2_leafn_add( struct xfs_buf *bp, /* leaf buffer */ struct xfs_da_args *args, /* operation arguments */ int index) /* insertion pt for new entry */ { struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_inode *dp = args->dp; struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir2_leaf_entry *lep; struct xfs_dir2_leaf_entry *ents; int compact; /* compacting stale leaves */ int highstale = 0; /* next stale entry */ int lfloghigh; /* high leaf entry logging */ int lfloglow; /* low leaf entry logging */ int lowstale = 0; /* previous stale entry */ trace_xfs_dir2_leafn_add(args, index); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); /* * Quick check just to make sure we are not going to index * into other peoples memory */ if (index < 0) return -EFSCORRUPTED; /* * If there are already the maximum number of leaf entries in * the block, if there are no stale entries it won't fit. * Caller will do a split. If there are stale entries we'll do * a compact. */ if (leafhdr.count == dp->d_ops->leaf_max_ents(args->geo)) { if (!leafhdr.stale) return -ENOSPC; compact = leafhdr.stale > 1; } else compact = 0; ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval); ASSERT(index == leafhdr.count || be32_to_cpu(ents[index].hashval) >= args->hashval); if (args->op_flags & XFS_DA_OP_JUSTCHECK) return 0; /* * Compact out all but one stale leaf entry. Leaves behind * the entry closest to index. */ if (compact) xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, &highstale, &lfloglow, &lfloghigh); else if (leafhdr.stale) { /* * Set impossible logging indices for this case. */ lfloglow = leafhdr.count; lfloghigh = -1; } /* * Insert the new entry, log everything. */ lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, highstale, &lfloglow, &lfloghigh); lep->hashval = cpu_to_be32(args->hashval); lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(args->geo, args->blkno, args->index)); dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, bp); xfs_dir3_leaf_log_ents(args, bp, lfloglow, lfloghigh); xfs_dir3_leaf_check(dp, bp); return 0; } #ifdef DEBUG static void xfs_dir2_free_hdr_check( struct xfs_inode *dp, struct xfs_buf *bp, xfs_dir2_db_t db) { struct xfs_dir3_icfree_hdr hdr; dp->d_ops->free_hdr_from_disk(&hdr, bp->b_addr); ASSERT((hdr.firstdb % dp->d_ops->free_max_bests(dp->i_mount->m_dir_geo)) == 0); ASSERT(hdr.firstdb <= db); ASSERT(db < hdr.firstdb + hdr.nvalid); } #else #define xfs_dir2_free_hdr_check(dp, bp, db) #endif /* DEBUG */ /* * Return the last hash value in the leaf. * Stale entries are ok. */ xfs_dahash_t /* hash value */ xfs_dir2_leaf_lasthash( struct xfs_inode *dp, struct xfs_buf *bp, /* leaf buffer */ int *count) /* count of entries in leaf */ { struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || leafhdr.magic == XFS_DIR2_LEAF1_MAGIC || leafhdr.magic == XFS_DIR3_LEAF1_MAGIC); if (count) *count = leafhdr.count; if (!leafhdr.count) return 0; ents = dp->d_ops->leaf_ents_p(leaf); return be32_to_cpu(ents[leafhdr.count - 1].hashval); } /* * Look up a leaf entry for space to add a name in a node-format leaf block. * The extrablk in state is a freespace block. */ STATIC int xfs_dir2_leafn_lookup_for_addname( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int *indexp, /* out: leaf entry index */ xfs_da_state_t *state) /* state to fill in */ { struct xfs_buf *curbp = NULL; /* current data/free buffer */ xfs_dir2_db_t curdb = -1; /* current data block number */ xfs_dir2_db_t curfdb = -1; /* current free block number */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int fi; /* free entry index */ xfs_dir2_free_t *free = NULL; /* free block structure */ int index; /* leaf entry index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int length; /* length of new data entry */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_dir2_db_t newfdb; /* new free block number */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); xfs_dir3_leaf_check(dp, bp); ASSERT(leafhdr.count > 0); /* * Look up the hash value in the leaf entries. */ index = xfs_dir2_leaf_search_hash(args, bp); /* * Do we have a buffer coming in? */ if (state->extravalid) { /* If so, it's a free block buffer, get the block number. */ curbp = state->extrablk.bp; curfdb = state->extrablk.blkno; free = curbp->b_addr; ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); } length = dp->d_ops->data_entsize(args->namelen); /* * Loop over leaf entries with the right hash value. */ for (lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Pull the data block number from the entry. */ newdb = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); /* * For addname, we're looking for a place to put the new entry. * We want to use a data block with an entry of equal * hash value to ours if there is one with room. * * If this block isn't the data block we already have * in hand, take a look at it. */ if (newdb != curdb) { __be16 *bests; curdb = newdb; /* * Convert the data block to the free block * holding its freespace information. */ newfdb = dp->d_ops->db_to_fdb(args->geo, newdb); /* * If it's not the one we have in hand, read it in. */ if (newfdb != curfdb) { /* * If we had one before, drop it. */ if (curbp) xfs_trans_brelse(tp, curbp); error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(args->geo, newfdb), &curbp); if (error) return error; free = curbp->b_addr; xfs_dir2_free_hdr_check(dp, curbp, curdb); } /* * Get the index for our entry. */ fi = dp->d_ops->db_to_fdindex(args->geo, curdb); /* * If it has room, return it. */ bests = dp->d_ops->free_bests_p(free); if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) { XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", XFS_ERRLEVEL_LOW, mp); if (curfdb != newfdb) xfs_trans_brelse(tp, curbp); return -EFSCORRUPTED; } curfdb = newfdb; if (be16_to_cpu(bests[fi]) >= length) goto out; } } /* Didn't find any space */ fi = -1; out: ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); if (curbp) { /* Giving back a free block. */ state->extravalid = 1; state->extrablk.bp = curbp; state->extrablk.index = fi; state->extrablk.blkno = curfdb; /* * Important: this magic number is not in the buffer - it's for * buffer type information and therefore only the free/data type * matters here, not whether CRCs are enabled or not. */ state->extrablk.magic = XFS_DIR2_FREE_MAGIC; } else { state->extravalid = 0; } /* * Return the index, that will be the insertion point. */ *indexp = index; return -ENOENT; } /* * Look up a leaf entry in a node-format leaf block. * The extrablk in state a data block. */ STATIC int xfs_dir2_leafn_lookup_for_entry( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int *indexp, /* out: leaf entry index */ xfs_da_state_t *state) /* state to fill in */ { struct xfs_buf *curbp = NULL; /* current data/free buffer */ xfs_dir2_db_t curdb = -1; /* current data block number */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int index; /* leaf entry index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_trans_t *tp; /* transaction pointer */ enum xfs_dacmp cmp; /* comparison result */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); xfs_dir3_leaf_check(dp, bp); if (leafhdr.count <= 0) return -EFSCORRUPTED; /* * Look up the hash value in the leaf entries. */ index = xfs_dir2_leaf_search_hash(args, bp); /* * Do we have a buffer coming in? */ if (state->extravalid) { curbp = state->extrablk.bp; curdb = state->extrablk.blkno; } /* * Loop over leaf entries with the right hash value. */ for (lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Pull the data block number from the entry. */ newdb = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); /* * Not adding a new entry, so we really want to find * the name given to us. * * If it's a different data block, go get it. */ if (newdb != curdb) { /* * If we had a block before that we aren't saving * for a CI name, drop it */ if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || curdb != state->extrablk.blkno)) xfs_trans_brelse(tp, curbp); /* * If needing the block that is saved with a CI match, * use it otherwise read in the new data block. */ if (args->cmpresult != XFS_CMP_DIFFERENT && newdb == state->extrablk.blkno) { ASSERT(state->extravalid); curbp = state->extrablk.bp; } else { error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, newdb), -1, &curbp); if (error) return error; } xfs_dir3_data_check(dp, curbp); curdb = newdb; } /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); /* * Compare the entry and if it's an exact match, return * EEXIST immediately. If it's the first case-insensitive * match, store the block & inode number and continue looking. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { /* If there is a CI match block, drop it */ if (args->cmpresult != XFS_CMP_DIFFERENT && curdb != state->extrablk.blkno) xfs_trans_brelse(tp, state->extrablk.bp); args->cmpresult = cmp; args->inumber = be64_to_cpu(dep->inumber); args->filetype = dp->d_ops->data_get_ftype(dep); *indexp = index; state->extravalid = 1; state->extrablk.bp = curbp; state->extrablk.blkno = curdb; state->extrablk.index = (int)((char *)dep - (char *)curbp->b_addr); state->extrablk.magic = XFS_DIR2_DATA_MAGIC; curbp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); if (cmp == XFS_CMP_EXACT) return -EEXIST; } } ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT)); if (curbp) { if (args->cmpresult == XFS_CMP_DIFFERENT) { /* Giving back last used data block. */ state->extravalid = 1; state->extrablk.bp = curbp; state->extrablk.index = -1; state->extrablk.blkno = curdb; state->extrablk.magic = XFS_DIR2_DATA_MAGIC; curbp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); } else { /* If the curbp is not the CI match block, drop it */ if (state->extrablk.bp != curbp) xfs_trans_brelse(tp, curbp); } } else { state->extravalid = 0; } *indexp = index; return -ENOENT; } /* * Look up a leaf entry in a node-format leaf block. * If this is an addname then the extrablk in state is a freespace block, * otherwise it's a data block. */ int xfs_dir2_leafn_lookup_int( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int *indexp, /* out: leaf entry index */ xfs_da_state_t *state) /* state to fill in */ { if (args->op_flags & XFS_DA_OP_ADDNAME) return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, state); return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); } /* * Move count leaf entries from source to destination leaf. * Log entries and headers. Stale entries are preserved. */ static void xfs_dir3_leafn_moveents( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *bp_s, /* source */ struct xfs_dir3_icleaf_hdr *shdr, struct xfs_dir2_leaf_entry *sents, int start_s,/* source leaf index */ struct xfs_buf *bp_d, /* destination */ struct xfs_dir3_icleaf_hdr *dhdr, struct xfs_dir2_leaf_entry *dents, int start_d,/* destination leaf index */ int count) /* count of leaves to copy */ { int stale; /* count stale leaves copied */ trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count); /* * Silently return if nothing to do. */ if (count == 0) return; /* * If the destination index is not the end of the current * destination leaf entries, open up a hole in the destination * to hold the new entries. */ if (start_d < dhdr->count) { memmove(&dents[start_d + count], &dents[start_d], (dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, bp_d, start_d + count, count + dhdr->count - 1); } /* * If the source has stale leaves, count the ones in the copy range * so we can update the header correctly. */ if (shdr->stale) { int i; /* temp leaf index */ for (i = start_s, stale = 0; i < start_s + count; i++) { if (sents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) stale++; } } else stale = 0; /* * Copy the leaf entries from source to destination. */ memcpy(&dents[start_d], &sents[start_s], count * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, bp_d, start_d, start_d + count - 1); /* * If there are source entries after the ones we copied, * delete the ones we copied by sliding the next ones down. */ if (start_s + count < shdr->count) { memmove(&sents[start_s], &sents[start_s + count], count * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, bp_s, start_s, start_s + count - 1); } /* * Update the headers and log them. */ shdr->count -= count; shdr->stale -= stale; dhdr->count += count; dhdr->stale += stale; } /* * Determine the sort order of two leaf blocks. * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. */ int /* sort order */ xfs_dir2_leafn_order( struct xfs_inode *dp, struct xfs_buf *leaf1_bp, /* leaf1 buffer */ struct xfs_buf *leaf2_bp) /* leaf2 buffer */ { struct xfs_dir2_leaf *leaf1 = leaf1_bp->b_addr; struct xfs_dir2_leaf *leaf2 = leaf2_bp->b_addr; struct xfs_dir2_leaf_entry *ents1; struct xfs_dir2_leaf_entry *ents2; struct xfs_dir3_icleaf_hdr hdr1; struct xfs_dir3_icleaf_hdr hdr2; dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1); dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2); ents1 = dp->d_ops->leaf_ents_p(leaf1); ents2 = dp->d_ops->leaf_ents_p(leaf2); if (hdr1.count > 0 && hdr2.count > 0 && (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) || be32_to_cpu(ents2[hdr2.count - 1].hashval) < be32_to_cpu(ents1[hdr1.count - 1].hashval))) return 1; return 0; } /* * Rebalance leaf entries between two leaf blocks. * This is actually only called when the second block is new, * though the code deals with the general case. * A new entry will be inserted in one of the blocks, and that * entry is taken into account when balancing. */ static void xfs_dir2_leafn_rebalance( xfs_da_state_t *state, /* btree cursor */ xfs_da_state_blk_t *blk1, /* first btree block */ xfs_da_state_blk_t *blk2) /* second btree block */ { xfs_da_args_t *args; /* operation arguments */ int count; /* count (& direction) leaves */ int isleft; /* new goes in left leaf */ xfs_dir2_leaf_t *leaf1; /* first leaf structure */ xfs_dir2_leaf_t *leaf2; /* second leaf structure */ int mid; /* midpoint leaf index */ #if defined(DEBUG) || defined(XFS_WARN) int oldstale; /* old count of stale leaves */ #endif int oldsum; /* old total leaf count */ int swap_blocks; /* swapped leaf blocks */ struct xfs_dir2_leaf_entry *ents1; struct xfs_dir2_leaf_entry *ents2; struct xfs_dir3_icleaf_hdr hdr1; struct xfs_dir3_icleaf_hdr hdr2; struct xfs_inode *dp = state->args->dp; args = state->args; /* * If the block order is wrong, swap the arguments. */ swap_blocks = xfs_dir2_leafn_order(dp, blk1->bp, blk2->bp); if (swap_blocks) swap(blk1, blk2); leaf1 = blk1->bp->b_addr; leaf2 = blk2->bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1); dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2); ents1 = dp->d_ops->leaf_ents_p(leaf1); ents2 = dp->d_ops->leaf_ents_p(leaf2); oldsum = hdr1.count + hdr2.count; #if defined(DEBUG) || defined(XFS_WARN) oldstale = hdr1.stale + hdr2.stale; #endif mid = oldsum >> 1; /* * If the old leaf count was odd then the new one will be even, * so we need to divide the new count evenly. */ if (oldsum & 1) { xfs_dahash_t midhash; /* middle entry hash value */ if (mid >= hdr1.count) midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval); else midhash = be32_to_cpu(ents1[mid].hashval); isleft = args->hashval <= midhash; } /* * If the old count is even then the new count is odd, so there's * no preferred side for the new entry. * Pick the left one. */ else isleft = 1; /* * Calculate moved entry count. Positive means left-to-right, * negative means right-to-left. Then move the entries. */ count = hdr1.count - mid + (isleft == 0); if (count > 0) xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1, hdr1.count - count, blk2->bp, &hdr2, ents2, 0, count); else if (count < 0) xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0, blk1->bp, &hdr1, ents1, hdr1.count, count); ASSERT(hdr1.count + hdr2.count == oldsum); ASSERT(hdr1.stale + hdr2.stale == oldstale); /* log the changes made when moving the entries */ dp->d_ops->leaf_hdr_to_disk(leaf1, &hdr1); dp->d_ops->leaf_hdr_to_disk(leaf2, &hdr2); xfs_dir3_leaf_log_header(args, blk1->bp); xfs_dir3_leaf_log_header(args, blk2->bp); xfs_dir3_leaf_check(dp, blk1->bp); xfs_dir3_leaf_check(dp, blk2->bp); /* * Mark whether we're inserting into the old or new leaf. */ if (hdr1.count < hdr2.count) state->inleaf = swap_blocks; else if (hdr1.count > hdr2.count) state->inleaf = !swap_blocks; else state->inleaf = swap_blocks ^ (blk1->index <= hdr1.count); /* * Adjust the expected index for insertion. */ if (!state->inleaf) blk2->index = blk1->index - hdr1.count; /* * Finally sanity check just to make sure we are not returning a * negative index */ if (blk2->index < 0) { state->inleaf = 1; blk2->index = 0; xfs_alert(dp->i_mount, "%s: picked the wrong leaf? reverting original leaf: blk1->index %d", __func__, blk1->index); } } static int xfs_dir3_data_block_free( xfs_da_args_t *args, struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_free *free, xfs_dir2_db_t fdb, int findex, struct xfs_buf *fbp, int longest) { int logfree = 0; __be16 *bests; struct xfs_dir3_icfree_hdr freehdr; struct xfs_inode *dp = args->dp; dp->d_ops->free_hdr_from_disk(&freehdr, free); bests = dp->d_ops->free_bests_p(free); if (hdr) { /* * Data block is not empty, just set the free entry to the new * value. */ bests[findex] = cpu_to_be16(longest); xfs_dir2_free_log_bests(args, fbp, findex, findex); return 0; } /* One less used entry in the free table. */ freehdr.nused--; /* * If this was the last entry in the table, we can trim the table size * back. There might be other entries at the end referring to * non-existent data blocks, get those too. */ if (findex == freehdr.nvalid - 1) { int i; /* free entry index */ for (i = findex - 1; i >= 0; i--) { if (bests[i] != cpu_to_be16(NULLDATAOFF)) break; } freehdr.nvalid = i + 1; logfree = 0; } else { /* Not the last entry, just punch it out. */ bests[findex] = cpu_to_be16(NULLDATAOFF); logfree = 1; } dp->d_ops->free_hdr_to_disk(free, &freehdr); xfs_dir2_free_log_header(args, fbp); /* * If there are no useful entries left in the block, get rid of the * block if we can. */ if (!freehdr.nused) { int error; error = xfs_dir2_shrink_inode(args, fdb, fbp); if (error == 0) { fbp = NULL; logfree = 0; } else if (error != -ENOSPC || args->total != 0) return error; /* * It's possible to get ENOSPC if there is no * space reservation. In this case some one * else will eventually get rid of this block. */ } /* Log the free entry that changed, unless we got rid of it. */ if (logfree) xfs_dir2_free_log_bests(args, fbp, findex, findex); return 0; } /* * Remove an entry from a node directory. * This removes the leaf entry and the data entry, * and updates the free block if necessary. */ static int /* error */ xfs_dir2_leafn_remove( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *bp, /* leaf buffer */ int index, /* leaf entry index */ xfs_da_state_blk_t *dblk, /* data block */ int *rval) /* resulting block needs join */ { xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_db_t db; /* data block number */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ int longest; /* longest data free entry */ int off; /* data block entry offset */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_data_free *bf; /* bestfree table */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leafn_remove(args, index); dp = args->dp; tp = args->trans; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); /* * Point to the entry we're removing. */ lep = &ents[index]; /* * Extract the data block and offset from the entry. */ db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); ASSERT(dblk->blkno == db); off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)); ASSERT(dblk->index == off); /* * Kill the leaf entry by marking it stale. * Log the leaf block changes. */ leafhdr.stale++; dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, bp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir3_leaf_log_ents(args, bp, index, index); /* * Make the data entry free. Keep track of the longest freespace * in the data block in case it changes. */ dbp = dblk->bp; hdr = dbp->b_addr; dep = (xfs_dir2_data_entry_t *)((char *)hdr + off); bf = dp->d_ops->data_bestfree_p(hdr); longest = be16_to_cpu(bf[0].length); needlog = needscan = 0; xfs_dir2_data_make_free(args, dbp, off, dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); /* * Rescan the data block freespaces for bestfree. * Log the data block header if needed. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, dbp); xfs_dir3_data_check(dp, dbp); /* * If the longest data block freespace changes, need to update * the corresponding freeblock entry. */ if (longest < be16_to_cpu(bf[0].length)) { int error; /* error return value */ struct xfs_buf *fbp; /* freeblock buffer */ xfs_dir2_db_t fdb; /* freeblock block number */ int findex; /* index in freeblock entries */ xfs_dir2_free_t *free; /* freeblock structure */ /* * Convert the data block number to a free block, * read in the free block. */ fdb = dp->d_ops->db_to_fdb(args->geo, db); error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(args->geo, fdb), &fbp); if (error) return error; free = fbp->b_addr; #ifdef DEBUG { struct xfs_dir3_icfree_hdr freehdr; dp->d_ops->free_hdr_from_disk(&freehdr, free); ASSERT(freehdr.firstdb == dp->d_ops->free_max_bests(args->geo) * (fdb - xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET))); } #endif /* * Calculate which entry we need to fix. */ findex = dp->d_ops->db_to_fdindex(args->geo, db); longest = be16_to_cpu(bf[0].length); /* * If the data block is now empty we can get rid of it * (usually). */ if (longest == args->geo->blksize - dp->d_ops->data_entry_offset) { /* * Try to punch out the data block. */ error = xfs_dir2_shrink_inode(args, db, dbp); if (error == 0) { dblk->bp = NULL; hdr = NULL; } /* * We can get ENOSPC if there's no space reservation. * In this case just drop the buffer and some one else * will eventually get rid of the empty block. */ else if (!(error == -ENOSPC && args->total == 0)) return error; } /* * If we got rid of the data block, we can eliminate that entry * in the free block. */ error = xfs_dir3_data_block_free(args, hdr, free, fdb, findex, fbp, longest); if (error) return error; } xfs_dir3_leaf_check(dp, bp); /* * Return indication of whether this leaf block is empty enough * to justify trying to join it with a neighbor. */ *rval = (dp->d_ops->leaf_hdr_size + (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) < args->geo->magicpct; return 0; } /* * Split the leaf entries in the old block into old and new blocks. */ int /* error */ xfs_dir2_leafn_split( xfs_da_state_t *state, /* btree cursor */ xfs_da_state_blk_t *oldblk, /* original block */ xfs_da_state_blk_t *newblk) /* newly created block */ { xfs_da_args_t *args; /* operation arguments */ xfs_dablk_t blkno; /* new leaf block number */ int error; /* error return value */ struct xfs_inode *dp; /* * Allocate space for a new leaf node. */ args = state->args; dp = args->dp; ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); error = xfs_da_grow_inode(args, &blkno); if (error) { return error; } /* * Initialize the new leaf block. */ error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(args->geo, blkno), &newblk->bp, XFS_DIR2_LEAFN_MAGIC); if (error) return error; newblk->blkno = blkno; newblk->magic = XFS_DIR2_LEAFN_MAGIC; /* * Rebalance the entries across the two leaves, link the new * block into the leaves. */ xfs_dir2_leafn_rebalance(state, oldblk, newblk); error = xfs_da3_blk_link(state, oldblk, newblk); if (error) { return error; } /* * Insert the new entry in the correct block. */ if (state->inleaf) error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); else error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); /* * Update last hashval in each block since we added the name. */ oldblk->hashval = xfs_dir2_leaf_lasthash(dp, oldblk->bp, NULL); newblk->hashval = xfs_dir2_leaf_lasthash(dp, newblk->bp, NULL); xfs_dir3_leaf_check(dp, oldblk->bp); xfs_dir3_leaf_check(dp, newblk->bp); return error; } /* * Check a leaf block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. */ int /* error */ xfs_dir2_leafn_toosmall( xfs_da_state_t *state, /* btree cursor */ int *action) /* resulting action to take */ { xfs_da_state_blk_t *blk; /* leaf block */ xfs_dablk_t blkno; /* leaf block number */ struct xfs_buf *bp; /* leaf buffer */ int bytes; /* bytes in use */ int count; /* leaf live entry count */ int error; /* error return value */ int forward; /* sibling block direction */ int i; /* sibling counter */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int rval; /* result from path_shift */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; struct xfs_inode *dp = state->args->dp; /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[state->path.active - 1]; leaf = blk->bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); xfs_dir3_leaf_check(dp, blk->bp); count = leafhdr.count - leafhdr.stale; bytes = dp->d_ops->leaf_hdr_size + count * sizeof(ents[0]); if (bytes > (state->args->geo->blksize >> 1)) { /* * Blk over 50%, don't try to join. */ *action = 0; return 0; } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (arbitrarily) * to merge with the forward block unless it is NULL. */ if (count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (leafhdr.forw != 0); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &rval); if (error) return error; *action = rval ? 2 : 0; return 0; } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink a directory over time. */ forward = leafhdr.forw < leafhdr.back; for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { struct xfs_dir3_icleaf_hdr hdr2; blkno = forward ? leafhdr.forw : leafhdr.back; if (blkno == 0) continue; /* * Read the sibling leaf block. */ error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, -1, &bp); if (error) return error; /* * Count bytes in the two blocks combined. */ count = leafhdr.count - leafhdr.stale; bytes = state->args->geo->blksize - (state->args->geo->blksize >> 2); leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf); ents = dp->d_ops->leaf_ents_p(leaf); count += hdr2.count - hdr2.stale; bytes -= count * sizeof(ents[0]); /* * Fits with at least 25% to spare. */ if (bytes >= 0) break; xfs_trans_brelse(state->args->trans, bp); } /* * Didn't like either block, give up. */ if (i >= 2) { *action = 0; return 0; } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &rval); else error = xfs_da3_path_shift(state, &state->path, forward, 0, &rval); if (error) { return error; } *action = rval ? 0 : 1; return 0; } /* * Move all the leaf entries from drop_blk to save_blk. * This is done as part of a join operation. */ void xfs_dir2_leafn_unbalance( xfs_da_state_t *state, /* cursor */ xfs_da_state_blk_t *drop_blk, /* dead block */ xfs_da_state_blk_t *save_blk) /* surviving block */ { xfs_da_args_t *args; /* operation arguments */ xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ struct xfs_dir3_icleaf_hdr savehdr; struct xfs_dir3_icleaf_hdr drophdr; struct xfs_dir2_leaf_entry *sents; struct xfs_dir2_leaf_entry *dents; struct xfs_inode *dp = state->args->dp; args = state->args; ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); drop_leaf = drop_blk->bp->b_addr; save_leaf = save_blk->bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&savehdr, save_leaf); dp->d_ops->leaf_hdr_from_disk(&drophdr, drop_leaf); sents = dp->d_ops->leaf_ents_p(save_leaf); dents = dp->d_ops->leaf_ents_p(drop_leaf); /* * If there are any stale leaf entries, take this opportunity * to purge them. */ if (drophdr.stale) xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp); if (savehdr.stale) xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp); /* * Move the entries from drop to the appropriate end of save. */ drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval); if (xfs_dir2_leafn_order(dp, save_blk->bp, drop_blk->bp)) xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, save_blk->bp, &savehdr, sents, 0, drophdr.count); else xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, save_blk->bp, &savehdr, sents, savehdr.count, drophdr.count); save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval); /* log the changes made when moving the entries */ dp->d_ops->leaf_hdr_to_disk(save_leaf, &savehdr); dp->d_ops->leaf_hdr_to_disk(drop_leaf, &drophdr); xfs_dir3_leaf_log_header(args, save_blk->bp); xfs_dir3_leaf_log_header(args, drop_blk->bp); xfs_dir3_leaf_check(dp, save_blk->bp); xfs_dir3_leaf_check(dp, drop_blk->bp); } /* * Top-level node form directory addname routine. */ int /* error */ xfs_dir2_node_addname( xfs_da_args_t *args) /* operation arguments */ { xfs_da_state_blk_t *blk; /* leaf block for insert */ int error; /* error return value */ int rval; /* sub-return value */ xfs_da_state_t *state; /* btree cursor */ trace_xfs_dir2_node_addname(args); /* * Allocate and initialize the state (btree cursor). */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * Look up the name. We're not supposed to find it, but * this gives us the insertion point. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) rval = error; if (rval != -ENOENT) { goto done; } /* * Add the data entry to a data block. * Extravalid is set to a freeblock found by lookup. */ rval = xfs_dir2_node_addname_int(args, state->extravalid ? &state->extrablk : NULL); if (rval) { goto done; } blk = &state->path.blk[state->path.active - 1]; ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); /* * Add the new leaf entry. */ rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); if (rval == 0) { /* * It worked, fix the hash values up the btree. */ if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) xfs_da3_fixhashpath(state, &state->path); } else { /* * It didn't work, we need to split the leaf block. */ if (args->total == 0) { ASSERT(rval == -ENOSPC); goto done; } /* * Split the leaf block and insert the new entry. */ rval = xfs_da3_split(state); } done: xfs_da_state_free(state); return rval; } /* * Add the data entry for a node-format directory name addition. * The leaf entry is added in xfs_dir2_leafn_add. * We may enter with a freespace block that the lookup found. */ static int /* error */ xfs_dir2_node_addname_int( xfs_da_args_t *args, /* operation arguments */ xfs_da_state_blk_t *fblk) /* optional freespace block */ { xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_db_t dbno; /* data block number */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data entry pointer */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ int error; /* error return value */ xfs_dir2_db_t fbno; /* freespace block number */ struct xfs_buf *fbp; /* freespace buffer */ int findex; /* freespace entry index */ xfs_dir2_free_t *free=NULL; /* freespace block structure */ xfs_dir2_db_t ifbno; /* initial freespace block no */ xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ int length; /* length of the new entry */ int logfree; /* need to log free entry */ xfs_mount_t *mp; /* filesystem mount point */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ __be16 *tagp; /* data entry tag pointer */ xfs_trans_t *tp; /* transaction pointer */ __be16 *bests; struct xfs_dir3_icfree_hdr freehdr; struct xfs_dir2_data_free *bf; xfs_dir2_data_aoff_t aoff; dp = args->dp; mp = dp->i_mount; tp = args->trans; length = dp->d_ops->data_entsize(args->namelen); /* * If we came in with a freespace block that means that lookup * found an entry with our hash value. This is the freespace * block for that data entry. */ if (fblk) { fbp = fblk->bp; /* * Remember initial freespace block number. */ ifbno = fblk->blkno; free = fbp->b_addr; findex = fblk->index; bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); /* * This means the free entry showed that the data block had * space for our entry, so we remembered it. * Use that data block. */ if (findex >= 0) { ASSERT(findex < freehdr.nvalid); ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); ASSERT(be16_to_cpu(bests[findex]) >= length); dbno = freehdr.firstdb + findex; } else { /* * The data block looked at didn't have enough room. * We'll start at the beginning of the freespace entries. */ dbno = -1; findex = 0; } } else { /* * Didn't come in with a freespace block, so no data block. */ ifbno = dbno = -1; fbp = NULL; findex = 0; } /* * If we don't have a data block yet, we're going to scan the * freespace blocks looking for one. Figure out what the * highest freespace block number is. */ if (dbno == -1) { xfs_fileoff_t fo; /* freespace block number */ if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) return error; lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo); fbno = ifbno; } /* * While we haven't identified a data block, search the freeblock * data for a good data block. If we find a null freeblock entry, * indicating a hole in the data blocks, remember that. */ while (dbno == -1) { /* * If we don't have a freeblock in hand, get the next one. */ if (fbp == NULL) { /* * Happens the first time through unless lookup gave * us a freespace block to start with. */ if (++fbno == 0) fbno = xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET); /* * If it's ifbno we already looked at it. */ if (fbno == ifbno) fbno++; /* * If it's off the end we're done. */ if (fbno >= lastfbno) break; /* * Read the block. There can be holes in the * freespace blocks, so this might not succeed. * This should be really rare, so there's no reason * to avoid it. */ error = xfs_dir2_free_try_read(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), &fbp); if (error) return error; if (!fbp) continue; free = fbp->b_addr; findex = 0; } /* * Look at the current free entry. Is it good enough? * * The bests initialisation should be where the bufer is read in * the above branch. But gcc is too stupid to realise that bests * and the freehdr are actually initialised if they are placed * there, so we have to do it here to avoid warnings. Blech. */ bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); if (be16_to_cpu(bests[findex]) != NULLDATAOFF && be16_to_cpu(bests[findex]) >= length) dbno = freehdr.firstdb + findex; else { /* * Are we done with the freeblock? */ if (++findex == freehdr.nvalid) { /* * Drop the block. */ xfs_trans_brelse(tp, fbp); fbp = NULL; if (fblk && fblk->bp) fblk->bp = NULL; } } } /* * If we don't have a data block, we need to allocate one and make * the freespace entries refer to it. */ if (unlikely(dbno == -1)) { /* * Not allowed to allocate, return failure. */ if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) return -ENOSPC; /* * Allocate and initialize the new data block. */ if (unlikely((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &dbno)) || (error = xfs_dir3_data_init(args, dbno, &dbp)))) return error; /* * If (somehow) we have a freespace block, get rid of it. */ if (fbp) xfs_trans_brelse(tp, fbp); if (fblk && fblk->bp) fblk->bp = NULL; /* * Get the freespace block corresponding to the data block * that was just allocated. */ fbno = dp->d_ops->db_to_fdb(args->geo, dbno); error = xfs_dir2_free_try_read(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), &fbp); if (error) return error; /* * If there wasn't a freespace block, the read will * return a NULL fbp. Allocate and initialize a new one. */ if (!fbp) { error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fbno); if (error) return error; if (dp->d_ops->db_to_fdb(args->geo, dbno) != fbno) { xfs_alert(mp, "%s: dir ino %llu needed freesp block %lld for data block %lld, got %lld ifbno %llu lastfbno %d", __func__, (unsigned long long)dp->i_ino, (long long)dp->d_ops->db_to_fdb( args->geo, dbno), (long long)dbno, (long long)fbno, (unsigned long long)ifbno, lastfbno); if (fblk) { xfs_alert(mp, " fblk "PTR_FMT" blkno %llu index %d magic 0x%x", fblk, (unsigned long long)fblk->blkno, fblk->index, fblk->magic); } else { xfs_alert(mp, " ... fblk is NULL"); } XFS_ERROR_REPORT("xfs_dir2_node_addname_int", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } /* * Get a buffer for the new block. */ error = xfs_dir3_free_get_buf(args, fbno, &fbp); if (error) return error; free = fbp->b_addr; bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); /* * Remember the first slot as our empty slot. */ freehdr.firstdb = (fbno - xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)) * dp->d_ops->free_max_bests(args->geo); } else { free = fbp->b_addr; bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); } /* * Set the freespace block index from the data block number. */ findex = dp->d_ops->db_to_fdindex(args->geo, dbno); /* * If it's after the end of the current entries in the * freespace block, extend that table. */ if (findex >= freehdr.nvalid) { ASSERT(findex < dp->d_ops->free_max_bests(args->geo)); freehdr.nvalid = findex + 1; /* * Tag new entry so nused will go up. */ bests[findex] = cpu_to_be16(NULLDATAOFF); } /* * If this entry was for an empty data block * (this should always be true) then update the header. */ if (bests[findex] == cpu_to_be16(NULLDATAOFF)) { freehdr.nused++; dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr); xfs_dir2_free_log_header(args, fbp); } /* * Update the real value in the table. * We haven't allocated the data entry yet so this will * change again. */ hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); bests[findex] = bf[0].length; logfree = 1; } /* * We had a data block so we don't have to make a new one. */ else { /* * If just checking, we succeeded. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) return 0; /* * Read the data block in. */ error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, dbno), -1, &dbp); if (error) return error; hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); logfree = 0; } ASSERT(be16_to_cpu(bf[0].length) >= length); /* * Point to the existing unused space. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); needscan = needlog = 0; /* * Mark the first part of the unused space, inuse for us. */ aoff = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); error = xfs_dir2_data_use_free(args, dbp, dup, aoff, length, &needlog, &needscan); if (error) { xfs_trans_brelse(tp, dbp); return error; } /* * Fill in the new entry and log it. */ dep = (xfs_dir2_data_entry_t *)dup; dep->inumber = cpu_to_be64(args->inumber); dep->namelen = args->namelen; memcpy(dep->name, args->name, dep->namelen); dp->d_ops->data_put_ftype(dep, args->filetype); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, dbp, dep); /* * Rescan the block for bestfree if needed. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); /* * Log the data block header if needed. */ if (needlog) xfs_dir2_data_log_header(args, dbp); /* * If the freespace entry is now wrong, update it. */ bests = dp->d_ops->free_bests_p(free); /* gcc is so stupid */ if (be16_to_cpu(bests[findex]) != be16_to_cpu(bf[0].length)) { bests[findex] = bf[0].length; logfree = 1; } /* * Log the freespace entry if needed. */ if (logfree) xfs_dir2_free_log_bests(args, fbp, findex, findex); /* * Return the data block and offset in args, then drop the data block. */ args->blkno = (xfs_dablk_t)dbno; args->index = be16_to_cpu(*tagp); return 0; } /* * Lookup an entry in a node-format directory. * All the real work happens in xfs_da3_node_lookup_int. * The only real output is the inode number of the entry. */ int /* error */ xfs_dir2_node_lookup( xfs_da_args_t *args) /* operation arguments */ { int error; /* error return value */ int i; /* btree level */ int rval; /* operation return value */ xfs_da_state_t *state; /* btree cursor */ trace_xfs_dir2_node_lookup(args); /* * Allocate and initialize the btree cursor. */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * Fill in the path to the entry in the cursor. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) rval = error; else if (rval == -ENOENT && args->cmpresult == XFS_CMP_CASE) { /* If a CI match, dup the actual name and return -EEXIST */ xfs_dir2_data_entry_t *dep; dep = (xfs_dir2_data_entry_t *) ((char *)state->extrablk.bp->b_addr + state->extrablk.index); rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); } /* * Release the btree blocks and leaf block. */ for (i = 0; i < state->path.active; i++) { xfs_trans_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } /* * Release the data block if we have it. */ if (state->extravalid && state->extrablk.bp) { xfs_trans_brelse(args->trans, state->extrablk.bp); state->extrablk.bp = NULL; } xfs_da_state_free(state); return rval; } /* * Remove an entry from a node-format directory. */ int /* error */ xfs_dir2_node_removename( struct xfs_da_args *args) /* operation arguments */ { struct xfs_da_state_blk *blk; /* leaf block */ int error; /* error return value */ int rval; /* operation return value */ struct xfs_da_state *state; /* btree cursor */ trace_xfs_dir2_node_removename(args); /* * Allocate and initialize the btree cursor. */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* Look up the entry we're deleting, set up the cursor. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) goto out_free; /* Didn't find it, upper layer screwed up. */ if (rval != -EEXIST) { error = rval; goto out_free; } blk = &state->path.blk[state->path.active - 1]; ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); ASSERT(state->extravalid); /* * Remove the leaf and data entries. * Extrablk refers to the data block. */ error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, &state->extrablk, &rval); if (error) goto out_free; /* * Fix the hash values up the btree. */ xfs_da3_fixhashpath(state, &state->path); /* * If we need to join leaf blocks, do it. */ if (rval && state->path.active > 1) error = xfs_da3_join(state); /* * If no errors so far, try conversion to leaf format. */ if (!error) error = xfs_dir2_node_to_leaf(state); out_free: xfs_da_state_free(state); return error; } /* * Replace an entry's inode number in a node-format directory. */ int /* error */ xfs_dir2_node_replace( xfs_da_args_t *args) /* operation arguments */ { xfs_da_state_blk_t *blk; /* leaf block */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_entry_t *dep; /* data entry changed */ int error; /* error return value */ int i; /* btree level */ xfs_ino_t inum; /* new inode number */ int ftype; /* new file type */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ int rval; /* internal return value */ xfs_da_state_t *state; /* btree cursor */ trace_xfs_dir2_node_replace(args); /* * Allocate and initialize the btree cursor. */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * We have to save new inode number and ftype since * xfs_da3_node_lookup_int() is going to overwrite them */ inum = args->inumber; ftype = args->filetype; /* * Lookup the entry to change in the btree. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) { rval = error; } /* * It should be found, since the vnodeops layer has looked it up * and locked it. But paranoia is good. */ if (rval == -EEXIST) { struct xfs_dir2_leaf_entry *ents; /* * Find the leaf entry. */ blk = &state->path.blk[state->path.active - 1]; ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); leaf = blk->bp->b_addr; ents = args->dp->d_ops->leaf_ents_p(leaf); lep = &ents[blk->index]; ASSERT(state->extravalid); /* * Point to the data entry. */ hdr = state->extrablk.bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); dep = (xfs_dir2_data_entry_t *) ((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); ASSERT(inum != be64_to_cpu(dep->inumber)); /* * Fill in the new inode number and log the entry. */ dep->inumber = cpu_to_be64(inum); args->dp->d_ops->data_put_ftype(dep, ftype); xfs_dir2_data_log_entry(args, state->extrablk.bp, dep); rval = 0; } /* * Didn't find it, and we're holding a data block. Drop it. */ else if (state->extravalid) { xfs_trans_brelse(args->trans, state->extrablk.bp); state->extrablk.bp = NULL; } /* * Release all the buffers in the cursor. */ for (i = 0; i < state->path.active; i++) { xfs_trans_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } xfs_da_state_free(state); return rval; } /* * Trim off a trailing empty freespace block. * Return (in rvalp) 1 if we did it, 0 if not. */ int /* error */ xfs_dir2_node_trim_free( xfs_da_args_t *args, /* operation arguments */ xfs_fileoff_t fo, /* free block number */ int *rvalp) /* out: did something */ { struct xfs_buf *bp; /* freespace buffer */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dir2_free_t *free; /* freespace structure */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir3_icfree_hdr freehdr; dp = args->dp; tp = args->trans; *rvalp = 0; /* * Read the freespace block. */ error = xfs_dir2_free_try_read(tp, dp, fo, &bp); if (error) return error; /* * There can be holes in freespace. If fo is a hole, there's * nothing to do. */ if (!bp) return 0; free = bp->b_addr; dp->d_ops->free_hdr_from_disk(&freehdr, free); /* * If there are used entries, there's nothing to do. */ if (freehdr.nused > 0) { xfs_trans_brelse(tp, bp); return 0; } /* * Blow the block away. */ error = xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo), bp); if (error) { /* * Can't fail with ENOSPC since that only happens with no * space reservation, when breaking up an extent into two * pieces. This is the last block of an extent. */ ASSERT(error != -ENOSPC); xfs_trans_brelse(tp, bp); return error; } /* * Return that we succeeded. */ *rvalp = 1; return 0; } xfsprogs-5.3.0/libxfs/xfs_dir2_priv.h0000644000175000017500000001272713435336036017503 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_DIR2_PRIV_H__ #define __XFS_DIR2_PRIV_H__ struct dir_context; /* xfs_dir2.c */ extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, xfs_dir2_db_t *dbp); extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const unsigned char *name, int len); /* xfs_dir2_block.c */ extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_buf **bpp); extern int xfs_dir2_block_addname(struct xfs_da_args *args); extern int xfs_dir2_block_lookup(struct xfs_da_args *args); extern int xfs_dir2_block_removename(struct xfs_da_args *args); extern int xfs_dir2_block_replace(struct xfs_da_args *args); extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args, struct xfs_buf *lbp, struct xfs_buf *dbp); /* xfs_dir2_data.c */ #ifdef DEBUG extern void xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp); #else #define xfs_dir3_data_check(dp,bp) #endif extern xfs_failaddr_t __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp); extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp); extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno); extern struct xfs_dir2_data_free * xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup, int *loghead); extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, struct xfs_buf **bpp); /* xfs_dir2_leaf.c */ extern int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp); extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp); extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args, struct xfs_buf *dbp); extern int xfs_dir2_leaf_addname(struct xfs_da_args *args); extern void xfs_dir3_leaf_compact(struct xfs_da_args *args, struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_buf *bp); extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int *indexp, int *lowstalep, int *highstalep, int *lowlogp, int *highlogp); extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno, struct xfs_buf **bpp, uint16_t magic); extern void xfs_dir3_leaf_log_ents(struct xfs_da_args *args, struct xfs_buf *bp, int first, int last); extern void xfs_dir3_leaf_log_header(struct xfs_da_args *args, struct xfs_buf *bp); extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args); extern int xfs_dir2_leaf_removename(struct xfs_da_args *args); extern int xfs_dir2_leaf_replace(struct xfs_da_args *args); extern int xfs_dir2_leaf_search_hash(struct xfs_da_args *args, struct xfs_buf *lbp); extern int xfs_dir2_leaf_trim_data(struct xfs_da_args *args, struct xfs_buf *lbp, xfs_dir2_db_t db); extern struct xfs_dir2_leaf_entry * xfs_dir3_leaf_find_entry(struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int index, int compact, int lowstale, int highstale, int *lfloglow, int *lfloghigh); extern int xfs_dir2_node_to_leaf(struct xfs_da_state *state); extern xfs_failaddr_t xfs_dir3_leaf_check_int(struct xfs_mount *mp, struct xfs_inode *dp, struct xfs_dir3_icleaf_hdr *hdr, struct xfs_dir2_leaf *leaf); /* xfs_dir2_node.c */ extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args, struct xfs_buf *lbp); extern xfs_dahash_t xfs_dir2_leaf_lasthash(struct xfs_inode *dp, struct xfs_buf *bp, int *count); extern int xfs_dir2_leafn_lookup_int(struct xfs_buf *bp, struct xfs_da_args *args, int *indexp, struct xfs_da_state *state); extern int xfs_dir2_leafn_order(struct xfs_inode *dp, struct xfs_buf *leaf1_bp, struct xfs_buf *leaf2_bp); extern int xfs_dir2_leafn_split(struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); extern int xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action); extern void xfs_dir2_leafn_unbalance(struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk); extern int xfs_dir2_node_addname(struct xfs_da_args *args); extern int xfs_dir2_node_lookup(struct xfs_da_args *args); extern int xfs_dir2_node_removename(struct xfs_da_args *args); extern int xfs_dir2_node_replace(struct xfs_da_args *args); extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo, int *rvalp); extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf **bpp); /* xfs_dir2_sf.c */ extern int xfs_dir2_block_sfsize(struct xfs_inode *dp, struct xfs_dir2_data_hdr *block, struct xfs_dir2_sf_hdr *sfhp); extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp, int size, xfs_dir2_sf_hdr_t *sfhp); extern int xfs_dir2_sf_addname(struct xfs_da_args *args); extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); extern int xfs_dir2_sf_removename(struct xfs_da_args *args); extern int xfs_dir2_sf_replace(struct xfs_da_args *args); extern xfs_failaddr_t xfs_dir2_sf_verify(struct xfs_inode *ip); /* xfs_dir2_readdir.c */ extern int xfs_readdir(struct xfs_trans *tp, struct xfs_inode *dp, struct dir_context *ctx, size_t bufsize); #endif /* __XFS_DIR2_PRIV_H__ */ xfsprogs-5.3.0/libxfs/xfs_dir2_sf.c0000644000175000017500000010620713570057155017125 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" /* * Prototypes for internal functions. */ static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t offset, int new_isize); static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, int new_isize); static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, xfs_dir2_sf_entry_t **sfepp, xfs_dir2_data_aoff_t *offsetp); #ifdef DEBUG static void xfs_dir2_sf_check(xfs_da_args_t *args); #else #define xfs_dir2_sf_check(args) #endif /* DEBUG */ static void xfs_dir2_sf_toino4(xfs_da_args_t *args); static void xfs_dir2_sf_toino8(xfs_da_args_t *args); /* * Given a block directory (dp/block), calculate its size as a shortform (sf) * directory and a header for the sf directory, if it will fit it the * space currently present in the inode. If it won't fit, the output * size is too big (but not accurate). */ int /* size for sf form */ xfs_dir2_block_sfsize( xfs_inode_t *dp, /* incore inode pointer */ xfs_dir2_data_hdr_t *hdr, /* block directory data */ xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ { xfs_dir2_dataptr_t addr; /* data entry address */ xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ xfs_dir2_block_tail_t *btp; /* tail area of the block */ int count; /* shortform entry count */ xfs_dir2_data_entry_t *dep; /* data entry in the block */ int i; /* block entry index */ int i8count; /* count of big-inode entries */ int isdot; /* entry is "." */ int isdotdot; /* entry is ".." */ xfs_mount_t *mp; /* mount structure pointer */ int namelen; /* total name bytes */ xfs_ino_t parent = 0; /* parent inode number */ int size=0; /* total computed size */ int has_ftype; struct xfs_da_geometry *geo; mp = dp->i_mount; geo = mp->m_dir_geo; /* * if there is a filetype field, add the extra byte to the namelen * for each entry that we see. */ has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0; count = i8count = namelen = 0; btp = xfs_dir2_block_tail_p(geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Iterate over the block's data entries by using the leaf pointers. */ for (i = 0; i < be32_to_cpu(btp->count); i++) { if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR) continue; /* * Calculate the pointer to the entry at hand. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(geo, addr)); /* * Detect . and .., so we can special-case them. * . is not included in sf directories. * .. is included by just the parent inode number. */ isdot = dep->namelen == 1 && dep->name[0] == '.'; isdotdot = dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.'; if (!isdot) i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; /* take into account the file type field */ if (!isdot && !isdotdot) { count++; namelen += dep->namelen + has_ftype; } else if (isdotdot) parent = be64_to_cpu(dep->inumber); /* * Calculate the new size, see if we should give up yet. */ size = xfs_dir2_sf_hdr_size(i8count) + /* header */ count * 3 * sizeof(u8) + /* namelen + offset */ namelen + /* name */ (i8count ? /* inumber */ count * XFS_INO64_SIZE : count * XFS_INO32_SIZE); if (size > XFS_IFORK_DSIZE(dp)) return size; /* size value is a failure */ } /* * Create the output header, if it worked. */ sfhp->count = count; sfhp->i8count = i8count; dp->d_ops->sf_put_parent_ino(sfhp, parent); return size; } /* * Convert a block format directory to shortform. * Caller has already checked that it will fit, and built us a header. */ int /* error */ xfs_dir2_block_to_sf( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *bp, int size, /* shortform directory size */ xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_data_entry_t *dep; /* data entry pointer */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* unused data pointer */ char *endptr; /* end of data entries */ int error; /* error return value */ int logflags; /* inode logging flags */ xfs_mount_t *mp; /* filesystem mount point */ char *ptr; /* current data pointer */ xfs_dir2_sf_entry_t *sfep; /* shortform entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */ xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */ trace_xfs_dir2_block_to_sf(args); dp = args->dp; mp = dp->i_mount; /* * allocate a temporary destination buffer the size of the inode * to format the data into. Once we have formatted the data, we * can free the block and copy the formatted data into the inode literal * area. */ dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP); hdr = bp->b_addr; /* * Copy the header into the newly allocate local space. */ sfp = (xfs_dir2_sf_hdr_t *)dst; memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count)); /* * Set up to loop over the block's entries. */ ptr = (char *)dp->d_ops->data_entry_p(hdr); endptr = xfs_dir3_data_endp(args->geo, hdr); sfep = xfs_dir2_sf_firstentry(sfp); /* * Loop over the active and unused entries. * Stop when we reach the leaf/tail portion of the block. */ while (ptr < endptr) { /* * If it's unused, just skip over it. */ dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { ptr += be16_to_cpu(dup->length); continue; } dep = (xfs_dir2_data_entry_t *)ptr; /* * Skip . */ if (dep->namelen == 1 && dep->name[0] == '.') ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); /* * Skip .., but make sure the inode number is right. */ else if (dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.') ASSERT(be64_to_cpu(dep->inumber) == dp->d_ops->sf_get_parent_ino(sfp)); /* * Normal entry, copy it into shortform. */ else { sfep->namelen = dep->namelen; xfs_dir2_sf_put_offset(sfep, (xfs_dir2_data_aoff_t) ((char *)dep - (char *)hdr)); memcpy(sfep->name, dep->name, dep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, be64_to_cpu(dep->inumber)); dp->d_ops->sf_put_ftype(sfep, dp->d_ops->data_get_ftype(dep)); sfep = dp->d_ops->sf_nextentry(sfp, sfep); } ptr += dp->d_ops->data_entsize(dep->namelen); } ASSERT((char *)sfep - (char *)sfp == size); /* now we are done with the block, we can shrink the inode */ logflags = XFS_ILOG_CORE; error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp); if (error) { ASSERT(error != -ENOSPC); goto out; } /* * The buffer is now unconditionally gone, whether * xfs_dir2_shrink_inode worked or not. * * Convert the inode to local format and copy the data in. */ ASSERT(dp->i_df.if_bytes == 0); xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size); dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; dp->i_d.di_size = size; logflags |= XFS_ILOG_DDATA; xfs_dir2_sf_check(args); out: xfs_trans_log_inode(args->trans, dp, logflags); kmem_free(dst); return error; } /* * Add a name to a shortform directory. * There are two algorithms, "easy" and "hard" which we decide on * before changing anything. * Convert to block form if necessary, if the new entry won't fit. */ int /* error */ xfs_dir2_sf_addname( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int incr_isize; /* total change in size */ int new_isize; /* di_size after adding name */ int objchange; /* changing to 8-byte inodes */ xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */ int pick; /* which algorithm to use */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */ trace_xfs_dir2_sf_addname(args); ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); /* * Make sure the shortform value has some of its header. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * Compute entry (and change in) size. */ incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen); objchange = 0; /* * Do we have to change to 8 byte inodes? */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { /* * Yes, adjust the inode size. old count + (parent + new) */ incr_isize += (sfp->count + 2) * XFS_INO64_DIFF; objchange = 1; } new_isize = (int)dp->i_d.di_size + incr_isize; /* * Won't fit as shortform any more (due to size), * or the pick routine says it won't (due to offset values). */ if (new_isize > XFS_IFORK_DSIZE(dp) || (pick = xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { /* * Just checking or no space reservation, it doesn't fit. */ if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) return -ENOSPC; /* * Convert to block form then add the name. */ error = xfs_dir2_sf_to_block(args); if (error) return error; return xfs_dir2_block_addname(args); } /* * Just checking, it fits. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) return 0; /* * Do it the easy way - just add it at the end. */ if (pick == 1) xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); /* * Do it the hard way - look for a place to insert the new entry. * Convert to 8 byte inode numbers first if necessary. */ else { ASSERT(pick == 2); if (objchange) xfs_dir2_sf_toino8(args); xfs_dir2_sf_addname_hard(args, objchange, new_isize); } xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); return 0; } /* * Add the new entry the "easy" way. * This is copying the old directory and adding the new entry at the end. * Since it's sorted by "offset" we need room after the last offset * that's already there, and then room to convert to a block directory. * This is already checked by the pick routine. */ static void xfs_dir2_sf_addname_easy( xfs_da_args_t *args, /* operation arguments */ xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ int new_isize) /* new directory size */ { int byteoff; /* byte offset in sf dir */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; byteoff = (int)((char *)sfep - (char *)sfp); /* * Grow the in-inode space. */ xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen), XFS_DATA_FORK); /* * Need to set up again due to realloc of the inode data. */ sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); /* * Fill in the new entry. */ sfep->namelen = args->namelen; xfs_dir2_sf_put_offset(sfep, offset); memcpy(sfep->name, args->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); dp->d_ops->sf_put_ftype(sfep, args->filetype); /* * Update the header and inode. */ sfp->count++; if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) sfp->i8count++; dp->i_d.di_size = new_isize; xfs_dir2_sf_check(args); } /* * Add the new entry the "hard" way. * The caller has already converted to 8 byte inode numbers if necessary, * in which case we need to leave the i8count at 1. * Find a hole that the new entry will fit into, and copy * the first part of the entries, the new entry, and the last part of * the entries. */ /* ARGSUSED */ static void xfs_dir2_sf_addname_hard( xfs_da_args_t *args, /* operation arguments */ int objchange, /* changing inode number size */ int new_isize) /* new directory size */ { int add_datasize; /* data size need for new ent */ char *buf; /* buffer for old */ xfs_inode_t *dp; /* incore directory inode */ int eof; /* reached end of old dir */ int nbytes; /* temp for byte copies */ xfs_dir2_data_aoff_t new_offset; /* next offset value */ xfs_dir2_data_aoff_t offset; /* current offset value */ int old_isize; /* previous di_size */ xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */ xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */ /* * Copy the old directory to the stack buffer. */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; old_isize = (int)dp->i_d.di_size; buf = kmem_alloc(old_isize, KM_SLEEP); oldsfp = (xfs_dir2_sf_hdr_t *)buf; memcpy(oldsfp, sfp, old_isize); /* * Loop over the old directory finding the place we're going * to insert the new entry. * If it's going to end up at the end then oldsfep will point there. */ for (offset = dp->d_ops->data_first_offset, oldsfep = xfs_dir2_sf_firstentry(oldsfp), add_datasize = dp->d_ops->data_entsize(args->namelen), eof = (char *)oldsfep == &buf[old_isize]; !eof; offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen), oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep), eof = (char *)oldsfep == &buf[old_isize]) { new_offset = xfs_dir2_sf_get_offset(oldsfep); if (offset + add_datasize <= new_offset) break; } /* * Get rid of the old directory, then allocate space for * the new one. We do this so xfs_idata_realloc won't copy * the data. */ xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); /* * Reset the pointer since the buffer was reallocated. */ sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Copy the first part of the directory, including the header. */ nbytes = (int)((char *)oldsfep - (char *)oldsfp); memcpy(sfp, oldsfp, nbytes); sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); /* * Fill in the new entry, and update the header counts. */ sfep->namelen = args->namelen; xfs_dir2_sf_put_offset(sfep, offset); memcpy(sfep->name, args->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); dp->d_ops->sf_put_ftype(sfep, args->filetype); sfp->count++; if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) sfp->i8count++; /* * If there's more left to copy, do that. */ if (!eof) { sfep = dp->d_ops->sf_nextentry(sfp, sfep); memcpy(sfep, oldsfep, old_isize - nbytes); } kmem_free(buf); dp->i_d.di_size = new_isize; xfs_dir2_sf_check(args); } /* * Decide if the new entry will fit at all. * If it will fit, pick between adding the new entry to the end (easy) * or somewhere else (hard). * Return 0 (won't fit), 1 (easy), 2 (hard). */ /*ARGSUSED*/ static int /* pick result */ xfs_dir2_sf_addname_pick( xfs_da_args_t *args, /* operation arguments */ int objchange, /* inode # size changes */ xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ { xfs_inode_t *dp; /* incore directory inode */ int holefit; /* found hole it will fit in */ int i; /* entry number */ xfs_dir2_data_aoff_t offset; /* data block offset */ xfs_dir2_sf_entry_t *sfep; /* shortform entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ int size; /* entry's data size */ int used; /* data bytes used */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; size = dp->d_ops->data_entsize(args->namelen); offset = dp->d_ops->data_first_offset; sfep = xfs_dir2_sf_firstentry(sfp); holefit = 0; /* * Loop over sf entries. * Keep track of data offset and whether we've seen a place * to insert the new entry. */ for (i = 0; i < sfp->count; i++) { if (!holefit) holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); offset = xfs_dir2_sf_get_offset(sfep) + dp->d_ops->data_entsize(sfep->namelen); sfep = dp->d_ops->sf_nextentry(sfp, sfep); } /* * Calculate data bytes used excluding the new entry, if this * was a data block (block form directory). */ used = offset + (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + (uint)sizeof(xfs_dir2_block_tail_t); /* * If it won't fit in a block form then we can't insert it, * we'll go back, convert to block, then try the insert and convert * to leaf. */ if (used + (holefit ? 0 : size) > args->geo->blksize) return 0; /* * If changing the inode number size, do it the hard way. */ if (objchange) return 2; /* * If it won't fit at the end then do it the hard way (use the hole). */ if (used + size > args->geo->blksize) return 2; /* * Do it the easy way. */ *sfepp = sfep; *offsetp = offset; return 1; } #ifdef DEBUG /* * Check consistency of shortform directory, assert if bad. */ static void xfs_dir2_sf_check( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry number */ int i8count; /* number of big inode#s */ xfs_ino_t ino; /* entry inode number */ int offset; /* data offset */ xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; offset = dp->d_ops->data_first_offset; ino = dp->d_ops->sf_get_parent_ino(sfp); i8count = ino > XFS_DIR2_MAX_SHORT_INUM; for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); ino = dp->d_ops->sf_get_ino(sfp, sfep); i8count += ino > XFS_DIR2_MAX_SHORT_INUM; offset = xfs_dir2_sf_get_offset(sfep) + dp->d_ops->data_entsize(sfep->namelen); ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX); } ASSERT(i8count == sfp->i8count); ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); ASSERT(offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize); } #endif /* DEBUG */ /* Verify the consistency of an inline directory. */ xfs_failaddr_t xfs_dir2_sf_verify( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; struct xfs_dir2_sf_hdr *sfp; struct xfs_dir2_sf_entry *sfep; struct xfs_dir2_sf_entry *next_sfep; char *endp; const struct xfs_dir_ops *dops; struct xfs_ifork *ifp; xfs_ino_t ino; int i; int i8count; int offset; int size; int error; uint8_t filetype; ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL); /* * xfs_iread calls us before xfs_setup_inode sets up ip->d_ops, * so we can only trust the mountpoint to have the right pointer. */ dops = xfs_dir_get_ops(mp, NULL); ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data; size = ifp->if_bytes; /* * Give up if the directory is way too short. */ if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) || size < xfs_dir2_sf_hdr_size(sfp->i8count)) return __this_address; endp = (char *)sfp + size; /* Check .. entry */ ino = dops->sf_get_parent_ino(sfp); i8count = ino > XFS_DIR2_MAX_SHORT_INUM; error = xfs_dir_ino_validate(mp, ino); if (error) return __this_address; offset = dops->data_first_offset; /* Check all reported entries */ sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0; i < sfp->count; i++) { /* * struct xfs_dir2_sf_entry has a variable length. * Check the fixed-offset parts of the structure are * within the data buffer. */ if (((char *)sfep + sizeof(*sfep)) >= endp) return __this_address; /* Don't allow names with known bad length. */ if (sfep->namelen == 0) return __this_address; /* * Check that the variable-length part of the structure is * within the data buffer. The next entry starts after the * name component, so nextentry is an acceptable test. */ next_sfep = dops->sf_nextentry(sfp, sfep); if (endp < (char *)next_sfep) return __this_address; /* Check that the offsets always increase. */ if (xfs_dir2_sf_get_offset(sfep) < offset) return __this_address; /* Check the inode number. */ ino = dops->sf_get_ino(sfp, sfep); i8count += ino > XFS_DIR2_MAX_SHORT_INUM; error = xfs_dir_ino_validate(mp, ino); if (error) return __this_address; /* Check the file type. */ filetype = dops->sf_get_ftype(sfep); if (filetype >= XFS_DIR3_FT_MAX) return __this_address; offset = xfs_dir2_sf_get_offset(sfep) + dops->data_entsize(sfep->namelen); sfep = next_sfep; } if (i8count != sfp->i8count) return __this_address; if ((void *)sfep != (void *)endp) return __this_address; /* Make sure this whole thing ought to be in local format. */ if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) return __this_address; return NULL; } /* * Create a new (shortform) directory. */ int /* error, always 0 */ xfs_dir2_sf_create( xfs_da_args_t *args, /* operation arguments */ xfs_ino_t pino) /* parent inode number */ { xfs_inode_t *dp; /* incore directory inode */ int i8count; /* parent inode is an 8-byte number */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ int size; /* directory size */ trace_xfs_dir2_sf_create(args); dp = args->dp; ASSERT(dp != NULL); ASSERT(dp->i_d.di_size == 0); /* * If it's currently a zero-length extent file, * convert it to local format. */ if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); dp->i_df.if_flags |= XFS_IFINLINE; } ASSERT(dp->i_df.if_flags & XFS_IFINLINE); ASSERT(dp->i_df.if_bytes == 0); i8count = pino > XFS_DIR2_MAX_SHORT_INUM; size = xfs_dir2_sf_hdr_size(i8count); /* * Make a buffer for the data. */ xfs_idata_realloc(dp, size, XFS_DATA_FORK); /* * Fill in the header, */ sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; sfp->i8count = i8count; /* * Now can put in the inode number, since i8count is set. */ dp->d_ops->sf_put_parent_ino(sfp, pino); sfp->count = 0; dp->i_d.di_size = size; xfs_dir2_sf_check(args); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); return 0; } /* * Lookup an entry in a shortform directory. * Returns EEXIST if found, ENOENT if not found. */ int /* error */ xfs_dir2_sf_lookup( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ int error; xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ enum xfs_dacmp cmp; /* comparison result */ xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ trace_xfs_dir2_sf_lookup(args); xfs_dir2_sf_check(args); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); /* * Bail out if the directory is way too short. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * Special case for . */ if (args->namelen == 1 && args->name[0] == '.') { args->inumber = dp->i_ino; args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; return -EEXIST; } /* * Special case for .. */ if (args->namelen == 2 && args->name[0] == '.' && args->name[1] == '.') { args->inumber = dp->d_ops->sf_get_parent_ino(sfp); args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; return -EEXIST; } /* * Loop over all the entries trying to match ours. */ ci_sfep = NULL; for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { /* * Compare name and if it's an exact match, return the inode * number. If it's the first case-insensitive match, store the * inode number and continue looking for an exact match. */ cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, sfep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; args->inumber = dp->d_ops->sf_get_ino(sfp, sfep); args->filetype = dp->d_ops->sf_get_ftype(sfep); if (cmp == XFS_CMP_EXACT) return -EEXIST; ci_sfep = sfep; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or replace). * If a case-insensitive match was not found, return -ENOENT. */ if (!ci_sfep) return -ENOENT; /* otherwise process the CI match as required by the caller */ error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); return error; } /* * Remove an entry from a shortform directory. */ int /* error */ xfs_dir2_sf_removename( xfs_da_args_t *args) { int byteoff; /* offset of removed entry */ xfs_inode_t *dp; /* incore directory inode */ int entsize; /* this entry's size */ int i; /* shortform entry index */ int newsize; /* new inode size */ int oldsize; /* old inode size */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ trace_xfs_dir2_sf_removename(args); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); oldsize = (int)dp->i_d.di_size; /* * Bail out if the directory is way too short. */ if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == oldsize); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * Loop over the old directory entries. * Find the one we're deleting. */ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { if (xfs_da_compname(args, sfep->name, sfep->namelen) == XFS_CMP_EXACT) { ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) == args->inumber); break; } } /* * Didn't find it. */ if (i == sfp->count) return -ENOENT; /* * Calculate sizes. */ byteoff = (int)((char *)sfep - (char *)sfp); entsize = dp->d_ops->sf_entsize(sfp, args->namelen); newsize = oldsize - entsize; /* * Copy the part if any after the removed entry, sliding it down. */ if (byteoff + entsize < oldsize) memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize, oldsize - (byteoff + entsize)); /* * Fix up the header and file size. */ sfp->count--; dp->i_d.di_size = newsize; /* * Reallocate, making it smaller. */ xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Are we changing inode number size? */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { if (sfp->i8count == 1) xfs_dir2_sf_toino4(args); else sfp->i8count--; } xfs_dir2_sf_check(args); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); return 0; } /* * Replace the inode number of an entry in a shortform directory. */ int /* error */ xfs_dir2_sf_replace( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ xfs_ino_t ino=0; /* entry old inode number */ int i8elevated; /* sf_toino8 set i8count=1 */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ trace_xfs_dir2_sf_replace(args); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); /* * Bail out if the shortform directory is way too small. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * New inode number is large, and need to convert to 8-byte inodes. */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { int error; /* error return value */ int newsize; /* new inode size */ newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF; /* * Won't fit as shortform, convert to block then do replace. */ if (newsize > XFS_IFORK_DSIZE(dp)) { error = xfs_dir2_sf_to_block(args); if (error) { return error; } return xfs_dir2_block_replace(args); } /* * Still fits, convert to 8-byte now. */ xfs_dir2_sf_toino8(args); i8elevated = 1; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; } else i8elevated = 0; ASSERT(args->namelen != 1 || args->name[0] != '.'); /* * Replace ..'s entry. */ if (args->namelen == 2 && args->name[0] == '.' && args->name[1] == '.') { ino = dp->d_ops->sf_get_parent_ino(sfp); ASSERT(args->inumber != ino); dp->d_ops->sf_put_parent_ino(sfp, args->inumber); } /* * Normal entry, look for the name. */ else { for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { if (xfs_da_compname(args, sfep->name, sfep->namelen) == XFS_CMP_EXACT) { ino = dp->d_ops->sf_get_ino(sfp, sfep); ASSERT(args->inumber != ino); dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); dp->d_ops->sf_put_ftype(sfep, args->filetype); break; } } /* * Didn't find it. */ if (i == sfp->count) { ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); if (i8elevated) xfs_dir2_sf_toino4(args); return -ENOENT; } } /* * See if the old number was large, the new number is small. */ if (ino > XFS_DIR2_MAX_SHORT_INUM && args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { /* * And the old count was one, so need to convert to small. */ if (sfp->i8count == 1) xfs_dir2_sf_toino4(args); else sfp->i8count--; } /* * See if the old number was small, the new number is large. */ if (ino <= XFS_DIR2_MAX_SHORT_INUM && args->inumber > XFS_DIR2_MAX_SHORT_INUM) { /* * add to the i8count unless we just converted to 8-byte * inodes (which does an implied i8count = 1) */ ASSERT(sfp->i8count != 0); if (!i8elevated) sfp->i8count++; } xfs_dir2_sf_check(args); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); return 0; } /* * Convert from 8-byte inode numbers to 4-byte inode numbers. * The last 8-byte inode number is gone, but the count is still 1. */ static void xfs_dir2_sf_toino4( xfs_da_args_t *args) /* operation arguments */ { char *buf; /* old dir's buffer */ xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ int newsize; /* new inode size */ xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ int oldsize; /* old inode size */ xfs_dir2_sf_entry_t *sfep; /* new sf entry */ xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ trace_xfs_dir2_sf_toino4(args); dp = args->dp; /* * Copy the old directory to the buffer. * Then nuke it from the inode, and add the new buffer to the inode. * Don't want xfs_idata_realloc copying the data here. */ oldsize = dp->i_df.if_bytes; buf = kmem_alloc(oldsize, KM_SLEEP); oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(oldsfp->i8count == 1); memcpy(buf, oldsfp, oldsize); /* * Compute the new inode size. */ newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF; xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); /* * Reset our pointers, the data has moved. */ oldsfp = (xfs_dir2_sf_hdr_t *)buf; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Fill in the new header. */ sfp->count = oldsfp->count; sfp->i8count = 0; dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); /* * Copy the entries field by field. */ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), oldsfep = xfs_dir2_sf_firstentry(oldsfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { sfep->namelen = oldsfep->namelen; memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset)); memcpy(sfep->name, oldsfep->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, dp->d_ops->sf_get_ino(oldsfp, oldsfep)); dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); } /* * Clean up the inode. */ kmem_free(buf); dp->i_d.di_size = newsize; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); } /* * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers. * The new entry w/ an 8-byte inode number is not there yet; we leave with * i8count set to 1, but no corresponding 8-byte entry. */ static void xfs_dir2_sf_toino8( xfs_da_args_t *args) /* operation arguments */ { char *buf; /* old dir's buffer */ xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ int newsize; /* new inode size */ xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ int oldsize; /* old inode size */ xfs_dir2_sf_entry_t *sfep; /* new sf entry */ xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ trace_xfs_dir2_sf_toino8(args); dp = args->dp; /* * Copy the old directory to the buffer. * Then nuke it from the inode, and add the new buffer to the inode. * Don't want xfs_idata_realloc copying the data here. */ oldsize = dp->i_df.if_bytes; buf = kmem_alloc(oldsize, KM_SLEEP); oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(oldsfp->i8count == 0); memcpy(buf, oldsfp, oldsize); /* * Compute the new inode size (nb: entry count + 1 for parent) */ newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF; xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); /* * Reset our pointers, the data has moved. */ oldsfp = (xfs_dir2_sf_hdr_t *)buf; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Fill in the new header. */ sfp->count = oldsfp->count; sfp->i8count = 1; dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); /* * Copy the entries field by field. */ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), oldsfep = xfs_dir2_sf_firstentry(oldsfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { sfep->namelen = oldsfep->namelen; memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset)); memcpy(sfep->name, oldsfep->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, dp->d_ops->sf_get_ino(oldsfp, oldsfep)); dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); } /* * Clean up the inode. */ kmem_free(buf); dp->i_d.di_size = newsize; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); } xfsprogs-5.3.0/libxfs/xfs_dquot_buf.c0000644000175000017500000001634213570057155017565 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_quota_defs.h" int xfs_calc_dquots_per_chunk( unsigned int nbblks) /* basic block units */ { ASSERT(nbblks > 0); return BBTOB(nbblks) / sizeof(xfs_dqblk_t); } /* * Do some primitive error checking on ondisk dquot data structures. * * The xfs_dqblk structure /contains/ the xfs_disk_dquot structure; * we verify them separately because at some points we have only the * smaller xfs_disk_dquot structure available. */ xfs_failaddr_t xfs_dquot_verify( struct xfs_mount *mp, xfs_disk_dquot_t *ddq, xfs_dqid_t id, uint type) /* used only during quotacheck */ { /* * We can encounter an uninitialized dquot buffer for 2 reasons: * 1. If we crash while deleting the quotainode(s), and those blks got * used for user data. This is because we take the path of regular * file deletion; however, the size field of quotainodes is never * updated, so all the tricks that we play in itruncate_finish * don't quite matter. * * 2. We don't play the quota buffers when there's a quotaoff logitem. * But the allocation will be replayed so we'll end up with an * uninitialized quota block. * * This is all fine; things are still consistent, and we haven't lost * any quota information. Just don't complain about bad dquot blks. */ if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) return __this_address; if (ddq->d_version != XFS_DQUOT_VERSION) return __this_address; if (type && ddq->d_flags != type) return __this_address; if (ddq->d_flags != XFS_DQ_USER && ddq->d_flags != XFS_DQ_PROJ && ddq->d_flags != XFS_DQ_GROUP) return __this_address; if (id != -1 && id != be32_to_cpu(ddq->d_id)) return __this_address; if (!ddq->d_id) return NULL; if (ddq->d_blk_softlimit && be64_to_cpu(ddq->d_bcount) > be64_to_cpu(ddq->d_blk_softlimit) && !ddq->d_btimer) return __this_address; if (ddq->d_ino_softlimit && be64_to_cpu(ddq->d_icount) > be64_to_cpu(ddq->d_ino_softlimit) && !ddq->d_itimer) return __this_address; if (ddq->d_rtb_softlimit && be64_to_cpu(ddq->d_rtbcount) > be64_to_cpu(ddq->d_rtb_softlimit) && !ddq->d_rtbtimer) return __this_address; return NULL; } xfs_failaddr_t xfs_dqblk_verify( struct xfs_mount *mp, struct xfs_dqblk *dqb, xfs_dqid_t id, uint type) /* used only during quotacheck */ { if (xfs_sb_version_hascrc(&mp->m_sb) && !uuid_equal(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; return xfs_dquot_verify(mp, &dqb->dd_diskdq, id, type); } /* * Do some primitive error checking on ondisk dquot data structures. */ void xfs_dqblk_repair( struct xfs_mount *mp, struct xfs_dqblk *dqb, xfs_dqid_t id, uint type) { /* * Typically, a repair is only requested by quotacheck. */ ASSERT(id != -1); memset(dqb, 0, sizeof(xfs_dqblk_t)); dqb->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); dqb->dd_diskdq.d_version = XFS_DQUOT_VERSION; dqb->dd_diskdq.d_flags = type; dqb->dd_diskdq.d_id = cpu_to_be32(id); if (xfs_sb_version_hascrc(&mp->m_sb)) { uuid_copy(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid); xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk), XFS_DQUOT_CRC_OFF); } } STATIC bool xfs_dquot_buf_verify_crc( struct xfs_mount *mp, struct xfs_buf *bp, bool readahead) { struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; int ndquots; int i; if (!xfs_sb_version_hascrc(&mp->m_sb)) return true; /* * if we are in log recovery, the quota subsystem has not been * initialised so we have no quotainfo structure. In that case, we need * to manually calculate the number of dquots in the buffer. */ if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else ndquots = xfs_calc_dquots_per_chunk(bp->b_length); for (i = 0; i < ndquots; i++, d++) { if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), XFS_DQUOT_CRC_OFF)) { if (!readahead) xfs_buf_verifier_error(bp, -EFSBADCRC, __func__, d, sizeof(*d), __this_address); return false; } } return true; } STATIC xfs_failaddr_t xfs_dquot_buf_verify( struct xfs_mount *mp, struct xfs_buf *bp, bool readahead) { struct xfs_dqblk *dqb = bp->b_addr; xfs_failaddr_t fa; xfs_dqid_t id = 0; int ndquots; int i; /* * if we are in log recovery, the quota subsystem has not been * initialised so we have no quotainfo structure. In that case, we need * to manually calculate the number of dquots in the buffer. */ if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else ndquots = xfs_calc_dquots_per_chunk(bp->b_length); /* * On the first read of the buffer, verify that each dquot is valid. * We don't know what the id of the dquot is supposed to be, just that * they should be increasing monotonically within the buffer. If the * first id is corrupt, then it will fail on the second dquot in the * buffer so corruptions could point to the wrong dquot in this case. */ for (i = 0; i < ndquots; i++) { struct xfs_disk_dquot *ddq; ddq = &dqb[i].dd_diskdq; if (i == 0) id = be32_to_cpu(ddq->d_id); fa = xfs_dqblk_verify(mp, &dqb[i], id + i, 0); if (fa) { if (!readahead) xfs_buf_verifier_error(bp, -EFSCORRUPTED, __func__, &dqb[i], sizeof(struct xfs_dqblk), fa); return fa; } } return NULL; } static xfs_failaddr_t xfs_dquot_buf_verify_struct( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; return xfs_dquot_buf_verify(mp, bp, false); } static void xfs_dquot_buf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; if (!xfs_dquot_buf_verify_crc(mp, bp, false)) return; xfs_dquot_buf_verify(mp, bp, false); } /* * readahead errors are silent and simply leave the buffer as !done so a real * read will then be run with the xfs_dquot_buf_ops verifier. See * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than * reporting the failure. */ static void xfs_dquot_buf_readahead_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; if (!xfs_dquot_buf_verify_crc(mp, bp, true) || xfs_dquot_buf_verify(mp, bp, true) != NULL) { xfs_buf_ioerror(bp, -EIO); bp->b_flags &= ~XBF_DONE; } } /* * we don't calculate the CRC here as that is done when the dquot is flushed to * the buffer after the update is done. This ensures that the dquot in the * buffer always has an up-to-date CRC value. */ static void xfs_dquot_buf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_dquot_buf_verify(mp, bp, false); } const struct xfs_buf_ops xfs_dquot_buf_ops = { .name = "xfs_dquot", .magic16 = { cpu_to_be16(XFS_DQUOT_MAGIC), cpu_to_be16(XFS_DQUOT_MAGIC) }, .verify_read = xfs_dquot_buf_read_verify, .verify_write = xfs_dquot_buf_write_verify, .verify_struct = xfs_dquot_buf_verify_struct, }; const struct xfs_buf_ops xfs_dquot_buf_ra_ops = { .name = "xfs_dquot_ra", .magic16 = { cpu_to_be16(XFS_DQUOT_MAGIC), cpu_to_be16(XFS_DQUOT_MAGIC) }, .verify_read = xfs_dquot_buf_readahead_verify, .verify_write = xfs_dquot_buf_write_verify, }; xfsprogs-5.3.0/libxfs/xfs_errortag.h0000644000175000017500000000751613570057155017432 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * Copyright (C) 2017 Oracle. * All Rights Reserved. */ #ifndef __XFS_ERRORTAG_H_ #define __XFS_ERRORTAG_H_ /* * error injection tags - the labels can be anything you want * but each tag should have its own unique number */ #define XFS_ERRTAG_NOERROR 0 #define XFS_ERRTAG_IFLUSH_1 1 #define XFS_ERRTAG_IFLUSH_2 2 #define XFS_ERRTAG_IFLUSH_3 3 #define XFS_ERRTAG_IFLUSH_4 4 #define XFS_ERRTAG_IFLUSH_5 5 #define XFS_ERRTAG_IFLUSH_6 6 #define XFS_ERRTAG_DA_READ_BUF 7 #define XFS_ERRTAG_BTREE_CHECK_LBLOCK 8 #define XFS_ERRTAG_BTREE_CHECK_SBLOCK 9 #define XFS_ERRTAG_ALLOC_READ_AGF 10 #define XFS_ERRTAG_IALLOC_READ_AGI 11 #define XFS_ERRTAG_ITOBP_INOTOBP 12 #define XFS_ERRTAG_IUNLINK 13 #define XFS_ERRTAG_IUNLINK_REMOVE 14 #define XFS_ERRTAG_DIR_INO_VALIDATE 15 #define XFS_ERRTAG_BULKSTAT_READ_CHUNK 16 #define XFS_ERRTAG_IODONE_IOERR 17 #define XFS_ERRTAG_STRATREAD_IOERR 18 #define XFS_ERRTAG_STRATCMPL_IOERR 19 #define XFS_ERRTAG_DIOWRITE_IOERR 20 #define XFS_ERRTAG_BMAPIFORMAT 21 #define XFS_ERRTAG_FREE_EXTENT 22 #define XFS_ERRTAG_RMAP_FINISH_ONE 23 #define XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE 24 #define XFS_ERRTAG_REFCOUNT_FINISH_ONE 25 #define XFS_ERRTAG_BMAP_FINISH_ONE 26 #define XFS_ERRTAG_AG_RESV_CRITICAL 27 /* * DEBUG mode instrumentation to test and/or trigger delayed allocation * block killing in the event of failed writes. When enabled, all * buffered writes are silenty dropped and handled as if they failed. * All delalloc blocks in the range of the write (including pre-existing * delalloc blocks!) are tossed as part of the write failure error * handling sequence. */ #define XFS_ERRTAG_DROP_WRITES 28 #define XFS_ERRTAG_LOG_BAD_CRC 29 #define XFS_ERRTAG_LOG_ITEM_PIN 30 #define XFS_ERRTAG_BUF_LRU_REF 31 #define XFS_ERRTAG_FORCE_SCRUB_REPAIR 32 #define XFS_ERRTAG_FORCE_SUMMARY_RECALC 33 #define XFS_ERRTAG_IUNLINK_FALLBACK 34 #define XFS_ERRTAG_MAX 35 /* * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. */ #define XFS_RANDOM_DEFAULT 100 #define XFS_RANDOM_IFLUSH_1 XFS_RANDOM_DEFAULT #define XFS_RANDOM_IFLUSH_2 XFS_RANDOM_DEFAULT #define XFS_RANDOM_IFLUSH_3 XFS_RANDOM_DEFAULT #define XFS_RANDOM_IFLUSH_4 XFS_RANDOM_DEFAULT #define XFS_RANDOM_IFLUSH_5 XFS_RANDOM_DEFAULT #define XFS_RANDOM_IFLUSH_6 XFS_RANDOM_DEFAULT #define XFS_RANDOM_DA_READ_BUF XFS_RANDOM_DEFAULT #define XFS_RANDOM_BTREE_CHECK_LBLOCK (XFS_RANDOM_DEFAULT/4) #define XFS_RANDOM_BTREE_CHECK_SBLOCK XFS_RANDOM_DEFAULT #define XFS_RANDOM_ALLOC_READ_AGF XFS_RANDOM_DEFAULT #define XFS_RANDOM_IALLOC_READ_AGI XFS_RANDOM_DEFAULT #define XFS_RANDOM_ITOBP_INOTOBP XFS_RANDOM_DEFAULT #define XFS_RANDOM_IUNLINK XFS_RANDOM_DEFAULT #define XFS_RANDOM_IUNLINK_REMOVE XFS_RANDOM_DEFAULT #define XFS_RANDOM_DIR_INO_VALIDATE XFS_RANDOM_DEFAULT #define XFS_RANDOM_BULKSTAT_READ_CHUNK XFS_RANDOM_DEFAULT #define XFS_RANDOM_IODONE_IOERR (XFS_RANDOM_DEFAULT/10) #define XFS_RANDOM_STRATREAD_IOERR (XFS_RANDOM_DEFAULT/10) #define XFS_RANDOM_STRATCMPL_IOERR (XFS_RANDOM_DEFAULT/10) #define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT #define XFS_RANDOM_FREE_EXTENT 1 #define XFS_RANDOM_RMAP_FINISH_ONE 1 #define XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE 1 #define XFS_RANDOM_REFCOUNT_FINISH_ONE 1 #define XFS_RANDOM_BMAP_FINISH_ONE 1 #define XFS_RANDOM_AG_RESV_CRITICAL 4 #define XFS_RANDOM_DROP_WRITES 1 #define XFS_RANDOM_LOG_BAD_CRC 1 #define XFS_RANDOM_LOG_ITEM_PIN 1 #define XFS_RANDOM_BUF_LRU_REF 2 #define XFS_RANDOM_FORCE_SCRUB_REPAIR 1 #define XFS_RANDOM_FORCE_SUMMARY_RECALC 1 #define XFS_RANDOM_IUNLINK_FALLBACK (XFS_RANDOM_DEFAULT/10) #endif /* __XFS_ERRORTAG_H_ */ xfsprogs-5.3.0/libxfs/xfs_format.h0000644000175000017500000016070313570057155017073 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_FORMAT_H__ #define __XFS_FORMAT_H__ /* * XFS On Disk Format Definitions * * This header file defines all the on-disk format definitions for * general XFS objects. Directory and attribute related objects are defined in * xfs_da_format.h, which log and log item formats are defined in * xfs_log_format.h. Everything else goes here. */ struct xfs_mount; struct xfs_trans; struct xfs_inode; struct xfs_buf; struct xfs_ifork; /* * Super block * Fits into a sector-sized buffer at address 0 of each allocation group. * Only the first of these is ever updated except during growfs. */ #define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ #define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ #define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ #define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ #define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ #define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */ #define XFS_SB_VERSION_NUMBITS 0x000f #define XFS_SB_VERSION_ALLFBITS 0xfff0 #define XFS_SB_VERSION_ATTRBIT 0x0010 #define XFS_SB_VERSION_NLINKBIT 0x0020 #define XFS_SB_VERSION_QUOTABIT 0x0040 #define XFS_SB_VERSION_ALIGNBIT 0x0080 #define XFS_SB_VERSION_DALIGNBIT 0x0100 #define XFS_SB_VERSION_SHAREDBIT 0x0200 #define XFS_SB_VERSION_LOGV2BIT 0x0400 #define XFS_SB_VERSION_SECTORBIT 0x0800 #define XFS_SB_VERSION_EXTFLGBIT 0x1000 #define XFS_SB_VERSION_DIRV2BIT 0x2000 #define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */ #define XFS_SB_VERSION_MOREBITSBIT 0x8000 /* * The size of a single extended attribute on disk is limited by * the size of index values within the attribute entries themselves. * These are be16 fields, so we can only support attribute data * sizes up to 2^16 bytes in length. */ #define XFS_XATTR_SIZE_MAX (1 << 16) /* * Supported feature bit list is just all bits in the versionnum field because * we've used them all up and understand them all. Except, of course, for the * shared superblock bit, which nobody knows what it does and so is unsupported. */ #define XFS_SB_VERSION_OKBITS \ ((XFS_SB_VERSION_NUMBITS | XFS_SB_VERSION_ALLFBITS) & \ ~XFS_SB_VERSION_SHAREDBIT) /* * There are two words to hold XFS "feature" bits: the original * word, sb_versionnum, and sb_features2. Whenever a bit is set in * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set. * * These defines represent bits in sb_features2. */ #define XFS_SB_VERSION2_RESERVED1BIT 0x00000001 #define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */ #define XFS_SB_VERSION2_RESERVED4BIT 0x00000004 #define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */ #define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */ #define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */ #define XFS_SB_VERSION2_CRCBIT 0x00000100 /* metadata CRCs */ #define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */ #define XFS_SB_VERSION2_OKBITS \ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ XFS_SB_VERSION2_ATTR2BIT | \ XFS_SB_VERSION2_PROJID32BIT | \ XFS_SB_VERSION2_FTYPE) /* Maximum size of the xfs filesystem label, no terminating NULL */ #define XFSLABEL_MAX 12 /* * Superblock - in core version. Must match the ondisk version below. * Must be padded to 64 bit alignment. */ typedef struct xfs_sb { uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ uint32_t sb_blocksize; /* logical block size, bytes */ xfs_rfsblock_t sb_dblocks; /* number of data blocks */ xfs_rfsblock_t sb_rblocks; /* number of realtime blocks */ xfs_rtblock_t sb_rextents; /* number of realtime extents */ uuid_t sb_uuid; /* user-visible file system unique id */ xfs_fsblock_t sb_logstart; /* starting block of log if internal */ xfs_ino_t sb_rootino; /* root inode number */ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ xfs_agblock_t sb_agblocks; /* size of an allocation group */ xfs_agnumber_t sb_agcount; /* number of allocation groups */ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ xfs_extlen_t sb_logblocks; /* number of log blocks */ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ uint16_t sb_sectsize; /* volume sector size, bytes */ uint16_t sb_inodesize; /* inode size, bytes */ uint16_t sb_inopblock; /* inodes per block */ char sb_fname[XFSLABEL_MAX]; /* file system name */ uint8_t sb_blocklog; /* log2 of sb_blocksize */ uint8_t sb_sectlog; /* log2 of sb_sectsize */ uint8_t sb_inodelog; /* log2 of sb_inodesize */ uint8_t sb_inopblog; /* log2 of sb_inopblock */ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ uint8_t sb_rextslog; /* log2 of sb_rextents */ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ uint8_t sb_imax_pct; /* max % of fs for inode space */ /* statistics */ /* * These fields must remain contiguous. If you really * want to change their layout, make sure you fix the * code in xfs_trans_apply_sb_deltas(). */ uint64_t sb_icount; /* allocated inodes */ uint64_t sb_ifree; /* free inodes */ uint64_t sb_fdblocks; /* free data blocks */ uint64_t sb_frextents; /* free realtime extents */ /* * End contiguous fields. */ xfs_ino_t sb_uquotino; /* user quota inode */ xfs_ino_t sb_gquotino; /* group quota inode */ uint16_t sb_qflags; /* quota flags */ uint8_t sb_flags; /* misc. flags */ uint8_t sb_shared_vn; /* shared version number */ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ uint32_t sb_unit; /* stripe or raid unit */ uint32_t sb_width; /* stripe or raid width */ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ uint8_t sb_logsectlog; /* log2 of the log sector size */ uint16_t sb_logsectsize; /* sector size for the log, bytes */ uint32_t sb_logsunit; /* stripe unit size for the log */ uint32_t sb_features2; /* additional feature bits */ /* * bad features2 field as a result of failing to pad the sb structure to * 64 bits. Some machines will be using this field for features2 bits. * Easiest just to mark it bad and not use it for anything else. * * This is not kept up to date in memory; it is always overwritten by * the value in sb_features2 when formatting the incore superblock to * the disk buffer. */ uint32_t sb_bad_features2; /* version 5 superblock fields start here */ /* feature masks */ uint32_t sb_features_compat; uint32_t sb_features_ro_compat; uint32_t sb_features_incompat; uint32_t sb_features_log_incompat; uint32_t sb_crc; /* superblock crc */ xfs_extlen_t sb_spino_align; /* sparse inode chunk alignment */ xfs_ino_t sb_pquotino; /* project quota inode */ xfs_lsn_t sb_lsn; /* last write sequence */ uuid_t sb_meta_uuid; /* metadata file system unique id */ /* must be padded to 64 bit alignment */ } xfs_sb_t; #define XFS_SB_CRC_OFF offsetof(struct xfs_sb, sb_crc) /* * Superblock - on disk version. Must match the in core version above. * Must be padded to 64 bit alignment. */ typedef struct xfs_dsb { __be32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ __be32 sb_blocksize; /* logical block size, bytes */ __be64 sb_dblocks; /* number of data blocks */ __be64 sb_rblocks; /* number of realtime blocks */ __be64 sb_rextents; /* number of realtime extents */ uuid_t sb_uuid; /* user-visible file system unique id */ __be64 sb_logstart; /* starting block of log if internal */ __be64 sb_rootino; /* root inode number */ __be64 sb_rbmino; /* bitmap inode for realtime extents */ __be64 sb_rsumino; /* summary inode for rt bitmap */ __be32 sb_rextsize; /* realtime extent size, blocks */ __be32 sb_agblocks; /* size of an allocation group */ __be32 sb_agcount; /* number of allocation groups */ __be32 sb_rbmblocks; /* number of rt bitmap blocks */ __be32 sb_logblocks; /* number of log blocks */ __be16 sb_versionnum; /* header version == XFS_SB_VERSION */ __be16 sb_sectsize; /* volume sector size, bytes */ __be16 sb_inodesize; /* inode size, bytes */ __be16 sb_inopblock; /* inodes per block */ char sb_fname[XFSLABEL_MAX]; /* file system name */ __u8 sb_blocklog; /* log2 of sb_blocksize */ __u8 sb_sectlog; /* log2 of sb_sectsize */ __u8 sb_inodelog; /* log2 of sb_inodesize */ __u8 sb_inopblog; /* log2 of sb_inopblock */ __u8 sb_agblklog; /* log2 of sb_agblocks (rounded up) */ __u8 sb_rextslog; /* log2 of sb_rextents */ __u8 sb_inprogress; /* mkfs is in progress, don't mount */ __u8 sb_imax_pct; /* max % of fs for inode space */ /* statistics */ /* * These fields must remain contiguous. If you really * want to change their layout, make sure you fix the * code in xfs_trans_apply_sb_deltas(). */ __be64 sb_icount; /* allocated inodes */ __be64 sb_ifree; /* free inodes */ __be64 sb_fdblocks; /* free data blocks */ __be64 sb_frextents; /* free realtime extents */ /* * End contiguous fields. */ __be64 sb_uquotino; /* user quota inode */ __be64 sb_gquotino; /* group quota inode */ __be16 sb_qflags; /* quota flags */ __u8 sb_flags; /* misc. flags */ __u8 sb_shared_vn; /* shared version number */ __be32 sb_inoalignmt; /* inode chunk alignment, fsblocks */ __be32 sb_unit; /* stripe or raid unit */ __be32 sb_width; /* stripe or raid width */ __u8 sb_dirblklog; /* log2 of dir block size (fsbs) */ __u8 sb_logsectlog; /* log2 of the log sector size */ __be16 sb_logsectsize; /* sector size for the log, bytes */ __be32 sb_logsunit; /* stripe unit size for the log */ __be32 sb_features2; /* additional feature bits */ /* * bad features2 field as a result of failing to pad the sb * structure to 64 bits. Some machines will be using this field * for features2 bits. Easiest just to mark it bad and not use * it for anything else. */ __be32 sb_bad_features2; /* version 5 superblock fields start here */ /* feature masks */ __be32 sb_features_compat; __be32 sb_features_ro_compat; __be32 sb_features_incompat; __be32 sb_features_log_incompat; __le32 sb_crc; /* superblock crc */ __be32 sb_spino_align; /* sparse inode chunk alignment */ __be64 sb_pquotino; /* project quota inode */ __be64 sb_lsn; /* last write sequence */ uuid_t sb_meta_uuid; /* metadata file system unique id */ /* must be padded to 64 bit alignment */ } xfs_dsb_t; /* * Misc. Flags - warning - these will be cleared by xfs_repair unless * a feature bit is set when the flag is used. */ #define XFS_SBF_NOFLAGS 0x00 /* no flags set */ #define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ /* * define max. shared version we can interoperate with */ #define XFS_SB_MAX_SHARED_VN 0 #define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) /* * The first XFS version we support is a v4 superblock with V2 directories. */ static inline bool xfs_sb_good_v4_features(struct xfs_sb *sbp) { if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) return false; if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) return false; /* check for unknown features in the fs */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) return false; return true; } static inline bool xfs_sb_good_version(struct xfs_sb *sbp) { if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) return true; if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) return xfs_sb_good_v4_features(sbp); return false; } static inline bool xfs_sb_version_hasrealtime(struct xfs_sb *sbp) { return sbp->sb_rblocks > 0; } /* * Detect a mismatched features2 field. Older kernels read/wrote * this into the wrong slot, so to be safe we keep them in sync. */ static inline bool xfs_sb_has_mismatched_features2(struct xfs_sb *sbp) { return sbp->sb_bad_features2 != sbp->sb_features2; } static inline bool xfs_sb_version_hasattr(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT); } static inline void xfs_sb_version_addattr(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; } static inline bool xfs_sb_version_hasquota(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT); } static inline void xfs_sb_version_addquota(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT; } static inline bool xfs_sb_version_hasalign(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT)); } static inline bool xfs_sb_version_hasdalign(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT); } static inline bool xfs_sb_version_haslogv2(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT); } static inline bool xfs_sb_version_hassector(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT); } static inline bool xfs_sb_version_hasasciici(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT); } static inline bool xfs_sb_version_hasmorebits(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT); } /* * sb_features2 bit version macros. */ static inline bool xfs_sb_version_haslazysbcount(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT)); } static inline bool xfs_sb_version_hasattr2(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT)); } static inline void xfs_sb_version_addattr2(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT; } static inline void xfs_sb_version_removeattr2(struct xfs_sb *sbp) { sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT; if (!sbp->sb_features2) sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT; } static inline bool xfs_sb_version_hasprojid32bit(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT)); } static inline void xfs_sb_version_addprojid32bit(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; } /* * Extended v5 superblock feature masks. These are to be used for new v5 * superblock features only. * * Compat features are new features that old kernels will not notice or affect * and so can mount read-write without issues. * * RO-Compat (read only) are features that old kernels can read but will break * if they write. Hence only read-only mounts of such filesystems are allowed on * kernels that don't support the feature bit. * * InCompat features are features which old kernels will not understand and so * must not mount. * * Log-InCompat features are for changes to log formats or new transactions that * can't be replayed on older kernels. The fields are set when the filesystem is * mounted, and a clean unmount clears the fields. */ #define XFS_SB_FEAT_COMPAT_ALL 0 #define XFS_SB_FEAT_COMPAT_UNKNOWN ~XFS_SB_FEAT_COMPAT_ALL static inline bool xfs_sb_has_compat_feature( struct xfs_sb *sbp, uint32_t feature) { return (sbp->sb_features_compat & feature) != 0; } #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */ #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */ #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */ #define XFS_SB_FEAT_RO_COMPAT_ALL \ (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ XFS_SB_FEAT_RO_COMPAT_REFLINK) #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL static inline bool xfs_sb_has_ro_compat_feature( struct xfs_sb *sbp, uint32_t feature) { return (sbp->sb_features_ro_compat & feature) != 0; } #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ #define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ XFS_SB_FEAT_INCOMPAT_META_UUID) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool xfs_sb_has_incompat_feature( struct xfs_sb *sbp, uint32_t feature) { return (sbp->sb_features_incompat & feature) != 0; } #define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0 #define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL static inline bool xfs_sb_has_incompat_log_feature( struct xfs_sb *sbp, uint32_t feature) { return (sbp->sb_features_log_incompat & feature) != 0; } /* * V5 superblock specific feature checks */ static inline bool xfs_sb_version_hascrc(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; } static inline bool xfs_sb_version_has_pquotino(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; } static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_FTYPE)) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE)); } static inline bool xfs_sb_version_hasfinobt(xfs_sb_t *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT); } static inline bool xfs_sb_version_hassparseinodes(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_SPINODES); } /* * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID * is stored separately from the user-visible UUID; this allows the * user-visible UUID to be changed on V5 filesystems which have a * filesystem UUID stamped into every piece of metadata. */ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID); } static inline bool xfs_sb_version_hasrmapbt(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_RMAPBT); } static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK); } /* * end of superblock version macros */ static inline bool xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino) { return (ino == sbp->sb_uquotino || ino == sbp->sb_gquotino || ino == sbp->sb_pquotino); } #define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ #define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) #define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr)) #define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d)) #define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d)) #define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno)) /* * File system sector to basic block conversions. */ #define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log) /* * File system block to basic block conversions. */ #define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) #define XFS_BB_TO_FSB(mp,bb) \ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) #define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) /* * File system block to byte conversions. */ #define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog) #define XFS_B_TO_FSB(mp,b) \ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) #define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) #define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) /* * Allocation group header * * This is divided into three structures, placed in sequential 512-byte * buffers after a copy of the superblock (also in a 512-byte buffer). */ #define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */ #define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */ #define XFS_AGFL_MAGIC 0x5841464c /* 'XAFL' */ #define XFS_AGF_VERSION 1 #define XFS_AGI_VERSION 1 #define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION) #define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION) /* * Btree number 0 is bno, 1 is cnt, 2 is rmap. This value gives the size of the * arrays below. */ #define XFS_BTNUM_AGF ((int)XFS_BTNUM_RMAPi + 1) /* * The second word of agf_levels in the first a.g. overlaps the EFS * superblock's magic number. Since the magic numbers valid for EFS * are > 64k, our value cannot be confused for an EFS superblock's. */ typedef struct xfs_agf { /* * Common allocation group header information */ __be32 agf_magicnum; /* magic number == XFS_AGF_MAGIC */ __be32 agf_versionnum; /* header version == XFS_AGF_VERSION */ __be32 agf_seqno; /* sequence # starting from 0 */ __be32 agf_length; /* size in blocks of a.g. */ /* * Freespace and rmap information */ __be32 agf_roots[XFS_BTNUM_AGF]; /* root blocks */ __be32 agf_levels[XFS_BTNUM_AGF]; /* btree levels */ __be32 agf_flfirst; /* first freelist block's index */ __be32 agf_fllast; /* last freelist block's index */ __be32 agf_flcount; /* count of blocks in freelist */ __be32 agf_freeblks; /* total free blocks */ __be32 agf_longest; /* longest free space */ __be32 agf_btreeblks; /* # of blocks held in AGF btrees */ uuid_t agf_uuid; /* uuid of filesystem */ __be32 agf_rmap_blocks; /* rmapbt blocks used */ __be32 agf_refcount_blocks; /* refcountbt blocks used */ __be32 agf_refcount_root; /* refcount tree root block */ __be32 agf_refcount_level; /* refcount btree levels */ /* * reserve some contiguous space for future logged fields before we add * the unlogged fields. This makes the range logging via flags and * structure offsets much simpler. */ __be64 agf_spare64[14]; /* unlogged fields, written during buffer writeback. */ __be64 agf_lsn; /* last write sequence */ __be32 agf_crc; /* crc of agf sector */ __be32 agf_spare2; /* structure must be padded to 64 bit alignment */ } xfs_agf_t; #define XFS_AGF_CRC_OFF offsetof(struct xfs_agf, agf_crc) #define XFS_AGF_MAGICNUM 0x00000001 #define XFS_AGF_VERSIONNUM 0x00000002 #define XFS_AGF_SEQNO 0x00000004 #define XFS_AGF_LENGTH 0x00000008 #define XFS_AGF_ROOTS 0x00000010 #define XFS_AGF_LEVELS 0x00000020 #define XFS_AGF_FLFIRST 0x00000040 #define XFS_AGF_FLLAST 0x00000080 #define XFS_AGF_FLCOUNT 0x00000100 #define XFS_AGF_FREEBLKS 0x00000200 #define XFS_AGF_LONGEST 0x00000400 #define XFS_AGF_BTREEBLKS 0x00000800 #define XFS_AGF_UUID 0x00001000 #define XFS_AGF_RMAP_BLOCKS 0x00002000 #define XFS_AGF_REFCOUNT_BLOCKS 0x00004000 #define XFS_AGF_REFCOUNT_ROOT 0x00008000 #define XFS_AGF_REFCOUNT_LEVEL 0x00010000 #define XFS_AGF_SPARE64 0x00020000 #define XFS_AGF_NUM_BITS 18 #define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) #define XFS_AGF_FLAGS \ { XFS_AGF_MAGICNUM, "MAGICNUM" }, \ { XFS_AGF_VERSIONNUM, "VERSIONNUM" }, \ { XFS_AGF_SEQNO, "SEQNO" }, \ { XFS_AGF_LENGTH, "LENGTH" }, \ { XFS_AGF_ROOTS, "ROOTS" }, \ { XFS_AGF_LEVELS, "LEVELS" }, \ { XFS_AGF_FLFIRST, "FLFIRST" }, \ { XFS_AGF_FLLAST, "FLLAST" }, \ { XFS_AGF_FLCOUNT, "FLCOUNT" }, \ { XFS_AGF_FREEBLKS, "FREEBLKS" }, \ { XFS_AGF_LONGEST, "LONGEST" }, \ { XFS_AGF_BTREEBLKS, "BTREEBLKS" }, \ { XFS_AGF_UUID, "UUID" }, \ { XFS_AGF_RMAP_BLOCKS, "RMAP_BLOCKS" }, \ { XFS_AGF_REFCOUNT_BLOCKS, "REFCOUNT_BLOCKS" }, \ { XFS_AGF_REFCOUNT_ROOT, "REFCOUNT_ROOT" }, \ { XFS_AGF_REFCOUNT_LEVEL, "REFCOUNT_LEVEL" }, \ { XFS_AGF_SPARE64, "SPARE64" } /* disk block (xfs_daddr_t) in the AG */ #define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log)) #define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp)) #define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)((bp)->b_addr)) /* * Size of the unlinked inode hash table in the agi. */ #define XFS_AGI_UNLINKED_BUCKETS 64 typedef struct xfs_agi { /* * Common allocation group header information */ __be32 agi_magicnum; /* magic number == XFS_AGI_MAGIC */ __be32 agi_versionnum; /* header version == XFS_AGI_VERSION */ __be32 agi_seqno; /* sequence # starting from 0 */ __be32 agi_length; /* size in blocks of a.g. */ /* * Inode information * Inodes are mapped by interpreting the inode number, so no * mapping data is needed here. */ __be32 agi_count; /* count of allocated inodes */ __be32 agi_root; /* root of inode btree */ __be32 agi_level; /* levels in inode btree */ __be32 agi_freecount; /* number of free inodes */ __be32 agi_newino; /* new inode just allocated */ __be32 agi_dirino; /* last directory inode chunk */ /* * Hash table of inodes which have been unlinked but are * still being referenced. */ __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; /* * This marks the end of logging region 1 and start of logging region 2. */ uuid_t agi_uuid; /* uuid of filesystem */ __be32 agi_crc; /* crc of agi sector */ __be32 agi_pad32; __be64 agi_lsn; /* last write sequence */ __be32 agi_free_root; /* root of the free inode btree */ __be32 agi_free_level;/* levels in free inode btree */ /* structure must be padded to 64 bit alignment */ } xfs_agi_t; #define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc) #define XFS_AGI_MAGICNUM (1 << 0) #define XFS_AGI_VERSIONNUM (1 << 1) #define XFS_AGI_SEQNO (1 << 2) #define XFS_AGI_LENGTH (1 << 3) #define XFS_AGI_COUNT (1 << 4) #define XFS_AGI_ROOT (1 << 5) #define XFS_AGI_LEVEL (1 << 6) #define XFS_AGI_FREECOUNT (1 << 7) #define XFS_AGI_NEWINO (1 << 8) #define XFS_AGI_DIRINO (1 << 9) #define XFS_AGI_UNLINKED (1 << 10) #define XFS_AGI_NUM_BITS_R1 11 /* end of the 1st agi logging region */ #define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1) #define XFS_AGI_FREE_ROOT (1 << 11) #define XFS_AGI_FREE_LEVEL (1 << 12) #define XFS_AGI_NUM_BITS_R2 13 /* disk block (xfs_daddr_t) in the AG */ #define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log)) #define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp)) #define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)((bp)->b_addr)) /* * The third a.g. block contains the a.g. freelist, an array * of block pointers to blocks owned by the allocation btree code. */ #define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log)) #define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp)) #define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)((bp)->b_addr)) #define XFS_BUF_TO_AGFL_BNO(mp, bp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ &(XFS_BUF_TO_AGFL(bp)->agfl_bno[0]) : \ (__be32 *)(bp)->b_addr) typedef struct xfs_agfl { __be32 agfl_magicnum; __be32 agfl_seqno; uuid_t agfl_uuid; __be64 agfl_lsn; __be32 agfl_crc; __be32 agfl_bno[]; /* actually xfs_agfl_size(mp) */ } __attribute__((packed)) xfs_agfl_t; #define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc) #define XFS_AGB_TO_FSB(mp,agno,agbno) \ (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno)) #define XFS_FSB_TO_AGNO(mp,fsbno) \ ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog)) #define XFS_FSB_TO_AGBNO(mp,fsbno) \ ((xfs_agblock_t)((fsbno) & xfs_mask32lo((mp)->m_sb.sb_agblklog))) #define XFS_AGB_TO_DADDR(mp,agno,agbno) \ ((xfs_daddr_t)XFS_FSB_TO_BB(mp, \ (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno))) #define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d)) /* * For checking for bad ranges of xfs_daddr_t's, covering multiple * allocation groups or a single xfs_daddr_t that's a superblock copy. */ #define XFS_AG_CHECK_DADDR(mp,d,len) \ ((len) == 1 ? \ ASSERT((d) == XFS_SB_DADDR || \ xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \ ASSERT(xfs_daddr_to_agno(mp, d) == \ xfs_daddr_to_agno(mp, (d) + (len) - 1))) typedef struct xfs_timestamp { __be32 t_sec; /* timestamp seconds */ __be32 t_nsec; /* timestamp nanoseconds */ } xfs_timestamp_t; /* * On-disk inode structure. * * This is just the header or "dinode core", the inode is expanded to fill a * variable size the leftover area split into a data and an attribute fork. * The format of the data and attribute fork depends on the format of the * inode as indicated by di_format and di_aformat. To access the data and * attribute use the XFS_DFORK_DPTR, XFS_DFORK_APTR, and XFS_DFORK_PTR macros * below. * * There is a very similar struct icdinode in xfs_inode which matches the * layout of the first 96 bytes of this structure, but is kept in native * format instead of big endian. * * Note: di_flushiter is only used by v1/2 inodes - it's effectively a zeroed * padding field for v3 inodes. */ #define XFS_DINODE_MAGIC 0x494e /* 'IN' */ typedef struct xfs_dinode { __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ __be16 di_mode; /* mode and type of file */ __u8 di_version; /* inode version */ __u8 di_format; /* format of di_c data */ __be16 di_onlink; /* old number of links to file */ __be32 di_uid; /* owner's user id */ __be32 di_gid; /* owner's group id */ __be32 di_nlink; /* number of links to file */ __be16 di_projid_lo; /* lower part of owner's project id */ __be16 di_projid_hi; /* higher part owner's project id */ __u8 di_pad[6]; /* unused, zeroed space */ __be16 di_flushiter; /* incremented on flush */ xfs_timestamp_t di_atime; /* time last accessed */ xfs_timestamp_t di_mtime; /* time last modified */ xfs_timestamp_t di_ctime; /* time created/inode modified */ __be64 di_size; /* number of bytes in file */ __be64 di_nblocks; /* # of direct & btree blocks used */ __be32 di_extsize; /* basic/minimum extent size for file */ __be32 di_nextents; /* number of extents in data fork */ __be16 di_anextents; /* number of extents in attribute fork*/ __u8 di_forkoff; /* attr fork offs, <<3 for 64b align */ __s8 di_aformat; /* format of attr fork's data */ __be32 di_dmevmask; /* DMIG event mask */ __be16 di_dmstate; /* DMIG state info */ __be16 di_flags; /* random flags, XFS_DIFLAG_... */ __be32 di_gen; /* generation number */ /* di_next_unlinked is the only non-core field in the old dinode */ __be32 di_next_unlinked;/* agi unlinked list ptr */ /* start of the extended dinode, writable fields */ __le32 di_crc; /* CRC of the inode */ __be64 di_changecount; /* number of attribute changes */ __be64 di_lsn; /* flush sequence */ __be64 di_flags2; /* more random flags */ __be32 di_cowextsize; /* basic cow extent size for file */ __u8 di_pad2[12]; /* more padding for future expansion */ /* fields only written to during inode creation */ xfs_timestamp_t di_crtime; /* time created */ __be64 di_ino; /* inode number */ uuid_t di_uuid; /* UUID of the filesystem */ /* structure must be padded to 64 bit alignment */ } xfs_dinode_t; #define XFS_DINODE_CRC_OFF offsetof(struct xfs_dinode, di_crc) #define DI_MAX_FLUSH 0xffff /* * Size of the core inode on disk. Version 1 and 2 inodes have * the same size, but version 3 has grown a few additional fields. */ static inline uint xfs_dinode_size(int version) { if (version == 3) return sizeof(struct xfs_dinode); return offsetof(struct xfs_dinode, di_crc); } /* * The 32 bit link count in the inode theoretically maxes out at UINT_MAX. * Since the pathconf interface is signed, we use 2^31 - 1 instead. */ #define XFS_MAXLINK ((1U << 31) - 1U) /* * Values for di_format * * This enum is used in string mapping in xfs_trace.h; please keep the * TRACE_DEFINE_ENUMs for it up to date. */ typedef enum xfs_dinode_fmt { XFS_DINODE_FMT_DEV, /* xfs_dev_t */ XFS_DINODE_FMT_LOCAL, /* bulk data */ XFS_DINODE_FMT_EXTENTS, /* struct xfs_bmbt_rec */ XFS_DINODE_FMT_BTREE, /* struct xfs_bmdr_block */ XFS_DINODE_FMT_UUID /* added long ago, but never used */ } xfs_dinode_fmt_t; #define XFS_INODE_FORMAT_STR \ { XFS_DINODE_FMT_DEV, "dev" }, \ { XFS_DINODE_FMT_LOCAL, "local" }, \ { XFS_DINODE_FMT_EXTENTS, "extent" }, \ { XFS_DINODE_FMT_BTREE, "btree" }, \ { XFS_DINODE_FMT_UUID, "uuid" } /* * Inode minimum and maximum sizes. */ #define XFS_DINODE_MIN_LOG 8 #define XFS_DINODE_MAX_LOG 11 #define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) #define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) /* * Inode size for given fs. */ #define XFS_LITINO(mp, version) \ ((int)(((mp)->m_sb.sb_inodesize) - xfs_dinode_size(version))) /* * Inode data & attribute fork sizes, per inode. */ #define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0) #define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3)) #define XFS_DFORK_DSIZE(dip,mp) \ (XFS_DFORK_Q(dip) ? \ XFS_DFORK_BOFF(dip) : \ XFS_LITINO(mp, (dip)->di_version)) #define XFS_DFORK_ASIZE(dip,mp) \ (XFS_DFORK_Q(dip) ? \ XFS_LITINO(mp, (dip)->di_version) - XFS_DFORK_BOFF(dip) : \ 0) #define XFS_DFORK_SIZE(dip,mp,w) \ ((w) == XFS_DATA_FORK ? \ XFS_DFORK_DSIZE(dip, mp) : \ XFS_DFORK_ASIZE(dip, mp)) #define XFS_DFORK_MAXEXT(dip, mp, w) \ (XFS_DFORK_SIZE(dip, mp, w) / sizeof(struct xfs_bmbt_rec)) /* * Return pointers to the data or attribute forks. */ #define XFS_DFORK_DPTR(dip) \ ((char *)dip + xfs_dinode_size(dip->di_version)) #define XFS_DFORK_APTR(dip) \ (XFS_DFORK_DPTR(dip) + XFS_DFORK_BOFF(dip)) #define XFS_DFORK_PTR(dip,w) \ ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip)) #define XFS_DFORK_FORMAT(dip,w) \ ((w) == XFS_DATA_FORK ? \ (dip)->di_format : \ (dip)->di_aformat) #define XFS_DFORK_NEXTENTS(dip,w) \ ((w) == XFS_DATA_FORK ? \ be32_to_cpu((dip)->di_nextents) : \ be16_to_cpu((dip)->di_anextents)) /* * For block and character special files the 32bit dev_t is stored at the * beginning of the data fork. */ static inline xfs_dev_t xfs_dinode_get_rdev(struct xfs_dinode *dip) { return be32_to_cpu(*(__be32 *)XFS_DFORK_DPTR(dip)); } static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) { *(__be32 *)XFS_DFORK_DPTR(dip) = cpu_to_be32(rdev); } /* * Values for di_flags */ #define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ #define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ #define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ #define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */ #define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */ #define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */ #define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */ #define XFS_DIFLAG_NODUMP_BIT 7 /* do not dump */ #define XFS_DIFLAG_RTINHERIT_BIT 8 /* create with realtime bit set */ #define XFS_DIFLAG_PROJINHERIT_BIT 9 /* create with parents projid */ #define XFS_DIFLAG_NOSYMLINKS_BIT 10 /* disallow symlink creation */ #define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */ #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ #define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */ #define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */ /* Do not use bit 15, di_flags is legacy and unchanging now */ #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) #define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT) #define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT) #define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) #define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) #define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) #define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT) #define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT) #define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) #define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) #define XFS_DIFLAG_ANY \ (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) /* * Values for di_flags2 These start by being exposed to userspace in the upper * 16 bits of the XFS_XFLAG_s range. */ #define XFS_DIFLAG2_DAX_BIT 0 /* use DAX for this inode */ #define XFS_DIFLAG2_REFLINK_BIT 1 /* file's blocks may be shared */ #define XFS_DIFLAG2_COWEXTSIZE_BIT 2 /* copy on write extent size hint */ #define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT) #define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT) #define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT) #define XFS_DIFLAG2_ANY \ (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE) /* * Inode number format: * low inopblog bits - offset in block * next agblklog bits - block number in ag * next agno_log bits - ag number * high agno_log-agblklog-inopblog bits - 0 */ #define XFS_INO_MASK(k) (uint32_t)((1ULL << (k)) - 1) #define XFS_INO_OFFSET_BITS(mp) (mp)->m_sb.sb_inopblog #define XFS_INO_AGBNO_BITS(mp) (mp)->m_sb.sb_agblklog #define XFS_INO_AGINO_BITS(mp) ((mp)->m_ino_geo.agino_log) #define XFS_INO_AGNO_BITS(mp) (mp)->m_agno_log #define XFS_INO_BITS(mp) \ XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp) #define XFS_INO_TO_AGNO(mp,i) \ ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) #define XFS_INO_TO_AGINO(mp,i) \ ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) #define XFS_INO_TO_AGBNO(mp,i) \ (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) #define XFS_INO_TO_OFFSET(mp,i) \ ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) #define XFS_INO_TO_FSB(mp,i) \ XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) #define XFS_AGINO_TO_INO(mp,a,i) \ (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) #define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) #define XFS_AGINO_TO_OFFSET(mp,i) \ ((i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) #define XFS_OFFBNO_TO_AGINO(mp,b,o) \ ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) #define XFS_FSB_TO_INO(mp, b) ((xfs_ino_t)((b) << XFS_INO_OFFSET_BITS(mp))) #define XFS_AGB_TO_AGINO(mp, b) ((xfs_agino_t)((b) << XFS_INO_OFFSET_BITS(mp))) #define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) #define XFS_MAXINUMBER_32 ((xfs_ino_t)((1ULL << 32) - 1ULL)) /* * RealTime Device format definitions */ /* Min and max rt extent sizes, specified in bytes */ #define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ #define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64kB */ #define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4kB */ #define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize) #define XFS_BLOCKMASK(mp) ((mp)->m_blockmask) #define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize) #define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask) /* * RT Summary and bit manipulation macros. */ #define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb))) #define XFS_SUMOFFSTOBLOCK(mp,s) \ (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog) #define XFS_SUMPTR(mp,bp,so) \ ((xfs_suminfo_t *)((bp)->b_addr + \ (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp)))) #define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log) #define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log) #define XFS_BITTOWORD(mp,bi) \ ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp))) #define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b)) #define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b)) #define XFS_RTLOBIT(w) xfs_lowbit32(w) #define XFS_RTHIBIT(w) xfs_highbit32(w) #define XFS_RTBLOCKLOG(b) xfs_highbit64(b) /* * Dquot and dquot block format definitions */ #define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ #define XFS_DQUOT_VERSION (uint8_t)0x01 /* latest version number */ /* * This is the main portion of the on-disk representation of quota * information for a user. This is the q_core of the xfs_dquot_t that * is kept in kernel memory. We pad this with some more expansion room * to construct the on disk structure. */ typedef struct xfs_disk_dquot { __be16 d_magic; /* dquot magic = XFS_DQUOT_MAGIC */ __u8 d_version; /* dquot version */ __u8 d_flags; /* XFS_DQ_USER/PROJ/GROUP */ __be32 d_id; /* user,project,group id */ __be64 d_blk_hardlimit;/* absolute limit on disk blks */ __be64 d_blk_softlimit;/* preferred limit on disk blks */ __be64 d_ino_hardlimit;/* maximum # allocated inodes */ __be64 d_ino_softlimit;/* preferred inode limit */ __be64 d_bcount; /* disk blocks owned by the user */ __be64 d_icount; /* inodes owned by the user */ __be32 d_itimer; /* zero if within inode limits if not, this is when we refuse service */ __be32 d_btimer; /* similar to above; for disk blocks */ __be16 d_iwarns; /* warnings issued wrt num inodes */ __be16 d_bwarns; /* warnings issued wrt disk blocks */ __be32 d_pad0; /* 64 bit align */ __be64 d_rtb_hardlimit;/* absolute limit on realtime blks */ __be64 d_rtb_softlimit;/* preferred limit on RT disk blks */ __be64 d_rtbcount; /* realtime blocks owned */ __be32 d_rtbtimer; /* similar to above; for RT disk blocks */ __be16 d_rtbwarns; /* warnings issued wrt RT disk blocks */ __be16 d_pad; } xfs_disk_dquot_t; /* * This is what goes on disk. This is separated from the xfs_disk_dquot because * carrying the unnecessary padding would be a waste of memory. */ typedef struct xfs_dqblk { xfs_disk_dquot_t dd_diskdq; /* portion that lives incore as well */ char dd_fill[4]; /* filling for posterity */ /* * These two are only present on filesystems with the CRC bits set. */ __be32 dd_crc; /* checksum */ __be64 dd_lsn; /* last modification in log */ uuid_t dd_uuid; /* location information */ } xfs_dqblk_t; #define XFS_DQUOT_CRC_OFF offsetof(struct xfs_dqblk, dd_crc) /* * Remote symlink format and access functions. */ #define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */ struct xfs_dsymlink_hdr { __be32 sl_magic; __be32 sl_offset; __be32 sl_bytes; __be32 sl_crc; uuid_t sl_uuid; __be64 sl_owner; __be64 sl_blkno; __be64 sl_lsn; }; #define XFS_SYMLINK_CRC_OFF offsetof(struct xfs_dsymlink_hdr, sl_crc) #define XFS_SYMLINK_MAXLEN 1024 /* * The maximum pathlen is 1024 bytes. Since the minimum file system * blocksize is 512 bytes, we can get a max of 3 extents back from * bmapi when crc headers are taken into account. */ #define XFS_SYMLINK_MAPS 3 #define XFS_SYMLINK_BUF_SPACE(mp, bufsize) \ ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ sizeof(struct xfs_dsymlink_hdr) : 0)) /* * Allocation Btree format definitions * * There are two on-disk btrees, one sorted by blockno and one sorted * by blockcount and blockno. All blocks look the same to make the code * simpler; if we have time later, we'll make the optimizations. */ #define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ #define XFS_ABTB_CRC_MAGIC 0x41423342 /* 'AB3B' */ #define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ #define XFS_ABTC_CRC_MAGIC 0x41423343 /* 'AB3C' */ /* * Data record/key structure */ typedef struct xfs_alloc_rec { __be32 ar_startblock; /* starting block number */ __be32 ar_blockcount; /* count of free blocks */ } xfs_alloc_rec_t, xfs_alloc_key_t; typedef struct xfs_alloc_rec_incore { xfs_agblock_t ar_startblock; /* starting block number */ xfs_extlen_t ar_blockcount; /* count of free blocks */ } xfs_alloc_rec_incore_t; /* btree pointer type */ typedef __be32 xfs_alloc_ptr_t; /* * Block numbers in the AG: * SB is sector 0, AGF is sector 1, AGI is sector 2, AGFL is sector 3. */ #define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1)) #define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1)) /* * Inode Allocation Btree format definitions * * There is a btree for the inode map per allocation group. */ #define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ #define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */ #define XFS_FIBT_MAGIC 0x46494254 /* 'FIBT' */ #define XFS_FIBT_CRC_MAGIC 0x46494233 /* 'FIB3' */ typedef uint64_t xfs_inofree_t; #define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) #define XFS_INODES_PER_CHUNK_LOG (XFS_NBBYLOG + 3) #define XFS_INOBT_ALL_FREE ((xfs_inofree_t)-1) #define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) #define XFS_INOBT_HOLEMASK_FULL 0 /* holemask for full chunk */ #define XFS_INOBT_HOLEMASK_BITS (NBBY * sizeof(uint16_t)) #define XFS_INODES_PER_HOLEMASK_BIT \ (XFS_INODES_PER_CHUNK / (NBBY * sizeof(uint16_t))) static inline xfs_inofree_t xfs_inobt_maskn(int i, int n) { return ((n >= XFS_INODES_PER_CHUNK ? 0 : XFS_INOBT_MASK(n)) - 1) << i; } /* * The on-disk inode record structure has two formats. The original "full" * format uses a 4-byte freecount. The "sparse" format uses a 1-byte freecount * and replaces the 3 high-order freecount bytes wth the holemask and inode * count. * * The holemask of the sparse record format allows an inode chunk to have holes * that refer to blocks not owned by the inode record. This facilitates inode * allocation in the event of severe free space fragmentation. */ typedef struct xfs_inobt_rec { __be32 ir_startino; /* starting inode number */ union { struct { __be32 ir_freecount; /* count of free inodes */ } f; struct { __be16 ir_holemask;/* hole mask for sparse chunks */ __u8 ir_count; /* total inode count */ __u8 ir_freecount; /* count of free inodes */ } sp; } ir_u; __be64 ir_free; /* free inode mask */ } xfs_inobt_rec_t; typedef struct xfs_inobt_rec_incore { xfs_agino_t ir_startino; /* starting inode number */ uint16_t ir_holemask; /* hole mask for sparse chunks */ uint8_t ir_count; /* total inode count */ uint8_t ir_freecount; /* count of free inodes (set bits) */ xfs_inofree_t ir_free; /* free inode mask */ } xfs_inobt_rec_incore_t; static inline bool xfs_inobt_issparse(uint16_t holemask) { /* non-zero holemask represents a sparse rec. */ return holemask; } /* * Key structure */ typedef struct xfs_inobt_key { __be32 ir_startino; /* starting inode number */ } xfs_inobt_key_t; /* btree pointer type */ typedef __be32 xfs_inobt_ptr_t; /* * block numbers in the AG. */ #define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) #define XFS_FIBT_BLOCK(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) /* * Reverse mapping btree format definitions * * There is a btree for the reverse map per allocation group */ #define XFS_RMAP_CRC_MAGIC 0x524d4233 /* 'RMB3' */ /* * Ownership info for an extent. This is used to create reverse-mapping * entries. */ #define XFS_OWNER_INFO_ATTR_FORK (1 << 0) #define XFS_OWNER_INFO_BMBT_BLOCK (1 << 1) struct xfs_owner_info { uint64_t oi_owner; xfs_fileoff_t oi_offset; unsigned int oi_flags; }; /* * Special owner types. * * Seeing as we only support up to 8EB, we have the upper bit of the owner field * to tell us we have a special owner value. We use these for static metadata * allocated at mkfs/growfs time, as well as for freespace management metadata. */ #define XFS_RMAP_OWN_NULL (-1ULL) /* No owner, for growfs */ #define XFS_RMAP_OWN_UNKNOWN (-2ULL) /* Unknown owner, for EFI recovery */ #define XFS_RMAP_OWN_FS (-3ULL) /* static fs metadata */ #define XFS_RMAP_OWN_LOG (-4ULL) /* static fs metadata */ #define XFS_RMAP_OWN_AG (-5ULL) /* AG freespace btree blocks */ #define XFS_RMAP_OWN_INOBT (-6ULL) /* Inode btree blocks */ #define XFS_RMAP_OWN_INODES (-7ULL) /* Inode chunk */ #define XFS_RMAP_OWN_REFC (-8ULL) /* refcount tree */ #define XFS_RMAP_OWN_COW (-9ULL) /* cow allocations */ #define XFS_RMAP_OWN_MIN (-10ULL) /* guard */ #define XFS_RMAP_NON_INODE_OWNER(owner) (!!((owner) & (1ULL << 63))) /* * Data record structure */ struct xfs_rmap_rec { __be32 rm_startblock; /* extent start block */ __be32 rm_blockcount; /* extent length */ __be64 rm_owner; /* extent owner */ __be64 rm_offset; /* offset within the owner */ }; /* * rmap btree record * rm_offset:63 is the attribute fork flag * rm_offset:62 is the bmbt block flag * rm_offset:61 is the unwritten extent flag (same as l0:63 in bmbt) * rm_offset:54-60 aren't used and should be zero * rm_offset:0-53 is the block offset within the inode */ #define XFS_RMAP_OFF_ATTR_FORK ((uint64_t)1ULL << 63) #define XFS_RMAP_OFF_BMBT_BLOCK ((uint64_t)1ULL << 62) #define XFS_RMAP_OFF_UNWRITTEN ((uint64_t)1ULL << 61) #define XFS_RMAP_LEN_MAX ((uint32_t)~0U) #define XFS_RMAP_OFF_FLAGS (XFS_RMAP_OFF_ATTR_FORK | \ XFS_RMAP_OFF_BMBT_BLOCK | \ XFS_RMAP_OFF_UNWRITTEN) #define XFS_RMAP_OFF_MASK ((uint64_t)0x3FFFFFFFFFFFFFULL) #define XFS_RMAP_OFF(off) ((off) & XFS_RMAP_OFF_MASK) #define XFS_RMAP_IS_BMBT_BLOCK(off) (!!((off) & XFS_RMAP_OFF_BMBT_BLOCK)) #define XFS_RMAP_IS_ATTR_FORK(off) (!!((off) & XFS_RMAP_OFF_ATTR_FORK)) #define XFS_RMAP_IS_UNWRITTEN(len) (!!((off) & XFS_RMAP_OFF_UNWRITTEN)) #define RMAPBT_STARTBLOCK_BITLEN 32 #define RMAPBT_BLOCKCOUNT_BITLEN 32 #define RMAPBT_OWNER_BITLEN 64 #define RMAPBT_ATTRFLAG_BITLEN 1 #define RMAPBT_BMBTFLAG_BITLEN 1 #define RMAPBT_EXNTFLAG_BITLEN 1 #define RMAPBT_UNUSED_OFFSET_BITLEN 7 #define RMAPBT_OFFSET_BITLEN 54 #define XFS_RMAP_ATTR_FORK (1 << 0) #define XFS_RMAP_BMBT_BLOCK (1 << 1) #define XFS_RMAP_UNWRITTEN (1 << 2) #define XFS_RMAP_KEY_FLAGS (XFS_RMAP_ATTR_FORK | \ XFS_RMAP_BMBT_BLOCK) #define XFS_RMAP_REC_FLAGS (XFS_RMAP_UNWRITTEN) struct xfs_rmap_irec { xfs_agblock_t rm_startblock; /* extent start block */ xfs_extlen_t rm_blockcount; /* extent length */ uint64_t rm_owner; /* extent owner */ uint64_t rm_offset; /* offset within the owner */ unsigned int rm_flags; /* state flags */ }; /* * Key structure * * We don't use the length for lookups */ struct xfs_rmap_key { __be32 rm_startblock; /* extent start block */ __be64 rm_owner; /* extent owner */ __be64 rm_offset; /* offset within the owner */ } __attribute__((packed)); /* btree pointer type */ typedef __be32 xfs_rmap_ptr_t; #define XFS_RMAP_BLOCK(mp) \ (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \ XFS_FIBT_BLOCK(mp) + 1 : \ XFS_IBT_BLOCK(mp) + 1) /* * Reference Count Btree format definitions * */ #define XFS_REFC_CRC_MAGIC 0x52334643 /* 'R3FC' */ unsigned int xfs_refc_block(struct xfs_mount *mp); /* * Data record/key structure * * Each record associates a range of physical blocks (starting at * rc_startblock and ending rc_blockcount blocks later) with a reference * count (rc_refcount). Extents that are being used to stage a copy on * write (CoW) operation are recorded in the refcount btree with a * refcount of 1. All other records must have a refcount > 1 and must * track an extent mapped only by file data forks. * * Extents with a single owner (attributes, metadata, non-shared file * data) are not tracked here. Free space is also not tracked here. * This is consistent with pre-reflink XFS. */ /* * Extents that are being used to stage a copy on write are stored * in the refcount btree with a refcount of 1 and the upper bit set * on the startblock. This speeds up mount time deletion of stale * staging extents because they're all at the right side of the tree. */ #define XFS_REFC_COW_START ((xfs_agblock_t)(1U << 31)) #define REFCNTBT_COWFLAG_BITLEN 1 #define REFCNTBT_AGBLOCK_BITLEN 31 struct xfs_refcount_rec { __be32 rc_startblock; /* starting block number */ __be32 rc_blockcount; /* count of blocks */ __be32 rc_refcount; /* number of inodes linked here */ }; struct xfs_refcount_key { __be32 rc_startblock; /* starting block number */ }; struct xfs_refcount_irec { xfs_agblock_t rc_startblock; /* starting block number */ xfs_extlen_t rc_blockcount; /* count of free blocks */ xfs_nlink_t rc_refcount; /* number of inodes linked here */ }; #define MAXREFCOUNT ((xfs_nlink_t)~0U) #define MAXREFCEXTLEN ((xfs_extlen_t)~0U) /* btree pointer type */ typedef __be32 xfs_refcount_ptr_t; /* * BMAP Btree format definitions * * This includes both the root block definition that sits inside an inode fork * and the record/pointer formats for the leaf/node in the blocks. */ #define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ #define XFS_BMAP_CRC_MAGIC 0x424d4133 /* 'BMA3' */ /* * Bmap root header, on-disk form only. */ typedef struct xfs_bmdr_block { __be16 bb_level; /* 0 is a leaf */ __be16 bb_numrecs; /* current # of data records */ } xfs_bmdr_block_t; /* * Bmap btree record and extent descriptor. * l0:63 is an extent flag (value 1 indicates non-normal). * l0:9-62 are startoff. * l0:0-8 and l1:21-63 are startblock. * l1:0-20 are blockcount. */ #define BMBT_EXNTFLAG_BITLEN 1 #define BMBT_STARTOFF_BITLEN 54 #define BMBT_STARTBLOCK_BITLEN 52 #define BMBT_BLOCKCOUNT_BITLEN 21 #define BMBT_STARTOFF_MASK ((1ULL << BMBT_STARTOFF_BITLEN) - 1) typedef struct xfs_bmbt_rec { __be64 l0, l1; } xfs_bmbt_rec_t; typedef uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ typedef xfs_bmbt_rec_t xfs_bmdr_rec_t; /* * Values and macros for delayed-allocation startblock fields. */ #define STARTBLOCKVALBITS 17 #define STARTBLOCKMASKBITS (15 + 20) #define STARTBLOCKMASK \ (((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) static inline int isnullstartblock(xfs_fsblock_t x) { return ((x) & STARTBLOCKMASK) == STARTBLOCKMASK; } static inline xfs_fsblock_t nullstartblock(int k) { ASSERT(k < (1 << STARTBLOCKVALBITS)); return STARTBLOCKMASK | (k); } static inline xfs_filblks_t startblockval(xfs_fsblock_t x) { return (xfs_filblks_t)((x) & ~STARTBLOCKMASK); } /* * Key structure for non-leaf levels of the tree. */ typedef struct xfs_bmbt_key { __be64 br_startoff; /* starting file offset */ } xfs_bmbt_key_t, xfs_bmdr_key_t; /* btree pointer type */ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* * Generic Btree block format definitions * * This is a combination of the actual format used on disk for short and long * format btrees. The first three fields are shared by both format, but the * pointers are different and should be used with care. * * To get the size of the actual short or long form headers please use the size * macros below. Never use sizeof(xfs_btree_block). * * The blkno, crc, lsn, owner and uuid fields are only available in filesystems * with the crc feature bit, and all accesses to them must be conditional on * that flag. */ /* short form block header */ struct xfs_btree_block_shdr { __be32 bb_leftsib; __be32 bb_rightsib; __be64 bb_blkno; __be64 bb_lsn; uuid_t bb_uuid; __be32 bb_owner; __le32 bb_crc; }; /* long form block header */ struct xfs_btree_block_lhdr { __be64 bb_leftsib; __be64 bb_rightsib; __be64 bb_blkno; __be64 bb_lsn; uuid_t bb_uuid; __be64 bb_owner; __le32 bb_crc; __be32 bb_pad; /* padding for alignment */ }; struct xfs_btree_block { __be32 bb_magic; /* magic number for block type */ __be16 bb_level; /* 0 is a leaf */ __be16 bb_numrecs; /* current # of data records */ union { struct xfs_btree_block_shdr s; struct xfs_btree_block_lhdr l; } bb_u; /* rest */ }; /* size of a short form block */ #define XFS_BTREE_SBLOCK_LEN \ (offsetof(struct xfs_btree_block, bb_u) + \ offsetof(struct xfs_btree_block_shdr, bb_blkno)) /* size of a long form block */ #define XFS_BTREE_LBLOCK_LEN \ (offsetof(struct xfs_btree_block, bb_u) + \ offsetof(struct xfs_btree_block_lhdr, bb_blkno)) /* sizes of CRC enabled btree blocks */ #define XFS_BTREE_SBLOCK_CRC_LEN \ (offsetof(struct xfs_btree_block, bb_u) + \ sizeof(struct xfs_btree_block_shdr)) #define XFS_BTREE_LBLOCK_CRC_LEN \ (offsetof(struct xfs_btree_block, bb_u) + \ sizeof(struct xfs_btree_block_lhdr)) #define XFS_BTREE_SBLOCK_CRC_OFF \ offsetof(struct xfs_btree_block, bb_u.s.bb_crc) #define XFS_BTREE_LBLOCK_CRC_OFF \ offsetof(struct xfs_btree_block, bb_u.l.bb_crc) /* * On-disk XFS access control list structure. */ struct xfs_acl_entry { __be32 ae_tag; __be32 ae_id; __be16 ae_perm; __be16 ae_pad; /* fill the implicit hole in the structure */ }; struct xfs_acl { __be32 acl_cnt; struct xfs_acl_entry acl_entry[0]; }; /* * The number of ACL entries allowed is defined by the on-disk format. * For v4 superblocks, that is limited to 25 entries. For v5 superblocks, it is * limited only by the maximum size of the xattr that stores the information. */ #define XFS_ACL_MAX_ENTRIES(mp) \ (xfs_sb_version_hascrc(&mp->m_sb) \ ? (XFS_XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \ sizeof(struct xfs_acl_entry) \ : 25) #define XFS_ACL_SIZE(cnt) \ (sizeof(struct xfs_acl) + \ sizeof(struct xfs_acl_entry) * cnt) #define XFS_ACL_MAX_SIZE(mp) \ XFS_ACL_SIZE(XFS_ACL_MAX_ENTRIES((mp))) /* On-disk XFS extended attribute names */ #define SGI_ACL_FILE "SGI_ACL_FILE" #define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) #endif /* __XFS_FORMAT_H__ */ xfsprogs-5.3.0/libxfs/xfs_fs.h0000644000175000017500000010104513570057155016205 0ustar nathansnathans// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 1995-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_FS_H__ #define __XFS_FS_H__ /* * SGI's XFS filesystem's major stuff (constants, structures) */ /* * Direct I/O attribute record used with XFS_IOC_DIOINFO * d_miniosz is the min xfer size, xfer size multiple and file seek offset * alignment. */ #ifndef HAVE_DIOATTR struct dioattr { __u32 d_mem; /* data buffer memory alignment */ __u32 d_miniosz; /* min xfer size */ __u32 d_maxiosz; /* max xfer size */ }; #endif /* * Flags for the bs_xflags/fsx_xflags field in XFS_IOC_FS[GS]ETXATTR[A] * These are for backwards compatibility only. New code should * use the kernel [4.5 onwards] defined FS_XFLAG_* definitions directly. */ #define XFS_XFLAG_REALTIME FS_XFLAG_REALTIME #define XFS_XFLAG_PREALLOC FS_XFLAG_PREALLOC #define XFS_XFLAG_IMMUTABLE FS_XFLAG_IMMUTABLE #define XFS_XFLAG_APPEND FS_XFLAG_APPEND #define XFS_XFLAG_SYNC FS_XFLAG_SYNC #define XFS_XFLAG_NOATIME FS_XFLAG_NOATIME #define XFS_XFLAG_NODUMP FS_XFLAG_NODUMP #define XFS_XFLAG_RTINHERIT FS_XFLAG_RTINHERIT #define XFS_XFLAG_PROJINHERIT FS_XFLAG_PROJINHERIT #define XFS_XFLAG_NOSYMLINKS FS_XFLAG_NOSYMLINKS #define XFS_XFLAG_EXTSIZE FS_XFLAG_EXTSIZE #define XFS_XFLAG_EXTSZINHERIT FS_XFLAG_EXTSZINHERIT #define XFS_XFLAG_NODEFRAG FS_XFLAG_NODEFRAG #define XFS_XFLAG_FILESTREAM FS_XFLAG_FILESTREAM #define XFS_XFLAG_HASATTR FS_XFLAG_HASATTR /* * Structure for XFS_IOC_GETBMAP. * On input, fill in bmv_offset and bmv_length of the first structure * to indicate the area of interest in the file, and bmv_entries with * the number of array elements given back. The first structure is * updated on return to give the offset and length for the next call. */ #ifndef HAVE_GETBMAP struct getbmap { __s64 bmv_offset; /* file offset of segment in blocks */ __s64 bmv_block; /* starting block (64-bit daddr_t) */ __s64 bmv_length; /* length of segment, blocks */ __s32 bmv_count; /* # of entries in array incl. 1st */ __s32 bmv_entries; /* # of entries filled in (output) */ }; #endif /* * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries * are used exactly as in the getbmap structure. The getbmapx structure * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field * is only used for the first structure. It contains input flags * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled * in by the XFS_IOC_GETBMAPX command for each returned structure after * the first. */ #ifndef HAVE_GETBMAPX struct getbmapx { __s64 bmv_offset; /* file offset of segment in blocks */ __s64 bmv_block; /* starting block (64-bit daddr_t) */ __s64 bmv_length; /* length of segment, blocks */ __s32 bmv_count; /* # of entries in array incl. 1st */ __s32 bmv_entries; /* # of entries filled in (output). */ __s32 bmv_iflags; /* input flags (1st structure) */ __s32 bmv_oflags; /* output flags (after 1st structure)*/ __s32 bmv_unused1; /* future use */ __s32 bmv_unused2; /* future use */ }; #endif /* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ #define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ #define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ #define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ #define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ #define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ #define BMV_IF_COWFORK 0x20 /* return CoW fork rather than data */ #define BMV_IF_VALID \ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ BMV_IF_DELALLOC|BMV_IF_NO_HOLES|BMV_IF_COWFORK) /* bmv_oflags values - returned for each non-header segment */ #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ #define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ #define BMV_OF_LAST 0x4 /* segment is the last in the file */ #define BMV_OF_SHARED 0x8 /* segment shared with another file */ /* fmr_owner special values for FS_IOC_GETFSMAP */ #define XFS_FMR_OWN_FREE FMR_OWN_FREE /* free space */ #define XFS_FMR_OWN_UNKNOWN FMR_OWN_UNKNOWN /* unknown owner */ #define XFS_FMR_OWN_FS FMR_OWNER('X', 1) /* static fs metadata */ #define XFS_FMR_OWN_LOG FMR_OWNER('X', 2) /* journalling log */ #define XFS_FMR_OWN_AG FMR_OWNER('X', 3) /* per-AG metadata */ #define XFS_FMR_OWN_INOBT FMR_OWNER('X', 4) /* inode btree blocks */ #define XFS_FMR_OWN_INODES FMR_OWNER('X', 5) /* inodes */ #define XFS_FMR_OWN_REFC FMR_OWNER('X', 6) /* refcount tree */ #define XFS_FMR_OWN_COW FMR_OWNER('X', 7) /* cow staging */ #define XFS_FMR_OWN_DEFECTIVE FMR_OWNER('X', 8) /* bad blocks */ /* * Structure for XFS_IOC_FSSETDM. * For use by backup and restore programs to set the XFS on-disk inode * fields di_dmevmask and di_dmstate. These must be set to exactly and * only values previously obtained via xfs_bulkstat! (Specifically the * struct xfs_bstat fields bs_dmevmask and bs_dmstate.) */ #ifndef HAVE_FSDMIDATA struct fsdmidata { __u32 fsd_dmevmask; /* corresponds to di_dmevmask */ __u16 fsd_padding; __u16 fsd_dmstate; /* corresponds to di_dmstate */ }; #endif /* * File segment locking set data type for 64 bit access. * Also used for all the RESV/FREE interfaces. */ typedef struct xfs_flock64 { __s16 l_type; __s16 l_whence; __s64 l_start; __s64 l_len; /* len == 0 means until end of file */ __s32 l_sysid; __u32 l_pid; __s32 l_pad[4]; /* reserve area */ } xfs_flock64_t; /* * Output for XFS_IOC_FSGEOMETRY_V1 */ struct xfs_fsop_geom_v1 { __u32 blocksize; /* filesystem (data) block size */ __u32 rtextsize; /* realtime extent size */ __u32 agblocks; /* fsblocks in an AG */ __u32 agcount; /* number of allocation groups */ __u32 logblocks; /* fsblocks in the log */ __u32 sectsize; /* (data) sector size, bytes */ __u32 inodesize; /* inode size in bytes */ __u32 imaxpct; /* max allowed inode space(%) */ __u64 datablocks; /* fsblocks in data subvolume */ __u64 rtblocks; /* fsblocks in realtime subvol */ __u64 rtextents; /* rt extents in realtime subvol*/ __u64 logstart; /* starting fsblock of the log */ unsigned char uuid[16]; /* unique id of the filesystem */ __u32 sunit; /* stripe unit, fsblocks */ __u32 swidth; /* stripe width, fsblocks */ __s32 version; /* structure version */ __u32 flags; /* superblock version flags */ __u32 logsectsize; /* log sector size, bytes */ __u32 rtsectsize; /* realtime sector size, bytes */ __u32 dirblocksize; /* directory block size, bytes */ }; /* * Output for XFS_IOC_FSGEOMETRY_V4 */ struct xfs_fsop_geom_v4 { __u32 blocksize; /* filesystem (data) block size */ __u32 rtextsize; /* realtime extent size */ __u32 agblocks; /* fsblocks in an AG */ __u32 agcount; /* number of allocation groups */ __u32 logblocks; /* fsblocks in the log */ __u32 sectsize; /* (data) sector size, bytes */ __u32 inodesize; /* inode size in bytes */ __u32 imaxpct; /* max allowed inode space(%) */ __u64 datablocks; /* fsblocks in data subvolume */ __u64 rtblocks; /* fsblocks in realtime subvol */ __u64 rtextents; /* rt extents in realtime subvol*/ __u64 logstart; /* starting fsblock of the log */ unsigned char uuid[16]; /* unique id of the filesystem */ __u32 sunit; /* stripe unit, fsblocks */ __u32 swidth; /* stripe width, fsblocks */ __s32 version; /* structure version */ __u32 flags; /* superblock version flags */ __u32 logsectsize; /* log sector size, bytes */ __u32 rtsectsize; /* realtime sector size, bytes */ __u32 dirblocksize; /* directory block size, bytes */ __u32 logsunit; /* log stripe unit, bytes */ }; /* * Output for XFS_IOC_FSGEOMETRY */ struct xfs_fsop_geom { __u32 blocksize; /* filesystem (data) block size */ __u32 rtextsize; /* realtime extent size */ __u32 agblocks; /* fsblocks in an AG */ __u32 agcount; /* number of allocation groups */ __u32 logblocks; /* fsblocks in the log */ __u32 sectsize; /* (data) sector size, bytes */ __u32 inodesize; /* inode size in bytes */ __u32 imaxpct; /* max allowed inode space(%) */ __u64 datablocks; /* fsblocks in data subvolume */ __u64 rtblocks; /* fsblocks in realtime subvol */ __u64 rtextents; /* rt extents in realtime subvol*/ __u64 logstart; /* starting fsblock of the log */ unsigned char uuid[16]; /* unique id of the filesystem */ __u32 sunit; /* stripe unit, fsblocks */ __u32 swidth; /* stripe width, fsblocks */ __s32 version; /* structure version */ __u32 flags; /* superblock version flags */ __u32 logsectsize; /* log sector size, bytes */ __u32 rtsectsize; /* realtime sector size, bytes */ __u32 dirblocksize; /* directory block size, bytes */ __u32 logsunit; /* log stripe unit, bytes */ uint32_t sick; /* o: unhealthy fs & rt metadata */ uint32_t checked; /* o: checked fs & rt metadata */ __u64 reserved[17]; /* reserved space */ }; #define XFS_FSOP_GEOM_SICK_COUNTERS (1 << 0) /* summary counters */ #define XFS_FSOP_GEOM_SICK_UQUOTA (1 << 1) /* user quota */ #define XFS_FSOP_GEOM_SICK_GQUOTA (1 << 2) /* group quota */ #define XFS_FSOP_GEOM_SICK_PQUOTA (1 << 3) /* project quota */ #define XFS_FSOP_GEOM_SICK_RT_BITMAP (1 << 4) /* realtime bitmap */ #define XFS_FSOP_GEOM_SICK_RT_SUMMARY (1 << 5) /* realtime summary */ /* Output for XFS_FS_COUNTS */ typedef struct xfs_fsop_counts { __u64 freedata; /* free data section blocks */ __u64 freertx; /* free rt extents */ __u64 freeino; /* free inodes */ __u64 allocino; /* total allocated inodes */ } xfs_fsop_counts_t; /* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ typedef struct xfs_fsop_resblks { __u64 resblks; __u64 resblks_avail; } xfs_fsop_resblks_t; #define XFS_FSOP_GEOM_VERSION 0 #define XFS_FSOP_GEOM_VERSION_V5 5 #define XFS_FSOP_GEOM_FLAGS_ATTR (1 << 0) /* attributes in use */ #define XFS_FSOP_GEOM_FLAGS_NLINK (1 << 1) /* 32-bit nlink values */ #define XFS_FSOP_GEOM_FLAGS_QUOTA (1 << 2) /* quotas enabled */ #define XFS_FSOP_GEOM_FLAGS_IALIGN (1 << 3) /* inode alignment */ #define XFS_FSOP_GEOM_FLAGS_DALIGN (1 << 4) /* large data alignment */ #define XFS_FSOP_GEOM_FLAGS_SHARED (1 << 5) /* read-only shared */ #define XFS_FSOP_GEOM_FLAGS_EXTFLG (1 << 6) /* special extent flag */ #define XFS_FSOP_GEOM_FLAGS_DIRV2 (1 << 7) /* directory version 2 */ #define XFS_FSOP_GEOM_FLAGS_LOGV2 (1 << 8) /* log format version 2 */ #define XFS_FSOP_GEOM_FLAGS_SECTOR (1 << 9) /* sector sizes >1BB */ #define XFS_FSOP_GEOM_FLAGS_ATTR2 (1 << 10) /* inline attributes rework */ #define XFS_FSOP_GEOM_FLAGS_PROJID32 (1 << 11) /* 32-bit project IDs */ #define XFS_FSOP_GEOM_FLAGS_DIRV2CI (1 << 12) /* ASCII only CI names */ /* -- Do not use -- (1 << 13) SGI parent pointers */ #define XFS_FSOP_GEOM_FLAGS_LAZYSB (1 << 14) /* lazy superblock counters */ #define XFS_FSOP_GEOM_FLAGS_V5SB (1 << 15) /* version 5 superblock */ #define XFS_FSOP_GEOM_FLAGS_FTYPE (1 << 16) /* inode directory types */ #define XFS_FSOP_GEOM_FLAGS_FINOBT (1 << 17) /* free inode btree */ #define XFS_FSOP_GEOM_FLAGS_SPINODES (1 << 18) /* sparse inode chunks */ #define XFS_FSOP_GEOM_FLAGS_RMAPBT (1 << 19) /* reverse mapping btree */ #define XFS_FSOP_GEOM_FLAGS_REFLINK (1 << 20) /* files can share blocks */ /* * Minimum and maximum sizes need for growth checks. * * Block counts are in units of filesystem blocks, not basic blocks. */ #define XFS_MIN_AG_BLOCKS 64 #define XFS_MIN_LOG_BLOCKS 512ULL #define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) #define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) /* * Limits on sb_agblocks/sb_agblklog -- mkfs won't format AGs smaller than * 16MB or larger than 1TB. */ #define XFS_MIN_AG_BYTES (1ULL << 24) /* 16 MB */ #define XFS_MAX_AG_BYTES (1ULL << 40) /* 1 TB */ /* keep the maximum size under 2^31 by a small amount */ #define XFS_MAX_LOG_BYTES \ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) /* Used for sanity checks on superblock */ #define XFS_MAX_DBLOCKS(s) ((xfs_rfsblock_t)(s)->sb_agcount * (s)->sb_agblocks) #define XFS_MIN_DBLOCKS(s) ((xfs_rfsblock_t)((s)->sb_agcount - 1) * \ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) /* * Output for XFS_IOC_AG_GEOMETRY */ struct xfs_ag_geometry { uint32_t ag_number; /* i/o: AG number */ uint32_t ag_length; /* o: length in blocks */ uint32_t ag_freeblks; /* o: free space */ uint32_t ag_icount; /* o: inodes allocated */ uint32_t ag_ifree; /* o: inodes free */ uint32_t ag_sick; /* o: sick things in ag */ uint32_t ag_checked; /* o: checked metadata in ag */ uint32_t ag_reserved32; /* o: zero */ uint64_t ag_reserved[12];/* o: zero */ }; #define XFS_AG_GEOM_SICK_SB (1 << 0) /* superblock */ #define XFS_AG_GEOM_SICK_AGF (1 << 1) /* AGF header */ #define XFS_AG_GEOM_SICK_AGFL (1 << 2) /* AGFL header */ #define XFS_AG_GEOM_SICK_AGI (1 << 3) /* AGI header */ #define XFS_AG_GEOM_SICK_BNOBT (1 << 4) /* free space by block */ #define XFS_AG_GEOM_SICK_CNTBT (1 << 5) /* free space by length */ #define XFS_AG_GEOM_SICK_INOBT (1 << 6) /* inode index */ #define XFS_AG_GEOM_SICK_FINOBT (1 << 7) /* free inode index */ #define XFS_AG_GEOM_SICK_RMAPBT (1 << 8) /* reverse mappings */ #define XFS_AG_GEOM_SICK_REFCNTBT (1 << 9) /* reference counts */ /* * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT */ typedef struct xfs_growfs_data { __u64 newblocks; /* new data subvol size, fsblocks */ __u32 imaxpct; /* new inode space percentage limit */ } xfs_growfs_data_t; typedef struct xfs_growfs_log { __u32 newblocks; /* new log size, fsblocks */ __u32 isint; /* 1 if new log is internal */ } xfs_growfs_log_t; typedef struct xfs_growfs_rt { __u64 newblocks; /* new realtime size, fsblocks */ __u32 extsize; /* new realtime extent size, fsblocks */ } xfs_growfs_rt_t; /* * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE */ typedef struct xfs_bstime { time_t tv_sec; /* seconds */ __s32 tv_nsec; /* and nanoseconds */ } xfs_bstime_t; struct xfs_bstat { __u64 bs_ino; /* inode number */ __u16 bs_mode; /* type and mode */ __u16 bs_nlink; /* number of links */ __u32 bs_uid; /* user id */ __u32 bs_gid; /* group id */ __u32 bs_rdev; /* device value */ __s32 bs_blksize; /* block size */ __s64 bs_size; /* file size */ xfs_bstime_t bs_atime; /* access time */ xfs_bstime_t bs_mtime; /* modify time */ xfs_bstime_t bs_ctime; /* inode change time */ int64_t bs_blocks; /* number of blocks */ __u32 bs_xflags; /* extended flags */ __s32 bs_extsize; /* extent size */ __s32 bs_extents; /* number of extents */ __u32 bs_gen; /* generation count */ __u16 bs_projid_lo; /* lower part of project id */ #define bs_projid bs_projid_lo /* (previously just bs_projid) */ __u16 bs_forkoff; /* inode fork offset in bytes */ __u16 bs_projid_hi; /* higher part of project id */ uint16_t bs_sick; /* sick inode metadata */ uint16_t bs_checked; /* checked inode metadata */ unsigned char bs_pad[2]; /* pad space, unused */ __u32 bs_cowextsize; /* cow extent size */ __u32 bs_dmevmask; /* DMIG event mask */ __u16 bs_dmstate; /* DMIG state info */ __u16 bs_aextents; /* attribute number of extents */ }; /* New bulkstat structure that reports v5 features and fixes padding issues */ struct xfs_bulkstat { uint64_t bs_ino; /* inode number */ uint64_t bs_size; /* file size */ uint64_t bs_blocks; /* number of blocks */ uint64_t bs_xflags; /* extended flags */ uint64_t bs_atime; /* access time, seconds */ uint64_t bs_mtime; /* modify time, seconds */ uint64_t bs_ctime; /* inode change time, seconds */ uint64_t bs_btime; /* creation time, seconds */ uint32_t bs_gen; /* generation count */ uint32_t bs_uid; /* user id */ uint32_t bs_gid; /* group id */ uint32_t bs_projectid; /* project id */ uint32_t bs_atime_nsec; /* access time, nanoseconds */ uint32_t bs_mtime_nsec; /* modify time, nanoseconds */ uint32_t bs_ctime_nsec; /* inode change time, nanoseconds */ uint32_t bs_btime_nsec; /* creation time, nanoseconds */ uint32_t bs_blksize; /* block size */ uint32_t bs_rdev; /* device value */ uint32_t bs_cowextsize_blks; /* cow extent size hint, blocks */ uint32_t bs_extsize_blks; /* extent size hint, blocks */ uint32_t bs_nlink; /* number of links */ uint32_t bs_extents; /* number of extents */ uint32_t bs_aextents; /* attribute number of extents */ uint16_t bs_version; /* structure version */ uint16_t bs_forkoff; /* inode fork offset in bytes */ uint16_t bs_sick; /* sick inode metadata */ uint16_t bs_checked; /* checked inode metadata */ uint16_t bs_mode; /* type and mode */ uint16_t bs_pad2; /* zeroed */ uint64_t bs_pad[7]; /* zeroed */ }; #define XFS_BULKSTAT_VERSION_V1 (1) #define XFS_BULKSTAT_VERSION_V5 (5) /* bs_sick flags */ #define XFS_BS_SICK_INODE (1 << 0) /* inode core */ #define XFS_BS_SICK_BMBTD (1 << 1) /* data fork */ #define XFS_BS_SICK_BMBTA (1 << 2) /* attr fork */ #define XFS_BS_SICK_BMBTC (1 << 3) /* cow fork */ #define XFS_BS_SICK_DIR (1 << 4) /* directory */ #define XFS_BS_SICK_XATTR (1 << 5) /* extended attributes */ #define XFS_BS_SICK_SYMLINK (1 << 6) /* symbolic link remote target */ #define XFS_BS_SICK_PARENT (1 << 7) /* parent pointers */ /* * Project quota id helpers (previously projid was 16bit only * and using two 16bit values to hold new 32bit projid was choosen * to retain compatibility with "old" filesystems). */ static inline uint32_t bstat_get_projid(const struct xfs_bstat *bs) { return (uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo; } /* * The user-level BulkStat Request interface structure. */ struct xfs_fsop_bulkreq { __u64 __user *lastip; /* last inode # pointer */ __s32 icount; /* count of entries in buffer */ void __user *ubuffer;/* user buffer for inode desc. */ __s32 __user *ocount; /* output count pointer */ }; /* * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). */ struct xfs_inogrp { __u64 xi_startino; /* starting inode number */ __s32 xi_alloccount; /* # bits set in allocmask */ __u64 xi_allocmask; /* mask of allocated inodes */ }; /* New inumbers structure that reports v5 features and fixes padding issues */ struct xfs_inumbers { uint64_t xi_startino; /* starting inode number */ uint64_t xi_allocmask; /* mask of allocated inodes */ uint8_t xi_alloccount; /* # bits set in allocmask */ uint8_t xi_version; /* version */ uint8_t xi_padding[6]; /* zero */ }; #define XFS_INUMBERS_VERSION_V1 (1) #define XFS_INUMBERS_VERSION_V5 (5) /* Header for bulk inode requests. */ struct xfs_bulk_ireq { uint64_t ino; /* I/O: start with this inode */ uint32_t flags; /* I/O: operation flags */ uint32_t icount; /* I: count of entries in buffer */ uint32_t ocount; /* O: count of entries filled out */ uint32_t agno; /* I: see comment for IREQ_AGNO */ uint64_t reserved[5]; /* must be zero */ }; /* * Only return results from the specified @agno. If @ino is zero, start * with the first inode of @agno. */ #define XFS_BULK_IREQ_AGNO (1 << 0) /* * Return bulkstat information for a single inode, where @ino value is a * special value, not a literal inode number. See the XFS_BULK_IREQ_SPECIAL_* * values below. Not compatible with XFS_BULK_IREQ_AGNO. */ #define XFS_BULK_IREQ_SPECIAL (1 << 1) #define XFS_BULK_IREQ_FLAGS_ALL (XFS_BULK_IREQ_AGNO | \ XFS_BULK_IREQ_SPECIAL) /* Operate on the root directory inode. */ #define XFS_BULK_IREQ_SPECIAL_ROOT (1) /* * ioctl structures for v5 bulkstat and inumbers requests */ struct xfs_bulkstat_req { struct xfs_bulk_ireq hdr; struct xfs_bulkstat bulkstat[]; }; #define XFS_BULKSTAT_REQ_SIZE(nr) (sizeof(struct xfs_bulkstat_req) + \ (nr) * sizeof(struct xfs_bulkstat)) struct xfs_inumbers_req { struct xfs_bulk_ireq hdr; struct xfs_inumbers inumbers[]; }; #define XFS_INUMBERS_REQ_SIZE(nr) (sizeof(struct xfs_inumbers_req) + \ (nr) * sizeof(struct xfs_inumbers)) /* * Error injection. */ typedef struct xfs_error_injection { __s32 fd; __s32 errtag; } xfs_error_injection_t; /* * Speculative preallocation trimming. */ #define XFS_EOFBLOCKS_VERSION 1 struct xfs_fs_eofblocks { __u32 eof_version; __u32 eof_flags; uid_t eof_uid; gid_t eof_gid; prid_t eof_prid; __u32 pad32; __u64 eof_min_file_size; __u64 pad64[12]; }; /* eof_flags values */ #define XFS_EOF_FLAGS_SYNC (1 << 0) /* sync/wait mode scan */ #define XFS_EOF_FLAGS_UID (1 << 1) /* filter by uid */ #define XFS_EOF_FLAGS_GID (1 << 2) /* filter by gid */ #define XFS_EOF_FLAGS_PRID (1 << 3) /* filter by project id */ #define XFS_EOF_FLAGS_MINFILESIZE (1 << 4) /* filter by min file size */ #define XFS_EOF_FLAGS_UNION (1 << 5) /* union filter algorithm; * kernel only, not included in * valid mask */ #define XFS_EOF_FLAGS_VALID \ (XFS_EOF_FLAGS_SYNC | \ XFS_EOF_FLAGS_UID | \ XFS_EOF_FLAGS_GID | \ XFS_EOF_FLAGS_PRID | \ XFS_EOF_FLAGS_MINFILESIZE) /* * The user-level Handle Request interface structure. */ typedef struct xfs_fsop_handlereq { __u32 fd; /* fd for FD_TO_HANDLE */ void __user *path; /* user pathname */ __u32 oflags; /* open flags */ void __user *ihandle;/* user supplied handle */ __u32 ihandlen; /* user supplied length */ void __user *ohandle;/* user buffer for handle */ __u32 __user *ohandlen;/* user buffer length */ } xfs_fsop_handlereq_t; /* * Compound structures for passing args through Handle Request interfaces * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and * XFS_IOC_ATTRMULTI_BY_HANDLE */ typedef struct xfs_fsop_setdm_handlereq { struct xfs_fsop_handlereq hreq; /* handle information */ struct fsdmidata __user *data; /* DMAPI data */ } xfs_fsop_setdm_handlereq_t; typedef struct xfs_attrlist_cursor { __u32 opaque[4]; } xfs_attrlist_cursor_t; typedef struct xfs_fsop_attrlist_handlereq { struct xfs_fsop_handlereq hreq; /* handle interface structure */ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ __u32 flags; /* which namespace to use */ __u32 buflen; /* length of buffer supplied */ void __user *buffer; /* returned names */ } xfs_fsop_attrlist_handlereq_t; typedef struct xfs_attr_multiop { __u32 am_opcode; #define ATTR_OP_GET 1 /* return the indicated attr's value */ #define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ #define ATTR_OP_REMOVE 3 /* remove the indicated attr */ __s32 am_error; void __user *am_attrname; void __user *am_attrvalue; __u32 am_length; __u32 am_flags; } xfs_attr_multiop_t; typedef struct xfs_fsop_attrmulti_handlereq { struct xfs_fsop_handlereq hreq; /* handle interface structure */ __u32 opcount;/* count of following multiop */ struct xfs_attr_multiop __user *ops; /* attr_multi data */ } xfs_fsop_attrmulti_handlereq_t; /* * per machine unique filesystem identifier types. */ typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ typedef struct xfs_fid { __u16 fid_len; /* length of remainder */ __u16 fid_pad; __u32 fid_gen; /* generation number */ __u64 fid_ino; /* 64 bits inode number */ } xfs_fid_t; typedef struct xfs_handle { union { __s64 align; /* force alignment of ha_fid */ xfs_fsid_t _ha_fsid; /* unique file system identifier */ } ha_u; xfs_fid_t ha_fid; /* file system specific file ID */ } xfs_handle_t; #define ha_fsid ha_u._ha_fsid /* * Structure passed to XFS_IOC_SWAPEXT */ typedef struct xfs_swapext { int64_t sx_version; /* version */ #define XFS_SX_VERSION 0 int64_t sx_fdtarget; /* fd of target file */ int64_t sx_fdtmp; /* fd of tmp file */ xfs_off_t sx_offset; /* offset into file */ xfs_off_t sx_length; /* leng from offset */ char sx_pad[16]; /* pad space, unused */ struct xfs_bstat sx_stat; /* stat of target b4 copy */ } xfs_swapext_t; /* * Flags for going down operation */ #define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ #define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ /* metadata scrubbing */ struct xfs_scrub_metadata { __u32 sm_type; /* What to check? */ __u32 sm_flags; /* flags; see below. */ __u64 sm_ino; /* inode number. */ __u32 sm_gen; /* inode generation. */ __u32 sm_agno; /* ag number. */ __u64 sm_reserved[5]; /* pad to 64 bytes */ }; /* * Metadata types and flags for scrub operation. */ /* Scrub subcommands. */ #define XFS_SCRUB_TYPE_PROBE 0 /* presence test ioctl */ #define XFS_SCRUB_TYPE_SB 1 /* superblock */ #define XFS_SCRUB_TYPE_AGF 2 /* AG free header */ #define XFS_SCRUB_TYPE_AGFL 3 /* AG free list */ #define XFS_SCRUB_TYPE_AGI 4 /* AG inode header */ #define XFS_SCRUB_TYPE_BNOBT 5 /* freesp by block btree */ #define XFS_SCRUB_TYPE_CNTBT 6 /* freesp by length btree */ #define XFS_SCRUB_TYPE_INOBT 7 /* inode btree */ #define XFS_SCRUB_TYPE_FINOBT 8 /* free inode btree */ #define XFS_SCRUB_TYPE_RMAPBT 9 /* reverse mapping btree */ #define XFS_SCRUB_TYPE_REFCNTBT 10 /* reference count btree */ #define XFS_SCRUB_TYPE_INODE 11 /* inode record */ #define XFS_SCRUB_TYPE_BMBTD 12 /* data fork block mapping */ #define XFS_SCRUB_TYPE_BMBTA 13 /* attr fork block mapping */ #define XFS_SCRUB_TYPE_BMBTC 14 /* CoW fork block mapping */ #define XFS_SCRUB_TYPE_DIR 15 /* directory */ #define XFS_SCRUB_TYPE_XATTR 16 /* extended attribute */ #define XFS_SCRUB_TYPE_SYMLINK 17 /* symbolic link */ #define XFS_SCRUB_TYPE_PARENT 18 /* parent pointers */ #define XFS_SCRUB_TYPE_RTBITMAP 19 /* realtime bitmap */ #define XFS_SCRUB_TYPE_RTSUM 20 /* realtime summary */ #define XFS_SCRUB_TYPE_UQUOTA 21 /* user quotas */ #define XFS_SCRUB_TYPE_GQUOTA 22 /* group quotas */ #define XFS_SCRUB_TYPE_PQUOTA 23 /* project quotas */ #define XFS_SCRUB_TYPE_FSCOUNTERS 24 /* fs summary counters */ /* Number of scrub subcommands. */ #define XFS_SCRUB_TYPE_NR 25 /* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0) /* o: Metadata object needs repair. */ #define XFS_SCRUB_OFLAG_CORRUPT (1 << 1) /* * o: Metadata object could be optimized. It's not corrupt, but * we could improve on it somehow. */ #define XFS_SCRUB_OFLAG_PREEN (1 << 2) /* o: Cross-referencing failed. */ #define XFS_SCRUB_OFLAG_XFAIL (1 << 3) /* o: Metadata object disagrees with cross-referenced metadata. */ #define XFS_SCRUB_OFLAG_XCORRUPT (1 << 4) /* o: Scan was not complete. */ #define XFS_SCRUB_OFLAG_INCOMPLETE (1 << 5) /* o: Metadata object looked funny but isn't corrupt. */ #define XFS_SCRUB_OFLAG_WARNING (1 << 6) /* * o: IFLAG_REPAIR was set but metadata object did not need fixing or * optimization and has therefore not been altered. */ #define XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED (1 << 7) #define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR) #define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \ XFS_SCRUB_OFLAG_PREEN | \ XFS_SCRUB_OFLAG_XFAIL | \ XFS_SCRUB_OFLAG_XCORRUPT | \ XFS_SCRUB_OFLAG_INCOMPLETE | \ XFS_SCRUB_OFLAG_WARNING | \ XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) #define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) /* * ioctl limits */ #ifdef XATTR_LIST_MAX # define XFS_XATTR_LIST_MAX XATTR_LIST_MAX #else # define XFS_XATTR_LIST_MAX 65536 #endif /* * ioctl commands that are used by Linux filesystems */ #define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS #define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS #define XFS_IOC_GETVERSION FS_IOC_GETVERSION /* * ioctl commands that replace IRIX fcntl()'s * For 'documentation' purposed more than anything else, * the "cmd #" field reflects the IRIX fcntl number. */ #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) #define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) #define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR #define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) #define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) #define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) #define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) #define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) #define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) #define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) #define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) #define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) /* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ /* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ #define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) #define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64) #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks) /* XFS_IOC_GETFSMAP ------ hoisted 59 */ #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata) #define XFS_IOC_AG_GEOMETRY _IOWR('X', 61, struct xfs_ag_geometry) /* * ioctl commands that replace IRIX syssgi()'s */ #define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) #define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) #define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) #define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) #define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) #define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) #define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) #define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) #define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) #define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) #define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) #define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) #define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) #define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) #define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks) #define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) #define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) #define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) /* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ #define XFS_IOC_FREEZE _IOWR('X', 119, int) /* aka FIFREEZE */ #define XFS_IOC_THAW _IOWR('X', 120, int) /* aka FITHAW */ #define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) #define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) #define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) #define XFS_IOC_FSGEOMETRY_V4 _IOR ('X', 124, struct xfs_fsop_geom_v4) #define XFS_IOC_GOINGDOWN _IOR ('X', 125, uint32_t) #define XFS_IOC_FSGEOMETRY _IOR ('X', 126, struct xfs_fsop_geom) #define XFS_IOC_BULKSTAT _IOR ('X', 127, struct xfs_bulkstat_req) #define XFS_IOC_INUMBERS _IOR ('X', 128, struct xfs_inumbers_req) /* XFS_IOC_GETFSUUID ---------- deprecated 140 */ /* reflink ioctls; these MUST match the btrfs ioctl definitions */ /* from struct btrfs_ioctl_clone_range_args */ struct xfs_clone_args { __s64 src_fd; __u64 src_offset; __u64 src_length; __u64 dest_offset; }; /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */ #define XFS_EXTENT_DATA_SAME 0 #define XFS_EXTENT_DATA_DIFFERS 1 /* from struct btrfs_ioctl_file_extent_same_info */ struct xfs_extent_data_info { __s64 fd; /* in - destination file */ __u64 logical_offset; /* in - start of extent in destination */ __u64 bytes_deduped; /* out - total # of bytes we were able * to dedupe from this file */ /* status of this dedupe operation: * < 0 for error * == XFS_EXTENT_DATA_SAME if dedupe succeeds * == XFS_EXTENT_DATA_DIFFERS if data differs */ __s32 status; /* out - see above description */ __u32 reserved; }; /* from struct btrfs_ioctl_file_extent_same_args */ struct xfs_extent_data { __u64 logical_offset; /* in - start of extent in source */ __u64 length; /* in - length of extent */ __u16 dest_count; /* in - total elements in info array */ __u16 reserved1; __u32 reserved2; struct xfs_extent_data_info info[0]; }; #define XFS_IOC_CLONE _IOW (0x94, 9, int) #define XFS_IOC_CLONE_RANGE _IOW (0x94, 13, struct xfs_clone_args) #define XFS_IOC_FILE_EXTENT_SAME _IOWR(0x94, 54, struct xfs_extent_data) #ifndef HAVE_BBMACROS /* * Block I/O parameterization. A basic block (BB) is the lowest size of * filesystem allocation, and must equal 512. Length units given to bio * routines are in BB's. */ #define BBSHIFT 9 #define BBSIZE (1<> BBSHIFT) #define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) #define BBTOB(bbs) ((bbs) << BBSHIFT) #endif #endif /* __XFS_FS_H__ */ xfsprogs-5.3.0/libxfs/xfs_health.h0000644000175000017500000001430013570057155017037 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_HEALTH_H__ #define __XFS_HEALTH_H__ /* * In-Core Filesystem Health Assessments * ===================================== * * We'd like to be able to summarize the current health status of the * filesystem so that the administrator knows when it's necessary to schedule * some downtime for repairs. Until then, we would also like to avoid abrupt * shutdowns due to corrupt metadata. * * The online scrub feature evaluates the health of all filesystem metadata. * When scrub detects corruption in a piece of metadata it will set the * corresponding sickness flag, and repair will clear it if successful. If * problems remain at unmount time, we can also request manual intervention by * logging a notice to run xfs_repair. * * Each health tracking group uses a pair of fields for reporting. The * "checked" field tell us if a given piece of metadata has ever been examined, * and the "sick" field tells us if that piece was found to need repairs. * Therefore we can conclude that for a given sick flag value: * * - checked && sick => metadata needs repair * - checked && !sick => metadata is ok * - !checked => has not been examined since mount */ struct xfs_mount; struct xfs_perag; struct xfs_inode; struct xfs_fsop_geom; /* Observable health issues for metadata spanning the entire filesystem. */ #define XFS_SICK_FS_COUNTERS (1 << 0) /* summary counters */ #define XFS_SICK_FS_UQUOTA (1 << 1) /* user quota */ #define XFS_SICK_FS_GQUOTA (1 << 2) /* group quota */ #define XFS_SICK_FS_PQUOTA (1 << 3) /* project quota */ /* Observable health issues for realtime volume metadata. */ #define XFS_SICK_RT_BITMAP (1 << 0) /* realtime bitmap */ #define XFS_SICK_RT_SUMMARY (1 << 1) /* realtime summary */ /* Observable health issues for AG metadata. */ #define XFS_SICK_AG_SB (1 << 0) /* superblock */ #define XFS_SICK_AG_AGF (1 << 1) /* AGF header */ #define XFS_SICK_AG_AGFL (1 << 2) /* AGFL header */ #define XFS_SICK_AG_AGI (1 << 3) /* AGI header */ #define XFS_SICK_AG_BNOBT (1 << 4) /* free space by block */ #define XFS_SICK_AG_CNTBT (1 << 5) /* free space by length */ #define XFS_SICK_AG_INOBT (1 << 6) /* inode index */ #define XFS_SICK_AG_FINOBT (1 << 7) /* free inode index */ #define XFS_SICK_AG_RMAPBT (1 << 8) /* reverse mappings */ #define XFS_SICK_AG_REFCNTBT (1 << 9) /* reference counts */ /* Observable health issues for inode metadata. */ #define XFS_SICK_INO_CORE (1 << 0) /* inode core */ #define XFS_SICK_INO_BMBTD (1 << 1) /* data fork */ #define XFS_SICK_INO_BMBTA (1 << 2) /* attr fork */ #define XFS_SICK_INO_BMBTC (1 << 3) /* cow fork */ #define XFS_SICK_INO_DIR (1 << 4) /* directory */ #define XFS_SICK_INO_XATTR (1 << 5) /* extended attributes */ #define XFS_SICK_INO_SYMLINK (1 << 6) /* symbolic link remote target */ #define XFS_SICK_INO_PARENT (1 << 7) /* parent pointers */ /* Primary evidence of health problems in a given group. */ #define XFS_SICK_FS_PRIMARY (XFS_SICK_FS_COUNTERS | \ XFS_SICK_FS_UQUOTA | \ XFS_SICK_FS_GQUOTA | \ XFS_SICK_FS_PQUOTA) #define XFS_SICK_RT_PRIMARY (XFS_SICK_RT_BITMAP | \ XFS_SICK_RT_SUMMARY) #define XFS_SICK_AG_PRIMARY (XFS_SICK_AG_SB | \ XFS_SICK_AG_AGF | \ XFS_SICK_AG_AGFL | \ XFS_SICK_AG_AGI | \ XFS_SICK_AG_BNOBT | \ XFS_SICK_AG_CNTBT | \ XFS_SICK_AG_INOBT | \ XFS_SICK_AG_FINOBT | \ XFS_SICK_AG_RMAPBT | \ XFS_SICK_AG_REFCNTBT) #define XFS_SICK_INO_PRIMARY (XFS_SICK_INO_CORE | \ XFS_SICK_INO_BMBTD | \ XFS_SICK_INO_BMBTA | \ XFS_SICK_INO_BMBTC | \ XFS_SICK_INO_DIR | \ XFS_SICK_INO_XATTR | \ XFS_SICK_INO_SYMLINK | \ XFS_SICK_INO_PARENT) /* These functions must be provided by the xfs implementation. */ void xfs_fs_mark_sick(struct xfs_mount *mp, unsigned int mask); void xfs_fs_mark_healthy(struct xfs_mount *mp, unsigned int mask); void xfs_fs_measure_sickness(struct xfs_mount *mp, unsigned int *sick, unsigned int *checked); void xfs_rt_mark_sick(struct xfs_mount *mp, unsigned int mask); void xfs_rt_mark_healthy(struct xfs_mount *mp, unsigned int mask); void xfs_rt_measure_sickness(struct xfs_mount *mp, unsigned int *sick, unsigned int *checked); void xfs_ag_mark_sick(struct xfs_perag *pag, unsigned int mask); void xfs_ag_mark_healthy(struct xfs_perag *pag, unsigned int mask); void xfs_ag_measure_sickness(struct xfs_perag *pag, unsigned int *sick, unsigned int *checked); void xfs_inode_mark_sick(struct xfs_inode *ip, unsigned int mask); void xfs_inode_mark_healthy(struct xfs_inode *ip, unsigned int mask); void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick, unsigned int *checked); void xfs_health_unmount(struct xfs_mount *mp); /* Now some helpers. */ static inline bool xfs_fs_has_sickness(struct xfs_mount *mp, unsigned int mask) { unsigned int sick, checked; xfs_fs_measure_sickness(mp, &sick, &checked); return sick & mask; } static inline bool xfs_rt_has_sickness(struct xfs_mount *mp, unsigned int mask) { unsigned int sick, checked; xfs_rt_measure_sickness(mp, &sick, &checked); return sick & mask; } static inline bool xfs_ag_has_sickness(struct xfs_perag *pag, unsigned int mask) { unsigned int sick, checked; xfs_ag_measure_sickness(pag, &sick, &checked); return sick & mask; } static inline bool xfs_inode_has_sickness(struct xfs_inode *ip, unsigned int mask) { unsigned int sick, checked; xfs_inode_measure_sickness(ip, &sick, &checked); return sick & mask; } static inline bool xfs_fs_is_healthy(struct xfs_mount *mp) { return !xfs_fs_has_sickness(mp, -1U); } static inline bool xfs_rt_is_healthy(struct xfs_mount *mp) { return !xfs_rt_has_sickness(mp, -1U); } static inline bool xfs_ag_is_healthy(struct xfs_perag *pag) { return !xfs_ag_has_sickness(pag, -1U); } static inline bool xfs_inode_is_healthy(struct xfs_inode *ip) { return !xfs_inode_has_sickness(ip, -1U); } void xfs_fsop_geom_health(struct xfs_mount *mp, struct xfs_fsop_geom *geo); void xfs_ag_geom_health(struct xfs_perag *pag, struct xfs_ag_geometry *ageo); void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bulkstat *bs); #endif /* __XFS_HEALTH_H__ */ xfsprogs-5.3.0/libxfs/xfs_ialloc.c0000644000175000017500000023214713570057155017043 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_ialloc.h" #include "xfs_ialloc_btree.h" #include "xfs_alloc.h" #include "xfs_bmap.h" #include "xfs_trans.h" #include "xfs_trace.h" #include "xfs_rmap.h" /* * Lookup a record by ino in the btree given by cur. */ int /* error */ xfs_inobt_lookup( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agino_t ino, /* starting inode of chunk */ xfs_lookup_t dir, /* <=, >=, == */ int *stat) /* success/failure */ { cur->bc_rec.i.ir_startino = ino; cur->bc_rec.i.ir_holemask = 0; cur->bc_rec.i.ir_count = 0; cur->bc_rec.i.ir_freecount = 0; cur->bc_rec.i.ir_free = 0; return xfs_btree_lookup(cur, dir, stat); } /* * Update the record referred to by cur to the value given. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int /* error */ xfs_inobt_update( struct xfs_btree_cur *cur, /* btree cursor */ xfs_inobt_rec_incore_t *irec) /* btree record */ { union xfs_btree_rec rec; rec.inobt.ir_startino = cpu_to_be32(irec->ir_startino); if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { rec.inobt.ir_u.sp.ir_holemask = cpu_to_be16(irec->ir_holemask); rec.inobt.ir_u.sp.ir_count = irec->ir_count; rec.inobt.ir_u.sp.ir_freecount = irec->ir_freecount; } else { /* ir_holemask/ir_count not supported on-disk */ rec.inobt.ir_u.f.ir_freecount = cpu_to_be32(irec->ir_freecount); } rec.inobt.ir_free = cpu_to_be64(irec->ir_free); return xfs_btree_update(cur, &rec); } /* Convert on-disk btree record to incore inobt record. */ void xfs_inobt_btrec_to_irec( struct xfs_mount *mp, union xfs_btree_rec *rec, struct xfs_inobt_rec_incore *irec) { irec->ir_startino = be32_to_cpu(rec->inobt.ir_startino); if (xfs_sb_version_hassparseinodes(&mp->m_sb)) { irec->ir_holemask = be16_to_cpu(rec->inobt.ir_u.sp.ir_holemask); irec->ir_count = rec->inobt.ir_u.sp.ir_count; irec->ir_freecount = rec->inobt.ir_u.sp.ir_freecount; } else { /* * ir_holemask/ir_count not supported on-disk. Fill in hardcoded * values for full inode chunks. */ irec->ir_holemask = XFS_INOBT_HOLEMASK_FULL; irec->ir_count = XFS_INODES_PER_CHUNK; irec->ir_freecount = be32_to_cpu(rec->inobt.ir_u.f.ir_freecount); } irec->ir_free = be64_to_cpu(rec->inobt.ir_free); } /* * Get the data from the pointed-to record. */ int xfs_inobt_get_rec( struct xfs_btree_cur *cur, struct xfs_inobt_rec_incore *irec, int *stat) { struct xfs_mount *mp = cur->bc_mp; xfs_agnumber_t agno = cur->bc_private.a.agno; union xfs_btree_rec *rec; int error; uint64_t realfree; error = xfs_btree_get_rec(cur, &rec, stat); if (error || *stat == 0) return error; xfs_inobt_btrec_to_irec(mp, rec, irec); if (!xfs_verify_agino(mp, agno, irec->ir_startino)) goto out_bad_rec; if (irec->ir_count < XFS_INODES_PER_HOLEMASK_BIT || irec->ir_count > XFS_INODES_PER_CHUNK) goto out_bad_rec; if (irec->ir_freecount > XFS_INODES_PER_CHUNK) goto out_bad_rec; /* if there are no holes, return the first available offset */ if (!xfs_inobt_issparse(irec->ir_holemask)) realfree = irec->ir_free; else realfree = irec->ir_free & xfs_inobt_irec_to_allocmask(irec); if (hweight64(realfree) != irec->ir_freecount) goto out_bad_rec; return 0; out_bad_rec: xfs_warn(mp, "%s Inode BTree record corruption in AG %d detected!", cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", agno); xfs_warn(mp, "start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x", irec->ir_startino, irec->ir_count, irec->ir_freecount, irec->ir_free, irec->ir_holemask); return -EFSCORRUPTED; } /* * Insert a single inobt record. Cursor must already point to desired location. */ int xfs_inobt_insert_rec( struct xfs_btree_cur *cur, uint16_t holemask, uint8_t count, int32_t freecount, xfs_inofree_t free, int *stat) { cur->bc_rec.i.ir_holemask = holemask; cur->bc_rec.i.ir_count = count; cur->bc_rec.i.ir_freecount = freecount; cur->bc_rec.i.ir_free = free; return xfs_btree_insert(cur, stat); } /* * Insert records describing a newly allocated inode chunk into the inobt. */ STATIC int xfs_inobt_insert( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agino_t newino, xfs_agino_t newlen, xfs_btnum_t btnum) { struct xfs_btree_cur *cur; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); xfs_agino_t thisino; int i; int error; cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); for (thisino = newino; thisino < newino + newlen; thisino += XFS_INODES_PER_CHUNK) { error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i); if (error) { xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } ASSERT(i == 0); error = xfs_inobt_insert_rec(cur, XFS_INOBT_HOLEMASK_FULL, XFS_INODES_PER_CHUNK, XFS_INODES_PER_CHUNK, XFS_INOBT_ALL_FREE, &i); if (error) { xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } ASSERT(i == 1); } xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; } /* * Verify that the number of free inodes in the AGI is correct. */ #ifdef DEBUG STATIC int xfs_check_agi_freecount( struct xfs_btree_cur *cur, struct xfs_agi *agi) { if (cur->bc_nlevels == 1) { xfs_inobt_rec_incore_t rec; int freecount = 0; int error; int i; error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); if (error) return error; do { error = xfs_inobt_get_rec(cur, &rec, &i); if (error) return error; if (i) { freecount += rec.ir_freecount; error = xfs_btree_increment(cur, 0, &i); if (error) return error; } } while (i == 1); if (!XFS_FORCED_SHUTDOWN(cur->bc_mp)) ASSERT(freecount == be32_to_cpu(agi->agi_freecount)); } return 0; } #else #define xfs_check_agi_freecount(cur, agi) 0 #endif /* * Initialise a new set of inodes. When called without a transaction context * (e.g. from recovery) we initiate a delayed write of the inode buffers rather * than logging them (which in a transaction context puts them into the AIL * for writeback rather than the xfsbufd queue). */ int xfs_ialloc_inode_init( struct xfs_mount *mp, struct xfs_trans *tp, struct list_head *buffer_list, int icount, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t length, unsigned int gen) { struct xfs_buf *fbuf; struct xfs_dinode *free; int nbufs; int version; int i, j; xfs_daddr_t d; xfs_ino_t ino = 0; /* * Loop over the new block(s), filling in the inodes. For small block * sizes, manipulate the inodes in buffers which are multiples of the * blocks size. */ nbufs = length / M_IGEO(mp)->blocks_per_cluster; /* * Figure out what version number to use in the inodes we create. If * the superblock version has caught up to the one that supports the new * inode format, then use the new inode version. Otherwise use the old * version so that old kernels will continue to be able to use the file * system. * * For v3 inodes, we also need to write the inode number into the inode, * so calculate the first inode number of the chunk here as * XFS_AGB_TO_AGINO() only works within a filesystem block, not * across multiple filesystem blocks (such as a cluster) and so cannot * be used in the cluster buffer loop below. * * Further, because we are writing the inode directly into the buffer * and calculating a CRC on the entire inode, we have ot log the entire * inode so that the entire range the CRC covers is present in the log. * That means for v3 inode we log the entire buffer rather than just the * inode cores. */ if (xfs_sb_version_hascrc(&mp->m_sb)) { version = 3; ino = XFS_AGINO_TO_INO(mp, agno, XFS_AGB_TO_AGINO(mp, agbno)); /* * log the initialisation that is about to take place as an * logical operation. This means the transaction does not * need to log the physical changes to the inode buffers as log * recovery will know what initialisation is actually needed. * Hence we only need to log the buffers as "ordered" buffers so * they track in the AIL as if they were physically logged. */ if (tp) xfs_icreate_log(tp, agno, agbno, icount, mp->m_sb.sb_inodesize, length, gen); } else version = 2; for (j = 0; j < nbufs; j++) { /* * Get the block. */ d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * M_IGEO(mp)->blocks_per_cluster)); fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize * M_IGEO(mp)->blocks_per_cluster, XBF_UNMAPPED); if (!fbuf) return -ENOMEM; /* Initialize the inode buffers and log them appropriately. */ fbuf->b_ops = &xfs_inode_buf_ops; xfs_buf_zero(fbuf, 0, BBTOB(fbuf->b_length)); for (i = 0; i < M_IGEO(mp)->inodes_per_cluster; i++) { int ioffset = i << mp->m_sb.sb_inodelog; uint isize = xfs_dinode_size(version); free = xfs_make_iptr(mp, fbuf, i); free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); free->di_version = version; free->di_gen = cpu_to_be32(gen); free->di_next_unlinked = cpu_to_be32(NULLAGINO); if (version == 3) { free->di_ino = cpu_to_be64(ino); ino++; uuid_copy(&free->di_uuid, &mp->m_sb.sb_meta_uuid); xfs_dinode_calc_crc(mp, free); } else if (tp) { /* just log the inode core */ xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1); } } if (tp) { /* * Mark the buffer as an inode allocation buffer so it * sticks in AIL at the point of this allocation * transaction. This ensures the they are on disk before * the tail of the log can be moved past this * transaction (i.e. by preventing relogging from moving * it forward in the log). */ xfs_trans_inode_alloc_buf(tp, fbuf); if (version == 3) { /* * Mark the buffer as ordered so that they are * not physically logged in the transaction but * still tracked in the AIL as part of the * transaction and pin the log appropriately. */ xfs_trans_ordered_buf(tp, fbuf); } } else { fbuf->b_flags |= XBF_DONE; xfs_buf_delwri_queue(fbuf, buffer_list); xfs_buf_relse(fbuf); } } return 0; } /* * Align startino and allocmask for a recently allocated sparse chunk such that * they are fit for insertion (or merge) into the on-disk inode btrees. * * Background: * * When enabled, sparse inode support increases the inode alignment from cluster * size to inode chunk size. This means that the minimum range between two * non-adjacent inode records in the inobt is large enough for a full inode * record. This allows for cluster sized, cluster aligned block allocation * without need to worry about whether the resulting inode record overlaps with * another record in the tree. Without this basic rule, we would have to deal * with the consequences of overlap by potentially undoing recent allocations in * the inode allocation codepath. * * Because of this alignment rule (which is enforced on mount), there are two * inobt possibilities for newly allocated sparse chunks. One is that the * aligned inode record for the chunk covers a range of inodes not already * covered in the inobt (i.e., it is safe to insert a new sparse record). The * other is that a record already exists at the aligned startino that considers * the newly allocated range as sparse. In the latter case, record content is * merged in hope that sparse inode chunks fill to full chunks over time. */ STATIC void xfs_align_sparse_ino( struct xfs_mount *mp, xfs_agino_t *startino, uint16_t *allocmask) { xfs_agblock_t agbno; xfs_agblock_t mod; int offset; agbno = XFS_AGINO_TO_AGBNO(mp, *startino); mod = agbno % mp->m_sb.sb_inoalignmt; if (!mod) return; /* calculate the inode offset and align startino */ offset = XFS_AGB_TO_AGINO(mp, mod); *startino -= offset; /* * Since startino has been aligned down, left shift allocmask such that * it continues to represent the same physical inodes relative to the * new startino. */ *allocmask <<= offset / XFS_INODES_PER_HOLEMASK_BIT; } /* * Determine whether the source inode record can merge into the target. Both * records must be sparse, the inode ranges must match and there must be no * allocation overlap between the records. */ STATIC bool __xfs_inobt_can_merge( struct xfs_inobt_rec_incore *trec, /* tgt record */ struct xfs_inobt_rec_incore *srec) /* src record */ { uint64_t talloc; uint64_t salloc; /* records must cover the same inode range */ if (trec->ir_startino != srec->ir_startino) return false; /* both records must be sparse */ if (!xfs_inobt_issparse(trec->ir_holemask) || !xfs_inobt_issparse(srec->ir_holemask)) return false; /* both records must track some inodes */ if (!trec->ir_count || !srec->ir_count) return false; /* can't exceed capacity of a full record */ if (trec->ir_count + srec->ir_count > XFS_INODES_PER_CHUNK) return false; /* verify there is no allocation overlap */ talloc = xfs_inobt_irec_to_allocmask(trec); salloc = xfs_inobt_irec_to_allocmask(srec); if (talloc & salloc) return false; return true; } /* * Merge the source inode record into the target. The caller must call * __xfs_inobt_can_merge() to ensure the merge is valid. */ STATIC void __xfs_inobt_rec_merge( struct xfs_inobt_rec_incore *trec, /* target */ struct xfs_inobt_rec_incore *srec) /* src */ { ASSERT(trec->ir_startino == srec->ir_startino); /* combine the counts */ trec->ir_count += srec->ir_count; trec->ir_freecount += srec->ir_freecount; /* * Merge the holemask and free mask. For both fields, 0 bits refer to * allocated inodes. We combine the allocated ranges with bitwise AND. */ trec->ir_holemask &= srec->ir_holemask; trec->ir_free &= srec->ir_free; } /* * Insert a new sparse inode chunk into the associated inode btree. The inode * record for the sparse chunk is pre-aligned to a startino that should match * any pre-existing sparse inode record in the tree. This allows sparse chunks * to fill over time. * * This function supports two modes of handling preexisting records depending on * the merge flag. If merge is true, the provided record is merged with the * existing record and updated in place. The merged record is returned in nrec. * If merge is false, an existing record is replaced with the provided record. * If no preexisting record exists, the provided record is always inserted. * * It is considered corruption if a merge is requested and not possible. Given * the sparse inode alignment constraints, this should never happen. */ STATIC int xfs_inobt_insert_sprec( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, int btnum, struct xfs_inobt_rec_incore *nrec, /* in/out: new/merged rec. */ bool merge) /* merge or replace */ { struct xfs_btree_cur *cur; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); int error; int i; struct xfs_inobt_rec_incore rec; cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); /* the new record is pre-aligned so we know where to look */ error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i); if (error) goto error; /* if nothing there, insert a new record and return */ if (i == 0) { error = xfs_inobt_insert_rec(cur, nrec->ir_holemask, nrec->ir_count, nrec->ir_freecount, nrec->ir_free, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); goto out; } /* * A record exists at this startino. Merge or replace the record * depending on what we've been asked to do. */ if (merge) { error = xfs_inobt_get_rec(cur, &rec, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); XFS_WANT_CORRUPTED_GOTO(mp, rec.ir_startino == nrec->ir_startino, error); /* * This should never fail. If we have coexisting records that * cannot merge, something is seriously wrong. */ XFS_WANT_CORRUPTED_GOTO(mp, __xfs_inobt_can_merge(nrec, &rec), error); trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino, rec.ir_holemask, nrec->ir_startino, nrec->ir_holemask); /* merge to nrec to output the updated record */ __xfs_inobt_rec_merge(nrec, &rec); trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino, nrec->ir_holemask); error = xfs_inobt_rec_check_count(mp, nrec); if (error) goto error; } error = xfs_inobt_update(cur, nrec); if (error) goto error; out: xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; error: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Allocate new inodes in the allocation group specified by agbp. * Return 0 for success, else error code. */ STATIC int xfs_ialloc_ag_alloc( struct xfs_trans *tp, struct xfs_buf *agbp, int *alloc) { struct xfs_agi *agi; struct xfs_alloc_arg args; xfs_agnumber_t agno; int error; xfs_agino_t newino; /* new first inode's number */ xfs_agino_t newlen; /* new number of inodes */ int isaligned = 0; /* inode allocation at stripe */ /* unit boundary */ /* init. to full chunk */ uint16_t allocmask = (uint16_t) -1; struct xfs_inobt_rec_incore rec; struct xfs_perag *pag; struct xfs_ino_geometry *igeo = M_IGEO(tp->t_mountp); int do_sparse = 0; memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = tp->t_mountp; args.fsbno = NULLFSBLOCK; args.oinfo = XFS_RMAP_OINFO_INODES; #ifdef DEBUG /* randomly do sparse inode allocations */ if (xfs_sb_version_hassparseinodes(&tp->t_mountp->m_sb) && igeo->ialloc_min_blks < igeo->ialloc_blks) do_sparse = prandom_u32() & 1; #endif /* * Locking will ensure that we don't have two callers in here * at one time. */ newlen = igeo->ialloc_inos; if (igeo->maxicount && percpu_counter_read_positive(&args.mp->m_icount) + newlen > igeo->maxicount) return -ENOSPC; args.minlen = args.maxlen = igeo->ialloc_blks; /* * First try to allocate inodes contiguous with the last-allocated * chunk of inodes. If the filesystem is striped, this will fill * an entire stripe unit with inodes. */ agi = XFS_BUF_TO_AGI(agbp); newino = be32_to_cpu(agi->agi_newino); agno = be32_to_cpu(agi->agi_seqno); args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) + igeo->ialloc_blks; if (do_sparse) goto sparse_alloc; if (likely(newino != NULLAGINO && (args.agbno < be32_to_cpu(agi->agi_length)))) { args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.type = XFS_ALLOCTYPE_THIS_BNO; args.prod = 1; /* * We need to take into account alignment here to ensure that * we don't modify the free list if we fail to have an exact * block. If we don't have an exact match, and every oher * attempt allocation attempt fails, we'll end up cancelling * a dirty transaction and shutting down. * * For an exact allocation, alignment must be 1, * however we need to take cluster alignment into account when * fixing up the freelist. Use the minalignslop field to * indicate that extra blocks might be required for alignment, * but not to use them in the actual exact allocation. */ args.alignment = 1; args.minalignslop = igeo->cluster_align - 1; /* Allow space for the inode btree to split. */ args.minleft = igeo->inobt_maxlevels - 1; if ((error = xfs_alloc_vextent(&args))) return error; /* * This request might have dirtied the transaction if the AG can * satisfy the request, but the exact block was not available. * If the allocation did fail, subsequent requests will relax * the exact agbno requirement and increase the alignment * instead. It is critical that the total size of the request * (len + alignment + slop) does not increase from this point * on, so reset minalignslop to ensure it is not included in * subsequent requests. */ args.minalignslop = 0; } if (unlikely(args.fsbno == NULLFSBLOCK)) { /* * Set the alignment for the allocation. * If stripe alignment is turned on then align at stripe unit * boundary. * If the cluster size is smaller than a filesystem block * then we're doing I/O for inodes in filesystem block size * pieces, so don't need alignment anyway. */ isaligned = 0; if (igeo->ialloc_align) { ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN)); args.alignment = args.mp->m_dalign; isaligned = 1; } else args.alignment = igeo->cluster_align; /* * Need to figure out where to allocate the inode blocks. * Ideally they should be spaced out through the a.g. * For now, just allocate blocks up front. */ args.agbno = be32_to_cpu(agi->agi_root); args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); /* * Allocate a fixed-size extent of inodes. */ args.type = XFS_ALLOCTYPE_NEAR_BNO; args.prod = 1; /* * Allow space for the inode btree to split. */ args.minleft = igeo->inobt_maxlevels - 1; if ((error = xfs_alloc_vextent(&args))) return error; } /* * If stripe alignment is turned on, then try again with cluster * alignment. */ if (isaligned && args.fsbno == NULLFSBLOCK) { args.type = XFS_ALLOCTYPE_NEAR_BNO; args.agbno = be32_to_cpu(agi->agi_root); args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.alignment = igeo->cluster_align; if ((error = xfs_alloc_vextent(&args))) return error; } /* * Finally, try a sparse allocation if the filesystem supports it and * the sparse allocation length is smaller than a full chunk. */ if (xfs_sb_version_hassparseinodes(&args.mp->m_sb) && igeo->ialloc_min_blks < igeo->ialloc_blks && args.fsbno == NULLFSBLOCK) { sparse_alloc: args.type = XFS_ALLOCTYPE_NEAR_BNO; args.agbno = be32_to_cpu(agi->agi_root); args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.alignment = args.mp->m_sb.sb_spino_align; args.prod = 1; args.minlen = igeo->ialloc_min_blks; args.maxlen = args.minlen; /* * The inode record will be aligned to full chunk size. We must * prevent sparse allocation from AG boundaries that result in * invalid inode records, such as records that start at agbno 0 * or extend beyond the AG. * * Set min agbno to the first aligned, non-zero agbno and max to * the last aligned agbno that is at least one full chunk from * the end of the AG. */ args.min_agbno = args.mp->m_sb.sb_inoalignmt; args.max_agbno = round_down(args.mp->m_sb.sb_agblocks, args.mp->m_sb.sb_inoalignmt) - igeo->ialloc_blks; error = xfs_alloc_vextent(&args); if (error) return error; newlen = XFS_AGB_TO_AGINO(args.mp, args.len); ASSERT(newlen <= XFS_INODES_PER_CHUNK); allocmask = (1 << (newlen / XFS_INODES_PER_HOLEMASK_BIT)) - 1; } if (args.fsbno == NULLFSBLOCK) { *alloc = 0; return 0; } ASSERT(args.len == args.minlen); /* * Stamp and write the inode buffers. * * Seed the new inode cluster with a random generation number. This * prevents short-term reuse of generation numbers if a chunk is * freed and then immediately reallocated. We use random numbers * rather than a linear progression to prevent the next generation * number from being easily guessable. */ error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno, args.agbno, args.len, prandom_u32()); if (error) return error; /* * Convert the results. */ newino = XFS_AGB_TO_AGINO(args.mp, args.agbno); if (xfs_inobt_issparse(~allocmask)) { /* * We've allocated a sparse chunk. Align the startino and mask. */ xfs_align_sparse_ino(args.mp, &newino, &allocmask); rec.ir_startino = newino; rec.ir_holemask = ~allocmask; rec.ir_count = newlen; rec.ir_freecount = newlen; rec.ir_free = XFS_INOBT_ALL_FREE; /* * Insert the sparse record into the inobt and allow for a merge * if necessary. If a merge does occur, rec is updated to the * merged record. */ error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO, &rec, true); if (error == -EFSCORRUPTED) { xfs_alert(args.mp, "invalid sparse inode record: ino 0x%llx holemask 0x%x count %u", XFS_AGINO_TO_INO(args.mp, agno, rec.ir_startino), rec.ir_holemask, rec.ir_count); xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE); } if (error) return error; /* * We can't merge the part we've just allocated as for the inobt * due to finobt semantics. The original record may or may not * exist independent of whether physical inodes exist in this * sparse chunk. * * We must update the finobt record based on the inobt record. * rec contains the fully merged and up to date inobt record * from the previous call. Set merge false to replace any * existing record with this one. */ if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_FINO, &rec, false); if (error) return error; } } else { /* full chunk - insert new records to both btrees */ error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, XFS_BTNUM_INO); if (error) return error; if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, XFS_BTNUM_FINO); if (error) return error; } } /* * Update AGI counts and newino. */ be32_add_cpu(&agi->agi_count, newlen); be32_add_cpu(&agi->agi_freecount, newlen); pag = xfs_perag_get(args.mp, agno); pag->pagi_freecount += newlen; pag->pagi_count += newlen; xfs_perag_put(pag); agi->agi_newino = cpu_to_be32(newino); /* * Log allocation group header fields */ xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT | XFS_AGI_NEWINO); /* * Modify/log superblock values for inode count and inode free count. */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); *alloc = 1; return 0; } STATIC xfs_agnumber_t xfs_ialloc_next_ag( xfs_mount_t *mp) { xfs_agnumber_t agno; spin_lock(&mp->m_agirotor_lock); agno = mp->m_agirotor; if (++mp->m_agirotor >= mp->m_maxagi) mp->m_agirotor = 0; spin_unlock(&mp->m_agirotor_lock); return agno; } /* * Select an allocation group to look for a free inode in, based on the parent * inode and the mode. Return the allocation group buffer. */ STATIC xfs_agnumber_t xfs_ialloc_ag_select( xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t parent, /* parent directory inode number */ umode_t mode) /* bits set to indicate file type */ { xfs_agnumber_t agcount; /* number of ag's in the filesystem */ xfs_agnumber_t agno; /* current ag number */ int flags; /* alloc buffer locking flags */ xfs_extlen_t ineed; /* blocks needed for inode allocation */ xfs_extlen_t longest = 0; /* longest extent available */ xfs_mount_t *mp; /* mount point structure */ int needspace; /* file mode implies space allocated */ xfs_perag_t *pag; /* per allocation group data */ xfs_agnumber_t pagno; /* parent (starting) ag number */ int error; /* * Files of these types need at least one block if length > 0 * (and they won't fit in the inode, but that's hard to figure out). */ needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); mp = tp->t_mountp; agcount = mp->m_maxagi; if (S_ISDIR(mode)) pagno = xfs_ialloc_next_ag(mp); else { pagno = XFS_INO_TO_AGNO(mp, parent); if (pagno >= agcount) pagno = 0; } ASSERT(pagno < agcount); /* * Loop through allocation groups, looking for one with a little * free space in it. Note we don't look for free inodes, exactly. * Instead, we include whether there is a need to allocate inodes * to mean that blocks must be allocated for them, * if none are currently free. */ agno = pagno; flags = XFS_ALLOC_FLAG_TRYLOCK; for (;;) { pag = xfs_perag_get(mp, agno); if (!pag->pagi_inodeok) { xfs_ialloc_next_ag(mp); goto nextag; } if (!pag->pagi_init) { error = xfs_ialloc_pagi_init(mp, tp, agno); if (error) goto nextag; } if (pag->pagi_freecount) { xfs_perag_put(pag); return agno; } if (!pag->pagf_init) { error = xfs_alloc_pagf_init(mp, tp, agno, flags); if (error) goto nextag; } /* * Check that there is enough free space for the file plus a * chunk of inodes if we need to allocate some. If this is the * first pass across the AGs, take into account the potential * space needed for alignment of inode chunks when checking the * longest contiguous free space in the AG - this prevents us * from getting ENOSPC because we have free space larger than * ialloc_blks but alignment constraints prevent us from using * it. * * If we can't find an AG with space for full alignment slack to * be taken into account, we must be near ENOSPC in all AGs. * Hence we don't include alignment for the second pass and so * if we fail allocation due to alignment issues then it is most * likely a real ENOSPC condition. */ ineed = M_IGEO(mp)->ialloc_min_blks; if (flags && ineed > 1) ineed += M_IGEO(mp)->cluster_align; longest = pag->pagf_longest; if (!longest) longest = pag->pagf_flcount > 0; if (pag->pagf_freeblks >= needspace + ineed && longest >= ineed) { xfs_perag_put(pag); return agno; } nextag: xfs_perag_put(pag); /* * No point in iterating over the rest, if we're shutting * down. */ if (XFS_FORCED_SHUTDOWN(mp)) return NULLAGNUMBER; agno++; if (agno >= agcount) agno = 0; if (agno == pagno) { if (flags == 0) return NULLAGNUMBER; flags = 0; } } } /* * Try to retrieve the next record to the left/right from the current one. */ STATIC int xfs_ialloc_next_rec( struct xfs_btree_cur *cur, xfs_inobt_rec_incore_t *rec, int *done, int left) { int error; int i; if (left) error = xfs_btree_decrement(cur, 0, &i); else error = xfs_btree_increment(cur, 0, &i); if (error) return error; *done = !i; if (i) { error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); } return 0; } STATIC int xfs_ialloc_get_rec( struct xfs_btree_cur *cur, xfs_agino_t agino, xfs_inobt_rec_incore_t *rec, int *done) { int error; int i; error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_EQ, &i); if (error) return error; *done = !i; if (i) { error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); } return 0; } /* * Return the offset of the first free inode in the record. If the inode chunk * is sparsely allocated, we convert the record holemask to inode granularity * and mask off the unallocated regions from the inode free mask. */ STATIC int xfs_inobt_first_free_inode( struct xfs_inobt_rec_incore *rec) { xfs_inofree_t realfree; /* if there are no holes, return the first available offset */ if (!xfs_inobt_issparse(rec->ir_holemask)) return xfs_lowbit64(rec->ir_free); realfree = xfs_inobt_irec_to_allocmask(rec); realfree &= rec->ir_free; return xfs_lowbit64(realfree); } /* * Allocate an inode using the inobt-only algorithm. */ STATIC int xfs_dialloc_ag_inobt( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_ino_t parent, xfs_ino_t *inop) { struct xfs_mount *mp = tp->t_mountp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); struct xfs_perag *pag; struct xfs_btree_cur *cur, *tcur; struct xfs_inobt_rec_incore rec, trec; xfs_ino_t ino; int error; int offset; int i, j; int searchdistance = 10; pag = xfs_perag_get(mp, agno); ASSERT(pag->pagi_init); ASSERT(pag->pagi_inodeok); ASSERT(pag->pagi_freecount > 0); restart_pagno: cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); /* * If pagino is 0 (this is the root inode allocation) use newino. * This must work because we've just allocated some. */ if (!pagino) pagino = be32_to_cpu(agi->agi_newino); error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; /* * If in the same AG as the parent, try to get near the parent. */ if (pagno == agno) { int doneleft; /* done, to the left */ int doneright; /* done, to the right */ error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); error = xfs_inobt_get_rec(cur, &rec, &j); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, j == 1, error0); if (rec.ir_freecount > 0) { /* * Found a free inode in the same chunk * as the parent, done. */ goto alloc_inode; } /* * In the same AG as parent, but parent's chunk is full. */ /* duplicate the cursor, search left & right simultaneously */ error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; /* * Skip to last blocks looked up if same parent inode. */ if (pagino != NULLAGINO && pag->pagl_pagino == pagino && pag->pagl_leftrec != NULLAGINO && pag->pagl_rightrec != NULLAGINO) { error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, &trec, &doneleft); if (error) goto error1; error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, &rec, &doneright); if (error) goto error1; } else { /* search left with tcur, back up 1 record */ error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); if (error) goto error1; /* search right with cur, go forward 1 record. */ error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); if (error) goto error1; } /* * Loop until we find an inode chunk with a free inode. */ while (--searchdistance > 0 && (!doneleft || !doneright)) { int useleft; /* using left inode chunk this time */ /* figure out the closer block if both are valid. */ if (!doneleft && !doneright) { useleft = pagino - (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) < rec.ir_startino - pagino; } else { useleft = !doneleft; } /* free inodes to the left? */ if (useleft && trec.ir_freecount) { xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); cur = tcur; pag->pagl_leftrec = trec.ir_startino; pag->pagl_rightrec = rec.ir_startino; pag->pagl_pagino = pagino; rec = trec; goto alloc_inode; } /* free inodes to the right? */ if (!useleft && rec.ir_freecount) { xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); pag->pagl_leftrec = trec.ir_startino; pag->pagl_rightrec = rec.ir_startino; pag->pagl_pagino = pagino; goto alloc_inode; } /* get next record to check */ if (useleft) { error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); } else { error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); } if (error) goto error1; } if (searchdistance <= 0) { /* * Not in range - save last search * location and allocate a new inode */ xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); pag->pagl_leftrec = trec.ir_startino; pag->pagl_rightrec = rec.ir_startino; pag->pagl_pagino = pagino; } else { /* * We've reached the end of the btree. because * we are only searching a small chunk of the * btree each search, there is obviously free * inodes closer to the parent inode than we * are now. restart the search again. */ pag->pagl_pagino = NULLAGINO; pag->pagl_leftrec = NULLAGINO; pag->pagl_rightrec = NULLAGINO; xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); goto restart_pagno; } } /* * In a different AG from the parent. * See if the most recently allocated block has any free. */ if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), XFS_LOOKUP_EQ, &i); if (error) goto error0; if (i == 1) { error = xfs_inobt_get_rec(cur, &rec, &j); if (error) goto error0; if (j == 1 && rec.ir_freecount > 0) { /* * The last chunk allocated in the group * still has a free inode. */ goto alloc_inode; } } } /* * None left in the last group, search the whole AG */ error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); for (;;) { error = xfs_inobt_get_rec(cur, &rec, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if (rec.ir_freecount > 0) break; error = xfs_btree_increment(cur, 0, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); } alloc_inode: offset = xfs_inobt_first_free_inode(&rec); ASSERT(offset >= 0); ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % XFS_INODES_PER_CHUNK) == 0); ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_freecount--; error = xfs_inobt_update(cur, &rec); if (error) goto error0; be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); pag->pagi_freecount--; error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); xfs_perag_put(pag); *inop = ino; return 0; error1: xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); xfs_perag_put(pag); return error; } /* * Use the free inode btree to allocate an inode based on distance from the * parent. Note that the provided cursor may be deleted and replaced. */ STATIC int xfs_dialloc_ag_finobt_near( xfs_agino_t pagino, struct xfs_btree_cur **ocur, struct xfs_inobt_rec_incore *rec) { struct xfs_btree_cur *lcur = *ocur; /* left search cursor */ struct xfs_btree_cur *rcur; /* right search cursor */ struct xfs_inobt_rec_incore rrec; int error; int i, j; error = xfs_inobt_lookup(lcur, pagino, XFS_LOOKUP_LE, &i); if (error) return error; if (i == 1) { error = xfs_inobt_get_rec(lcur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(lcur->bc_mp, i == 1); /* * See if we've landed in the parent inode record. The finobt * only tracks chunks with at least one free inode, so record * existence is enough. */ if (pagino >= rec->ir_startino && pagino < (rec->ir_startino + XFS_INODES_PER_CHUNK)) return 0; } error = xfs_btree_dup_cursor(lcur, &rcur); if (error) return error; error = xfs_inobt_lookup(rcur, pagino, XFS_LOOKUP_GE, &j); if (error) goto error_rcur; if (j == 1) { error = xfs_inobt_get_rec(rcur, &rrec, &j); if (error) goto error_rcur; XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, j == 1, error_rcur); } XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, i == 1 || j == 1, error_rcur); if (i == 1 && j == 1) { /* * Both the left and right records are valid. Choose the closer * inode chunk to the target. */ if ((pagino - rec->ir_startino + XFS_INODES_PER_CHUNK - 1) > (rrec.ir_startino - pagino)) { *rec = rrec; xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); *ocur = rcur; } else { xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); } } else if (j == 1) { /* only the right record is valid */ *rec = rrec; xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); *ocur = rcur; } else if (i == 1) { /* only the left record is valid */ xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); } return 0; error_rcur: xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR); return error; } /* * Use the free inode btree to find a free inode based on a newino hint. If * the hint is NULL, find the first free inode in the AG. */ STATIC int xfs_dialloc_ag_finobt_newino( struct xfs_agi *agi, struct xfs_btree_cur *cur, struct xfs_inobt_rec_incore *rec) { int error; int i; if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), XFS_LOOKUP_EQ, &i); if (error) return error; if (i == 1) { error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); return 0; } } /* * Find the first inode available in the AG. */ error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); return 0; } /* * Update the inobt based on a modification made to the finobt. Also ensure that * the records from both trees are equivalent post-modification. */ STATIC int xfs_dialloc_ag_update_inobt( struct xfs_btree_cur *cur, /* inobt cursor */ struct xfs_inobt_rec_incore *frec, /* finobt record */ int offset) /* inode offset */ { struct xfs_inobt_rec_incore rec; int error; int i; error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); error = xfs_inobt_get_rec(cur, &rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) % XFS_INODES_PER_CHUNK) == 0); rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_freecount--; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, (rec.ir_free == frec->ir_free) && (rec.ir_freecount == frec->ir_freecount)); return xfs_inobt_update(cur, &rec); } /* * Allocate an inode using the free inode btree, if available. Otherwise, fall * back to the inobt search algorithm. * * The caller selected an AG for us, and made sure that free inodes are * available. */ STATIC int xfs_dialloc_ag( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_ino_t parent, xfs_ino_t *inop) { struct xfs_mount *mp = tp->t_mountp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); struct xfs_perag *pag; struct xfs_btree_cur *cur; /* finobt cursor */ struct xfs_btree_cur *icur; /* inobt cursor */ struct xfs_inobt_rec_incore rec; xfs_ino_t ino; int error; int offset; int i; if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return xfs_dialloc_ag_inobt(tp, agbp, parent, inop); pag = xfs_perag_get(mp, agno); /* * If pagino is 0 (this is the root inode allocation) use newino. * This must work because we've just allocated some. */ if (!pagino) pagino = be32_to_cpu(agi->agi_newino); cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); error = xfs_check_agi_freecount(cur, agi); if (error) goto error_cur; /* * The search algorithm depends on whether we're in the same AG as the * parent. If so, find the closest available inode to the parent. If * not, consider the agi hint or find the first free inode in the AG. */ if (agno == pagno) error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec); else error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec); if (error) goto error_cur; offset = xfs_inobt_first_free_inode(&rec); ASSERT(offset >= 0); ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % XFS_INODES_PER_CHUNK) == 0); ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); /* * Modify or remove the finobt record. */ rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_freecount--; if (rec.ir_freecount) error = xfs_inobt_update(cur, &rec); else error = xfs_btree_delete(cur, &i); if (error) goto error_cur; /* * The finobt has now been updated appropriately. We haven't updated the * agi and superblock yet, so we can create an inobt cursor and validate * the original freecount. If all is well, make the equivalent update to * the inobt using the finobt record and offset information. */ icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_check_agi_freecount(icur, agi); if (error) goto error_icur; error = xfs_dialloc_ag_update_inobt(icur, &rec, offset); if (error) goto error_icur; /* * Both trees have now been updated. We must update the perag and * superblock before we can check the freecount for each btree. */ be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); pag->pagi_freecount--; xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); error = xfs_check_agi_freecount(icur, agi); if (error) goto error_icur; error = xfs_check_agi_freecount(cur, agi); if (error) goto error_icur; xfs_btree_del_cursor(icur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_perag_put(pag); *inop = ino; return 0; error_icur: xfs_btree_del_cursor(icur, XFS_BTREE_ERROR); error_cur: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); xfs_perag_put(pag); return error; } /* * Allocate an inode on disk. * * Mode is used to tell whether the new inode will need space, and whether it * is a directory. * * This function is designed to be called twice if it has to do an allocation * to make more free inodes. On the first call, *IO_agbp should be set to NULL. * If an inode is available without having to performn an allocation, an inode * number is returned. In this case, *IO_agbp is set to NULL. If an allocation * needs to be done, xfs_dialloc returns the current AGI buffer in *IO_agbp. * The caller should then commit the current transaction, allocate a * new transaction, and call xfs_dialloc() again, passing in the previous value * of *IO_agbp. IO_agbp should be held across the transactions. Since the AGI * buffer is locked across the two calls, the second call is guaranteed to have * a free inode available. * * Once we successfully pick an inode its number is returned and the on-disk * data structures are updated. The inode itself is not read in, since doing so * would break ordering constraints with xfs_reclaim. */ int xfs_dialloc( struct xfs_trans *tp, xfs_ino_t parent, umode_t mode, struct xfs_buf **IO_agbp, xfs_ino_t *inop) { struct xfs_mount *mp = tp->t_mountp; struct xfs_buf *agbp; xfs_agnumber_t agno; int error; int ialloced; int noroom = 0; xfs_agnumber_t start_agno; struct xfs_perag *pag; struct xfs_ino_geometry *igeo = M_IGEO(mp); int okalloc = 1; if (*IO_agbp) { /* * If the caller passes in a pointer to the AGI buffer, * continue where we left off before. In this case, we * know that the allocation group has free inodes. */ agbp = *IO_agbp; goto out_alloc; } /* * We do not have an agbp, so select an initial allocation * group for inode allocation. */ start_agno = xfs_ialloc_ag_select(tp, parent, mode); if (start_agno == NULLAGNUMBER) { *inop = NULLFSINO; return 0; } /* * If we have already hit the ceiling of inode blocks then clear * okalloc so we scan all available agi structures for a free * inode. * * Read rough value of mp->m_icount by percpu_counter_read_positive, * which will sacrifice the preciseness but improve the performance. */ if (igeo->maxicount && percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos > igeo->maxicount) { noroom = 1; okalloc = 0; } /* * Loop until we find an allocation group that either has free inodes * or in which we can allocate some inodes. Iterate through the * allocation groups upward, wrapping at the end. */ agno = start_agno; for (;;) { pag = xfs_perag_get(mp, agno); if (!pag->pagi_inodeok) { xfs_ialloc_next_ag(mp); goto nextag; } if (!pag->pagi_init) { error = xfs_ialloc_pagi_init(mp, tp, agno); if (error) goto out_error; } /* * Do a first racy fast path check if this AG is usable. */ if (!pag->pagi_freecount && !okalloc) goto nextag; /* * Then read in the AGI buffer and recheck with the AGI buffer * lock held. */ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) goto out_error; if (pag->pagi_freecount) { xfs_perag_put(pag); goto out_alloc; } if (!okalloc) goto nextag_relse_buffer; error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); if (error) { xfs_trans_brelse(tp, agbp); if (error != -ENOSPC) goto out_error; xfs_perag_put(pag); *inop = NULLFSINO; return 0; } if (ialloced) { /* * We successfully allocated some inodes, return * the current context to the caller so that it * can commit the current transaction and call * us again where we left off. */ ASSERT(pag->pagi_freecount > 0); xfs_perag_put(pag); *IO_agbp = agbp; *inop = NULLFSINO; return 0; } nextag_relse_buffer: xfs_trans_brelse(tp, agbp); nextag: xfs_perag_put(pag); if (++agno == mp->m_sb.sb_agcount) agno = 0; if (agno == start_agno) { *inop = NULLFSINO; return noroom ? -ENOSPC : 0; } } out_alloc: *IO_agbp = NULL; return xfs_dialloc_ag(tp, agbp, parent, inop); out_error: xfs_perag_put(pag); return error; } /* * Free the blocks of an inode chunk. We must consider that the inode chunk * might be sparse and only free the regions that are allocated as part of the * chunk. */ STATIC void xfs_difree_inode_chunk( struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_inobt_rec_incore *rec) { struct xfs_mount *mp = tp->t_mountp; xfs_agblock_t sagbno = XFS_AGINO_TO_AGBNO(mp, rec->ir_startino); int startidx, endidx; int nextbit; xfs_agblock_t agbno; int contigblk; DECLARE_BITMAP(holemask, XFS_INOBT_HOLEMASK_BITS); if (!xfs_inobt_issparse(rec->ir_holemask)) { /* not sparse, calculate extent info directly */ xfs_bmap_add_free(tp, XFS_AGB_TO_FSB(mp, agno, sagbno), M_IGEO(mp)->ialloc_blks, &XFS_RMAP_OINFO_INODES); return; } /* holemask is only 16-bits (fits in an unsigned long) */ ASSERT(sizeof(rec->ir_holemask) <= sizeof(holemask[0])); holemask[0] = rec->ir_holemask; /* * Find contiguous ranges of zeroes (i.e., allocated regions) in the * holemask and convert the start/end index of each range to an extent. * We start with the start and end index both pointing at the first 0 in * the mask. */ startidx = endidx = find_first_zero_bit(holemask, XFS_INOBT_HOLEMASK_BITS); nextbit = startidx + 1; while (startidx < XFS_INOBT_HOLEMASK_BITS) { nextbit = find_next_zero_bit(holemask, XFS_INOBT_HOLEMASK_BITS, nextbit); /* * If the next zero bit is contiguous, update the end index of * the current range and continue. */ if (nextbit != XFS_INOBT_HOLEMASK_BITS && nextbit == endidx + 1) { endidx = nextbit; goto next; } /* * nextbit is not contiguous with the current end index. Convert * the current start/end to an extent and add it to the free * list. */ agbno = sagbno + (startidx * XFS_INODES_PER_HOLEMASK_BIT) / mp->m_sb.sb_inopblock; contigblk = ((endidx - startidx + 1) * XFS_INODES_PER_HOLEMASK_BIT) / mp->m_sb.sb_inopblock; ASSERT(agbno % mp->m_sb.sb_spino_align == 0); ASSERT(contigblk % mp->m_sb.sb_spino_align == 0); xfs_bmap_add_free(tp, XFS_AGB_TO_FSB(mp, agno, agbno), contigblk, &XFS_RMAP_OINFO_INODES); /* reset range to current bit and carry on... */ startidx = endidx = nextbit; next: nextbit++; } } STATIC int xfs_difree_inobt( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agino_t agino, struct xfs_icluster *xic, struct xfs_inobt_rec_incore *orec) { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); struct xfs_perag *pag; struct xfs_btree_cur *cur; struct xfs_inobt_rec_incore rec; int ilen; int error; int i; int off; ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length)); /* * Initialize the cursor. */ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; /* * Look for the entry describing this inode. */ if ((error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i))) { xfs_warn(mp, "%s: xfs_inobt_lookup() returned error %d.", __func__, error); goto error0; } XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); error = xfs_inobt_get_rec(cur, &rec, &i); if (error) { xfs_warn(mp, "%s: xfs_inobt_get_rec() returned error %d.", __func__, error); goto error0; } XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Get the offset in the inode chunk. */ off = agino - rec.ir_startino; ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK); ASSERT(!(rec.ir_free & XFS_INOBT_MASK(off))); /* * Mark the inode free & increment the count. */ rec.ir_free |= XFS_INOBT_MASK(off); rec.ir_freecount++; /* * When an inode chunk is free, it becomes eligible for removal. Don't * remove the chunk if the block size is large enough for multiple inode * chunks (that might not be free). */ if (!(mp->m_flags & XFS_MOUNT_IKEEP) && rec.ir_free == XFS_INOBT_ALL_FREE && mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK) { xic->deleted = true; xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); xic->alloc = xfs_inobt_irec_to_allocmask(&rec); /* * Remove the inode cluster from the AGI B+Tree, adjust the * AGI and Superblock inode counts, and mark the disk space * to be freed when the transaction is committed. */ ilen = rec.ir_freecount; be32_add_cpu(&agi->agi_count, -ilen); be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); pag = xfs_perag_get(mp, agno); pag->pagi_freecount -= ilen - 1; pag->pagi_count -= ilen; xfs_perag_put(pag); xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); if ((error = xfs_btree_delete(cur, &i))) { xfs_warn(mp, "%s: xfs_btree_delete returned error %d.", __func__, error); goto error0; } xfs_difree_inode_chunk(tp, agno, &rec); } else { xic->deleted = false; error = xfs_inobt_update(cur, &rec); if (error) { xfs_warn(mp, "%s: xfs_inobt_update returned error %d.", __func__, error); goto error0; } /* * Change the inode free counts and log the ag/sb changes. */ be32_add_cpu(&agi->agi_freecount, 1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); pag = xfs_perag_get(mp, agno); pag->pagi_freecount++; xfs_perag_put(pag); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); } error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; *orec = rec; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Free an inode in the free inode btree. */ STATIC int xfs_difree_finobt( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agino_t agino, struct xfs_inobt_rec_incore *ibtrec) /* inobt record */ { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); struct xfs_btree_cur *cur; struct xfs_inobt_rec_incore rec; int offset = agino - ibtrec->ir_startino; int error; int i; cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i); if (error) goto error; if (i == 0) { /* * If the record does not exist in the finobt, we must have just * freed an inode in a previously fully allocated chunk. If not, * something is out of sync. */ XFS_WANT_CORRUPTED_GOTO(mp, ibtrec->ir_freecount == 1, error); error = xfs_inobt_insert_rec(cur, ibtrec->ir_holemask, ibtrec->ir_count, ibtrec->ir_freecount, ibtrec->ir_free, &i); if (error) goto error; ASSERT(i == 1); goto out; } /* * Read and update the existing record. We could just copy the ibtrec * across here, but that would defeat the purpose of having redundant * metadata. By making the modifications independently, we can catch * corruptions that we wouldn't see if we just copied from one record * to another. */ error = xfs_inobt_get_rec(cur, &rec, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); rec.ir_free |= XFS_INOBT_MASK(offset); rec.ir_freecount++; XFS_WANT_CORRUPTED_GOTO(mp, (rec.ir_free == ibtrec->ir_free) && (rec.ir_freecount == ibtrec->ir_freecount), error); /* * The content of inobt records should always match between the inobt * and finobt. The lifecycle of records in the finobt is different from * the inobt in that the finobt only tracks records with at least one * free inode. Hence, if all of the inodes are free and we aren't * keeping inode chunks permanently on disk, remove the record. * Otherwise, update the record with the new information. * * Note that we currently can't free chunks when the block size is large * enough for multiple chunks. Leave the finobt record to remain in sync * with the inobt. */ if (rec.ir_free == XFS_INOBT_ALL_FREE && mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && !(mp->m_flags & XFS_MOUNT_IKEEP)) { error = xfs_btree_delete(cur, &i); if (error) goto error; ASSERT(i == 1); } else { error = xfs_inobt_update(cur, &rec); if (error) goto error; } out: error = xfs_check_agi_freecount(cur, agi); if (error) goto error; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; error: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Free disk inode. Carefully avoids touching the incore inode, all * manipulations incore are the caller's responsibility. * The on-disk inode is not changed by this operation, only the * btree (free inode mask) is changed. */ int xfs_difree( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t inode, /* inode to be freed */ struct xfs_icluster *xic) /* cluster info if deleted */ { /* REFERENCED */ xfs_agblock_t agbno; /* block number containing inode */ struct xfs_buf *agbp; /* buffer for allocation group header */ xfs_agino_t agino; /* allocation group inode number */ xfs_agnumber_t agno; /* allocation group number */ int error; /* error return value */ struct xfs_mount *mp; /* mount structure for filesystem */ struct xfs_inobt_rec_incore rec;/* btree record */ mp = tp->t_mountp; /* * Break up inode number into its components. */ agno = XFS_INO_TO_AGNO(mp, inode); if (agno >= mp->m_sb.sb_agcount) { xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).", __func__, agno, mp->m_sb.sb_agcount); ASSERT(0); return -EINVAL; } agino = XFS_INO_TO_AGINO(mp, inode); if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).", __func__, (unsigned long long)inode, (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino)); ASSERT(0); return -EINVAL; } agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agbno >= mp->m_sb.sb_agblocks) { xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).", __func__, agbno, mp->m_sb.sb_agblocks); ASSERT(0); return -EINVAL; } /* * Get the allocation group header. */ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) { xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.", __func__, error); return error; } /* * Fix up the inode allocation btree. */ error = xfs_difree_inobt(mp, tp, agbp, agino, xic, &rec); if (error) goto error0; /* * Fix up the free inode btree. */ if (xfs_sb_version_hasfinobt(&mp->m_sb)) { error = xfs_difree_finobt(mp, tp, agbp, agino, &rec); if (error) goto error0; } return 0; error0: return error; } STATIC int xfs_imap_lookup( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agino_t agino, xfs_agblock_t agbno, xfs_agblock_t *chunk_agbno, xfs_agblock_t *offset_agbno, int flags) { struct xfs_inobt_rec_incore rec; struct xfs_btree_cur *cur; struct xfs_buf *agbp; int error; int i; error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) { xfs_alert(mp, "%s: xfs_ialloc_read_agi() returned error %d, agno %d", __func__, error, agno); return error; } /* * Lookup the inode record for the given agino. If the record cannot be * found, then it's an invalid inode number and we should abort. Once * we have a record, we need to ensure it contains the inode number * we are looking up. */ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); if (!error) { if (i) error = xfs_inobt_get_rec(cur, &rec, &i); if (!error && i == 0) error = -EINVAL; } xfs_trans_brelse(tp, agbp); xfs_btree_del_cursor(cur, error); if (error) return error; /* check that the returned record contains the required inode */ if (rec.ir_startino > agino || rec.ir_startino + M_IGEO(mp)->ialloc_inos <= agino) return -EINVAL; /* for untrusted inodes check it is allocated first */ if ((flags & XFS_IGET_UNTRUSTED) && (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))) return -EINVAL; *chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino); *offset_agbno = agbno - *chunk_agbno; return 0; } /* * Return the location of the inode in imap, for mapping it into a buffer. */ int xfs_imap( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t ino, /* inode to locate */ struct xfs_imap *imap, /* location map structure */ uint flags) /* flags for inode btree lookup */ { xfs_agblock_t agbno; /* block number of inode in the alloc group */ xfs_agino_t agino; /* inode number within alloc group */ xfs_agnumber_t agno; /* allocation group number */ xfs_agblock_t chunk_agbno; /* first block in inode chunk */ xfs_agblock_t cluster_agbno; /* first block in inode cluster */ int error; /* error code */ int offset; /* index of inode in its buffer */ xfs_agblock_t offset_agbno; /* blks from chunk start to inode */ ASSERT(ino != NULLFSINO); /* * Split up the inode number into its parts. */ agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || ino != XFS_AGINO_TO_INO(mp, agno, agino)) { #ifdef DEBUG /* * Don't output diagnostic information for untrusted inodes * as they can be invalid without implying corruption. */ if (flags & XFS_IGET_UNTRUSTED) return -EINVAL; if (agno >= mp->m_sb.sb_agcount) { xfs_alert(mp, "%s: agno (%d) >= mp->m_sb.sb_agcount (%d)", __func__, agno, mp->m_sb.sb_agcount); } if (agbno >= mp->m_sb.sb_agblocks) { xfs_alert(mp, "%s: agbno (0x%llx) >= mp->m_sb.sb_agblocks (0x%lx)", __func__, (unsigned long long)agbno, (unsigned long)mp->m_sb.sb_agblocks); } if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { xfs_alert(mp, "%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)", __func__, ino, XFS_AGINO_TO_INO(mp, agno, agino)); } xfs_stack_trace(); #endif /* DEBUG */ return -EINVAL; } /* * For bulkstat and handle lookups, we have an untrusted inode number * that we have to verify is valid. We cannot do this just by reading * the inode buffer as it may have been unlinked and removed leaving * inodes in stale state on disk. Hence we have to do a btree lookup * in all cases where an untrusted inode number is passed. */ if (flags & XFS_IGET_UNTRUSTED) { error = xfs_imap_lookup(mp, tp, agno, agino, agbno, &chunk_agbno, &offset_agbno, flags); if (error) return error; goto out_map; } /* * If the inode cluster size is the same as the blocksize or * smaller we get to the buffer by simple arithmetics. */ if (M_IGEO(mp)->blocks_per_cluster == 1) { offset = XFS_INO_TO_OFFSET(mp, ino); ASSERT(offset < mp->m_sb.sb_inopblock); imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno); imap->im_len = XFS_FSB_TO_BB(mp, 1); imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog); return 0; } /* * If the inode chunks are aligned then use simple maths to * find the location. Otherwise we have to do a btree * lookup to find the location. */ if (M_IGEO(mp)->inoalign_mask) { offset_agbno = agbno & M_IGEO(mp)->inoalign_mask; chunk_agbno = agbno - offset_agbno; } else { error = xfs_imap_lookup(mp, tp, agno, agino, agbno, &chunk_agbno, &offset_agbno, flags); if (error) return error; } out_map: ASSERT(agbno >= chunk_agbno); cluster_agbno = chunk_agbno + ((offset_agbno / M_IGEO(mp)->blocks_per_cluster) * M_IGEO(mp)->blocks_per_cluster); offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + XFS_INO_TO_OFFSET(mp, ino); imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno); imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster); imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog); /* * If the inode number maps to a block outside the bounds * of the file system then return NULL rather than calling * read_buf and panicing when we get an error from the * driver. */ if ((imap->im_blkno + imap->im_len) > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { xfs_alert(mp, "%s: (im_blkno (0x%llx) + im_len (0x%llx)) > sb_dblocks (0x%llx)", __func__, (unsigned long long) imap->im_blkno, (unsigned long long) imap->im_len, XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); return -EINVAL; } return 0; } /* * Log specified fields for the ag hdr (inode section). The growth of the agi * structure over time requires that we interpret the buffer as two logical * regions delineated by the end of the unlinked list. This is due to the size * of the hash table and its location in the middle of the agi. * * For example, a request to log a field before agi_unlinked and a field after * agi_unlinked could cause us to log the entire hash table and use an excessive * amount of log space. To avoid this behavior, log the region up through * agi_unlinked in one call and the region after agi_unlinked through the end of * the structure in another. */ void xfs_ialloc_log_agi( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *bp, /* allocation group header buffer */ int fields) /* bitmask of fields to log */ { int first; /* first byte number */ int last; /* last byte number */ static const short offsets[] = { /* field starting offsets */ /* keep in sync with bit definitions */ offsetof(xfs_agi_t, agi_magicnum), offsetof(xfs_agi_t, agi_versionnum), offsetof(xfs_agi_t, agi_seqno), offsetof(xfs_agi_t, agi_length), offsetof(xfs_agi_t, agi_count), offsetof(xfs_agi_t, agi_root), offsetof(xfs_agi_t, agi_level), offsetof(xfs_agi_t, agi_freecount), offsetof(xfs_agi_t, agi_newino), offsetof(xfs_agi_t, agi_dirino), offsetof(xfs_agi_t, agi_unlinked), offsetof(xfs_agi_t, agi_free_root), offsetof(xfs_agi_t, agi_free_level), sizeof(xfs_agi_t) }; #ifdef DEBUG xfs_agi_t *agi; /* allocation group header */ agi = XFS_BUF_TO_AGI(bp); ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); #endif /* * Compute byte offsets for the first and last fields in the first * region and log the agi buffer. This only logs up through * agi_unlinked. */ if (fields & XFS_AGI_ALL_BITS_R1) { xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1, &first, &last); xfs_trans_log_buf(tp, bp, first, last); } /* * Mask off the bits in the first region and calculate the first and * last field offsets for any bits in the second region. */ fields &= ~XFS_AGI_ALL_BITS_R1; if (fields) { xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2, &first, &last); xfs_trans_log_buf(tp, bp, first, last); } } static xfs_failaddr_t xfs_agi_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); int i; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGI(bp)->agi_lsn))) return __this_address; } /* * Validate the magic number of the agi block. */ if (!xfs_verify_magic(bp, agi->agi_magicnum)) return __this_address; if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) return __this_address; if (be32_to_cpu(agi->agi_level) < 1 || be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS) return __this_address; if (xfs_sb_version_hasfinobt(&mp->m_sb) && (be32_to_cpu(agi->agi_free_level) < 1 || be32_to_cpu(agi->agi_free_level) > XFS_BTREE_MAXLEVELS)) return __this_address; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem. */ if (bp->b_pag && be32_to_cpu(agi->agi_seqno) != bp->b_pag->pag_agno) return __this_address; for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { if (agi->agi_unlinked[i] == cpu_to_be32(NULLAGINO)) continue; if (!xfs_verify_ino(mp, be32_to_cpu(agi->agi_unlinked[i]))) return __this_address; } return NULL; } static void xfs_agi_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_AGI_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_agi_verify(bp); if (XFS_TEST_ERROR(fa, mp, XFS_ERRTAG_IALLOC_READ_AGI)) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_agi_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; xfs_failaddr_t fa; fa = xfs_agi_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) XFS_BUF_TO_AGI(bp)->agi_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_AGI_CRC_OFF); } const struct xfs_buf_ops xfs_agi_buf_ops = { .name = "xfs_agi", .magic = { cpu_to_be32(XFS_AGI_MAGIC), cpu_to_be32(XFS_AGI_MAGIC) }, .verify_read = xfs_agi_read_verify, .verify_write = xfs_agi_write_verify, .verify_struct = xfs_agi_verify, }; /* * Read in the allocation group header (inode allocation section) */ int xfs_read_agi( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ struct xfs_buf **bpp) /* allocation group hdr buf */ { int error; trace_xfs_read_agi(mp, agno); ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops); if (error) return error; if (tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_AGI_BUF); xfs_buf_set_ref(*bpp, XFS_AGI_REF); return 0; } int xfs_ialloc_read_agi( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ struct xfs_buf **bpp) /* allocation group hdr buf */ { struct xfs_agi *agi; /* allocation group header */ struct xfs_perag *pag; /* per allocation group data */ int error; trace_xfs_ialloc_read_agi(mp, agno); error = xfs_read_agi(mp, tp, agno, bpp); if (error) return error; agi = XFS_BUF_TO_AGI(*bpp); pag = xfs_perag_get(mp, agno); if (!pag->pagi_init) { pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); pag->pagi_count = be32_to_cpu(agi->agi_count); pag->pagi_init = 1; } /* * It's possible for these to be out of sync if * we are in the middle of a forced shutdown. */ ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || XFS_FORCED_SHUTDOWN(mp)); xfs_perag_put(pag); return 0; } /* * Read in the agi to initialise the per-ag data in the mount structure */ int xfs_ialloc_pagi_init( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno) /* allocation group number */ { xfs_buf_t *bp = NULL; int error; error = xfs_ialloc_read_agi(mp, tp, agno, &bp); if (error) return error; if (bp) xfs_trans_brelse(tp, bp); return 0; } /* Is there an inode record covering a given range of inode numbers? */ int xfs_ialloc_has_inode_record( struct xfs_btree_cur *cur, xfs_agino_t low, xfs_agino_t high, bool *exists) { struct xfs_inobt_rec_incore irec; xfs_agino_t agino; uint16_t holemask; int has_record; int i; int error; *exists = false; error = xfs_inobt_lookup(cur, low, XFS_LOOKUP_LE, &has_record); while (error == 0 && has_record) { error = xfs_inobt_get_rec(cur, &irec, &has_record); if (error || irec.ir_startino > high) break; agino = irec.ir_startino; holemask = irec.ir_holemask; for (i = 0; i < XFS_INOBT_HOLEMASK_BITS; holemask >>= 1, i++, agino += XFS_INODES_PER_HOLEMASK_BIT) { if (holemask & 1) continue; if (agino + XFS_INODES_PER_HOLEMASK_BIT > low && agino <= high) { *exists = true; return 0; } } error = xfs_btree_increment(cur, 0, &has_record); } return error; } /* Is there an inode record covering a given extent? */ int xfs_ialloc_has_inodes_at_extent( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists) { xfs_agino_t low; xfs_agino_t high; low = XFS_AGB_TO_AGINO(cur->bc_mp, bno); high = XFS_AGB_TO_AGINO(cur->bc_mp, bno + len) - 1; return xfs_ialloc_has_inode_record(cur, low, high, exists); } struct xfs_ialloc_count_inodes { xfs_agino_t count; xfs_agino_t freecount; }; /* Record inode counts across all inobt records. */ STATIC int xfs_ialloc_count_inodes_rec( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, void *priv) { struct xfs_inobt_rec_incore irec; struct xfs_ialloc_count_inodes *ci = priv; xfs_inobt_btrec_to_irec(cur->bc_mp, rec, &irec); ci->count += irec.ir_count; ci->freecount += irec.ir_freecount; return 0; } /* Count allocated and free inodes under an inobt. */ int xfs_ialloc_count_inodes( struct xfs_btree_cur *cur, xfs_agino_t *count, xfs_agino_t *freecount) { struct xfs_ialloc_count_inodes ci = {0}; int error; ASSERT(cur->bc_btnum == XFS_BTNUM_INO); error = xfs_btree_query_all(cur, xfs_ialloc_count_inodes_rec, &ci); if (error) return error; *count = ci.count; *freecount = ci.freecount; return 0; } /* * Initialize inode-related geometry information. * * Compute the inode btree min and max levels and set maxicount. * * Set the inode cluster size. This may still be overridden by the file * system block size if it is larger than the chosen cluster size. * * For v5 filesystems, scale the cluster size with the inode size to keep a * constant ratio of inode per cluster buffer, but only if mkfs has set the * inode alignment value appropriately for larger cluster sizes. * * Then compute the inode cluster alignment information. */ void xfs_ialloc_setup_geometry( struct xfs_mount *mp) { struct xfs_sb *sbp = &mp->m_sb; struct xfs_ino_geometry *igeo = M_IGEO(mp); uint64_t icount; uint inodes; /* Compute inode btree geometry. */ igeo->agino_log = sbp->sb_inopblog + sbp->sb_agblklog; igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1); igeo->inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0); igeo->inobt_mnr[0] = igeo->inobt_mxr[0] / 2; igeo->inobt_mnr[1] = igeo->inobt_mxr[1] / 2; igeo->ialloc_inos = max_t(uint16_t, XFS_INODES_PER_CHUNK, sbp->sb_inopblock); igeo->ialloc_blks = igeo->ialloc_inos >> sbp->sb_inopblog; if (sbp->sb_spino_align) igeo->ialloc_min_blks = sbp->sb_spino_align; else igeo->ialloc_min_blks = igeo->ialloc_blks; /* Compute and fill in value of m_ino_geo.inobt_maxlevels. */ inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG; igeo->inobt_maxlevels = xfs_btree_compute_maxlevels(igeo->inobt_mnr, inodes); /* Set the maximum inode count for this filesystem. */ if (sbp->sb_imax_pct) { /* * Make sure the maximum inode count is a multiple * of the units we allocate inodes in. */ icount = sbp->sb_dblocks * sbp->sb_imax_pct; do_div(icount, 100); do_div(icount, igeo->ialloc_blks); igeo->maxicount = XFS_FSB_TO_INO(mp, icount * igeo->ialloc_blks); } else { igeo->maxicount = 0; } /* * Compute the desired size of an inode cluster buffer size, which * starts at 8K and (on v5 filesystems) scales up with larger inode * sizes. * * Preserve the desired inode cluster size because the sparse inodes * feature uses that desired size (not the actual size) to compute the * sparse inode alignment. The mount code validates this value, so we * cannot change the behavior. */ igeo->inode_cluster_size_raw = XFS_INODE_BIG_CLUSTER_SIZE; if (xfs_sb_version_hascrc(&mp->m_sb)) { int new_size = igeo->inode_cluster_size_raw; new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE; if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size)) igeo->inode_cluster_size_raw = new_size; } /* Calculate inode cluster ratios. */ if (igeo->inode_cluster_size_raw > mp->m_sb.sb_blocksize) igeo->blocks_per_cluster = XFS_B_TO_FSBT(mp, igeo->inode_cluster_size_raw); else igeo->blocks_per_cluster = 1; igeo->inode_cluster_size = XFS_FSB_TO_B(mp, igeo->blocks_per_cluster); igeo->inodes_per_cluster = XFS_FSB_TO_INO(mp, igeo->blocks_per_cluster); /* Calculate inode cluster alignment. */ if (xfs_sb_version_hasalign(&mp->m_sb) && mp->m_sb.sb_inoalignmt >= igeo->blocks_per_cluster) igeo->cluster_align = mp->m_sb.sb_inoalignmt; else igeo->cluster_align = 1; igeo->inoalign_mask = igeo->cluster_align - 1; igeo->cluster_align_inodes = XFS_FSB_TO_INO(mp, igeo->cluster_align); /* * If we are using stripe alignment, check whether * the stripe unit is a multiple of the inode alignment */ if (mp->m_dalign && igeo->inoalign_mask && !(mp->m_dalign & igeo->inoalign_mask)) igeo->ialloc_align = mp->m_dalign; else igeo->ialloc_align = 0; } xfsprogs-5.3.0/libxfs/xfs_ialloc.h0000644000175000017500000001206313570057155017041 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_IALLOC_H__ #define __XFS_IALLOC_H__ struct xfs_buf; struct xfs_dinode; struct xfs_imap; struct xfs_mount; struct xfs_trans; struct xfs_btree_cur; /* Move inodes in clusters of this size */ #define XFS_INODE_BIG_CLUSTER_SIZE 8192 struct xfs_icluster { bool deleted; /* record is deleted */ xfs_ino_t first_ino; /* first inode number */ uint64_t alloc; /* inode phys. allocation bitmap for * sparse chunks */ }; /* * Make an inode pointer out of the buffer/offset. */ static inline struct xfs_dinode * xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) { return xfs_buf_offset(b, o << (mp)->m_sb.sb_inodelog); } /* * Allocate an inode on disk. * Mode is used to tell whether the new inode will need space, and whether * it is a directory. * * To work within the constraint of one allocation per transaction, * xfs_dialloc() is designed to be called twice if it has to do an * allocation to make more free inodes. If an inode is * available without an allocation, agbp would be set to the current * agbp and alloc_done set to false. * If an allocation needed to be done, agbp would be set to the * inode header of the allocation group and alloc_done set to true. * The caller should then commit the current transaction and allocate a new * transaction. xfs_dialloc() should then be called again with * the agbp value returned from the previous call. * * Once we successfully pick an inode its number is returned and the * on-disk data structures are updated. The inode itself is not read * in, since doing so would break ordering constraints with xfs_reclaim. * * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. */ int /* error */ xfs_dialloc( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t parent, /* parent inode (directory) */ umode_t mode, /* mode bits for new inode */ struct xfs_buf **agbp, /* buf for a.g. inode header */ xfs_ino_t *inop); /* inode number allocated */ /* * Free disk inode. Carefully avoids touching the incore inode, all * manipulations incore are the caller's responsibility. * The on-disk inode is not changed by this operation, only the * btree (free inode mask) is changed. */ int /* error */ xfs_difree( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t inode, /* inode to be freed */ struct xfs_icluster *ifree); /* cluster info if deleted */ /* * Return the location of the inode in imap, for mapping it into a buffer. */ int xfs_imap( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t ino, /* inode to locate */ struct xfs_imap *imap, /* location map structure */ uint flags); /* flags for inode btree lookup */ /* * Log specified fields for the ag hdr (inode section) */ void xfs_ialloc_log_agi( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *bp, /* allocation group header buffer */ int fields); /* bitmask of fields to log */ /* * Read in the allocation group header (inode allocation section) */ int /* error */ xfs_ialloc_read_agi( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ struct xfs_buf **bpp); /* allocation group hdr buf */ /* * Read in the allocation group header to initialise the per-ag data * in the mount structure */ int xfs_ialloc_pagi_init( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno); /* allocation group number */ /* * Lookup a record by ino in the btree given by cur. */ int xfs_inobt_lookup(struct xfs_btree_cur *cur, xfs_agino_t ino, xfs_lookup_t dir, int *stat); /* * Get the data from the pointed-to record. */ int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_inobt_rec_incore_t *rec, int *stat); /* * Inode chunk initialisation routine */ int xfs_ialloc_inode_init(struct xfs_mount *mp, struct xfs_trans *tp, struct list_head *buffer_list, int icount, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t length, unsigned int gen); int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp); union xfs_btree_rec; void xfs_inobt_btrec_to_irec(struct xfs_mount *mp, union xfs_btree_rec *rec, struct xfs_inobt_rec_incore *irec); int xfs_ialloc_has_inodes_at_extent(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists); int xfs_ialloc_has_inode_record(struct xfs_btree_cur *cur, xfs_agino_t low, xfs_agino_t high, bool *exists); int xfs_ialloc_count_inodes(struct xfs_btree_cur *cur, xfs_agino_t *count, xfs_agino_t *freecount); int xfs_inobt_insert_rec(struct xfs_btree_cur *cur, uint16_t holemask, uint8_t count, int32_t freecount, xfs_inofree_t free, int *stat); int xfs_ialloc_cluster_alignment(struct xfs_mount *mp); void xfs_ialloc_setup_geometry(struct xfs_mount *mp); #endif /* __XFS_IALLOC_H__ */ xfsprogs-5.3.0/libxfs/xfs_ialloc_btree.c0000644000175000017500000003704513570057155020224 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_btree.h" #include "xfs_ialloc.h" #include "xfs_ialloc_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_rmap.h" STATIC int xfs_inobt_get_minrecs( struct xfs_btree_cur *cur, int level) { return M_IGEO(cur->bc_mp)->inobt_mnr[level != 0]; } STATIC struct xfs_btree_cur * xfs_inobt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agbp, cur->bc_private.a.agno, cur->bc_btnum); } STATIC void xfs_inobt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *nptr, int inc) /* level change */ { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); agi->agi_root = nptr->s; be32_add_cpu(&agi->agi_level, inc); xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); } STATIC void xfs_finobt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *nptr, int inc) /* level change */ { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); agi->agi_free_root = nptr->s; be32_add_cpu(&agi->agi_free_level, inc); xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL); } STATIC int __xfs_inobt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat, enum xfs_ag_resv_type resv) { xfs_alloc_arg_t args; /* block allocation args */ int error; /* error return value */ xfs_agblock_t sbno = be32_to_cpu(start->s); memset(&args, 0, sizeof(args)); args.tp = cur->bc_tp; args.mp = cur->bc_mp; args.oinfo = XFS_RMAP_OINFO_INOBT; args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno); args.minlen = 1; args.maxlen = 1; args.prod = 1; args.type = XFS_ALLOCTYPE_NEAR_BNO; args.resv = resv; error = xfs_alloc_vextent(&args); if (error) return error; if (args.fsbno == NULLFSBLOCK) { *stat = 0; return 0; } ASSERT(args.len == 1); new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno)); *stat = 1; return 0; } STATIC int xfs_inobt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { return __xfs_inobt_alloc_block(cur, start, new, stat, XFS_AG_RESV_NONE); } STATIC int xfs_finobt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { if (cur->bc_mp->m_finobt_nores) return xfs_inobt_alloc_block(cur, start, new, stat); return __xfs_inobt_alloc_block(cur, start, new, stat, XFS_AG_RESV_METADATA); } STATIC int __xfs_inobt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp, enum xfs_ag_resv_type resv) { return xfs_free_extent(cur->bc_tp, XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)), 1, &XFS_RMAP_OINFO_INOBT, resv); } STATIC int xfs_inobt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { return __xfs_inobt_free_block(cur, bp, XFS_AG_RESV_NONE); } STATIC int xfs_finobt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { if (cur->bc_mp->m_finobt_nores) return xfs_inobt_free_block(cur, bp); return __xfs_inobt_free_block(cur, bp, XFS_AG_RESV_METADATA); } STATIC int xfs_inobt_get_maxrecs( struct xfs_btree_cur *cur, int level) { return M_IGEO(cur->bc_mp)->inobt_mxr[level != 0]; } STATIC void xfs_inobt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->inobt.ir_startino = rec->inobt.ir_startino; } STATIC void xfs_inobt_init_high_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { __u32 x; x = be32_to_cpu(rec->inobt.ir_startino); x += XFS_INODES_PER_CHUNK - 1; key->inobt.ir_startino = cpu_to_be32(x); } STATIC void xfs_inobt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { rec->inobt.ir_u.sp.ir_holemask = cpu_to_be16(cur->bc_rec.i.ir_holemask); rec->inobt.ir_u.sp.ir_count = cur->bc_rec.i.ir_count; rec->inobt.ir_u.sp.ir_freecount = cur->bc_rec.i.ir_freecount; } else { /* ir_holemask/ir_count not supported on-disk */ rec->inobt.ir_u.f.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount); } rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); } /* * initial value of ptr for lookup */ STATIC void xfs_inobt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); ptr->s = agi->agi_root; } STATIC void xfs_finobt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); ptr->s = agi->agi_free_root; } STATIC int64_t xfs_inobt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { return (int64_t)be32_to_cpu(key->inobt.ir_startino) - cur->bc_rec.i.ir_startino; } STATIC int64_t xfs_inobt_diff_two_keys( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return (int64_t)be32_to_cpu(k1->inobt.ir_startino) - be32_to_cpu(k2->inobt.ir_startino); } static xfs_failaddr_t xfs_inobt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_failaddr_t fa; unsigned int level; if (!xfs_verify_magic(bp, block->bb_magic)) return __this_address; /* * During growfs operations, we can't verify the exact owner as the * perag is not fully initialised and hence not attached to the buffer. * * Similarly, during log recovery we will have a perag structure * attached, but the agi information will not yet have been initialised * from the on disk AGI. We don't currently use any of this information, * but beware of the landmine (i.e. need to check pag->pagi_init) if we * ever do. */ if (xfs_sb_version_hascrc(&mp->m_sb)) { fa = xfs_btree_sblock_v5hdr_verify(bp); if (fa) return fa; } /* level verification */ level = be16_to_cpu(block->bb_level); if (level >= M_IGEO(mp)->inobt_maxlevels) return __this_address; return xfs_btree_sblock_verify(bp, M_IGEO(mp)->inobt_mxr[level != 0]); } static void xfs_inobt_read_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; if (!xfs_btree_sblock_verify_crc(bp)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_inobt_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } if (bp->b_error) trace_xfs_btree_corrupt(bp, _RET_IP_); } static void xfs_inobt_write_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_inobt_verify(bp); if (fa) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } xfs_btree_sblock_calc_crc(bp); } const struct xfs_buf_ops xfs_inobt_buf_ops = { .name = "xfs_inobt", .magic = { cpu_to_be32(XFS_IBT_MAGIC), cpu_to_be32(XFS_IBT_CRC_MAGIC) }, .verify_read = xfs_inobt_read_verify, .verify_write = xfs_inobt_write_verify, .verify_struct = xfs_inobt_verify, }; const struct xfs_buf_ops xfs_finobt_buf_ops = { .name = "xfs_finobt", .magic = { cpu_to_be32(XFS_FIBT_MAGIC), cpu_to_be32(XFS_FIBT_CRC_MAGIC) }, .verify_read = xfs_inobt_read_verify, .verify_write = xfs_inobt_write_verify, .verify_struct = xfs_inobt_verify, }; STATIC int xfs_inobt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be32_to_cpu(k1->inobt.ir_startino) < be32_to_cpu(k2->inobt.ir_startino); } STATIC int xfs_inobt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <= be32_to_cpu(r2->inobt.ir_startino); } static const struct xfs_btree_ops xfs_inobt_ops = { .rec_len = sizeof(xfs_inobt_rec_t), .key_len = sizeof(xfs_inobt_key_t), .dup_cursor = xfs_inobt_dup_cursor, .set_root = xfs_inobt_set_root, .alloc_block = xfs_inobt_alloc_block, .free_block = xfs_inobt_free_block, .get_minrecs = xfs_inobt_get_minrecs, .get_maxrecs = xfs_inobt_get_maxrecs, .init_key_from_rec = xfs_inobt_init_key_from_rec, .init_high_key_from_rec = xfs_inobt_init_high_key_from_rec, .init_rec_from_cur = xfs_inobt_init_rec_from_cur, .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, .key_diff = xfs_inobt_key_diff, .buf_ops = &xfs_inobt_buf_ops, .diff_two_keys = xfs_inobt_diff_two_keys, .keys_inorder = xfs_inobt_keys_inorder, .recs_inorder = xfs_inobt_recs_inorder, }; static const struct xfs_btree_ops xfs_finobt_ops = { .rec_len = sizeof(xfs_inobt_rec_t), .key_len = sizeof(xfs_inobt_key_t), .dup_cursor = xfs_inobt_dup_cursor, .set_root = xfs_finobt_set_root, .alloc_block = xfs_finobt_alloc_block, .free_block = xfs_finobt_free_block, .get_minrecs = xfs_inobt_get_minrecs, .get_maxrecs = xfs_inobt_get_maxrecs, .init_key_from_rec = xfs_inobt_init_key_from_rec, .init_high_key_from_rec = xfs_inobt_init_high_key_from_rec, .init_rec_from_cur = xfs_inobt_init_rec_from_cur, .init_ptr_from_cur = xfs_finobt_init_ptr_from_cur, .key_diff = xfs_inobt_key_diff, .buf_ops = &xfs_finobt_buf_ops, .diff_two_keys = xfs_inobt_diff_two_keys, .keys_inorder = xfs_inobt_keys_inorder, .recs_inorder = xfs_inobt_recs_inorder, }; /* * Allocate a new inode btree cursor. */ struct xfs_btree_cur * /* new inode btree cursor */ xfs_inobt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for agi structure */ xfs_agnumber_t agno, /* allocation group number */ xfs_btnum_t btnum) /* ialloc or free ino btree */ { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); struct xfs_btree_cur *cur; cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_btnum = btnum; if (btnum == XFS_BTNUM_INO) { cur->bc_nlevels = be32_to_cpu(agi->agi_level); cur->bc_ops = &xfs_inobt_ops; cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_ibt_2); } else { cur->bc_nlevels = be32_to_cpu(agi->agi_free_level); cur->bc_ops = &xfs_finobt_ops; cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_fibt_2); } cur->bc_blocklog = mp->m_sb.sb_blocklog; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_private.a.agbp = agbp; cur->bc_private.a.agno = agno; return cur; } /* * Calculate number of records in an inobt btree block. */ int xfs_inobt_maxrecs( struct xfs_mount *mp, int blocklen, int leaf) { blocklen -= XFS_INOBT_BLOCK_LEN(mp); if (leaf) return blocklen / sizeof(xfs_inobt_rec_t); return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); } /* * Convert the inode record holemask to an inode allocation bitmap. The inode * allocation bitmap is inode granularity and specifies whether an inode is * physically allocated on disk (not whether the inode is considered allocated * or free by the fs). * * A bit value of 1 means the inode is allocated, a value of 0 means it is free. */ uint64_t xfs_inobt_irec_to_allocmask( struct xfs_inobt_rec_incore *rec) { uint64_t bitmap = 0; uint64_t inodespbit; int nextbit; uint allocbitmap; /* * The holemask has 16-bits for a 64 inode record. Therefore each * holemask bit represents multiple inodes. Create a mask of bits to set * in the allocmask for each holemask bit. */ inodespbit = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1; /* * Allocated inodes are represented by 0 bits in holemask. Invert the 0 * bits to 1 and convert to a uint so we can use xfs_next_bit(). Mask * anything beyond the 16 holemask bits since this casts to a larger * type. */ allocbitmap = ~rec->ir_holemask & ((1 << XFS_INOBT_HOLEMASK_BITS) - 1); /* * allocbitmap is the inverted holemask so every set bit represents * allocated inodes. To expand from 16-bit holemask granularity to * 64-bit (e.g., bit-per-inode), set inodespbit bits in the target * bitmap for every holemask bit. */ nextbit = xfs_next_bit(&allocbitmap, 1, 0); while (nextbit != -1) { ASSERT(nextbit < (sizeof(rec->ir_holemask) * NBBY)); bitmap |= (inodespbit << (nextbit * XFS_INODES_PER_HOLEMASK_BIT)); nextbit = xfs_next_bit(&allocbitmap, 1, nextbit + 1); } return bitmap; } #if defined(DEBUG) || defined(XFS_WARN) /* * Verify that an in-core inode record has a valid inode count. */ int xfs_inobt_rec_check_count( struct xfs_mount *mp, struct xfs_inobt_rec_incore *rec) { int inocount = 0; int nextbit = 0; uint64_t allocbmap; int wordsz; wordsz = sizeof(allocbmap) / sizeof(unsigned int); allocbmap = xfs_inobt_irec_to_allocmask(rec); nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, nextbit); while (nextbit != -1) { inocount++; nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, nextbit + 1); } if (inocount != rec->ir_count) return -EFSCORRUPTED; return 0; } #endif /* DEBUG */ static xfs_extlen_t xfs_inobt_max_size( struct xfs_mount *mp, xfs_agnumber_t agno) { xfs_agblock_t agblocks = xfs_ag_block_count(mp, agno); /* Bail out if we're uninitialized, which can happen in mkfs. */ if (M_IGEO(mp)->inobt_mxr[0] == 0) return 0; /* * The log is permanently allocated, so the space it occupies will * never be available for the kinds of things that would require btree * expansion. We therefore can pretend the space isn't there. */ if (mp->m_sb.sb_logstart && XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno) agblocks -= mp->m_sb.sb_logblocks; return xfs_btree_calc_size(M_IGEO(mp)->inobt_mnr, (uint64_t)agblocks * mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK); } /* Read AGI and create inobt cursor. */ int xfs_inobt_cur( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_btnum_t which, struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp) { struct xfs_btree_cur *cur; int error; ASSERT(*agi_bpp == NULL); ASSERT(*curpp == NULL); error = xfs_ialloc_read_agi(mp, tp, agno, agi_bpp); if (error) return error; cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which); if (!cur) { xfs_trans_brelse(tp, *agi_bpp); *agi_bpp = NULL; return -ENOMEM; } *curpp = cur; return 0; } static int xfs_inobt_count_blocks( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_btnum_t btnum, xfs_extlen_t *tree_blocks) { struct xfs_buf *agbp = NULL; struct xfs_btree_cur *cur = NULL; int error; error = xfs_inobt_cur(mp, tp, agno, btnum, &cur, &agbp); if (error) return error; error = xfs_btree_count_blocks(cur, tree_blocks); xfs_btree_del_cursor(cur, error); xfs_trans_brelse(tp, agbp); return error; } /* * Figure out how many blocks to reserve and how many are used by this btree. */ int xfs_finobt_calc_reserves( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used) { xfs_extlen_t tree_len = 0; int error; if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return 0; error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO, &tree_len); if (error) return error; *ask += xfs_inobt_max_size(mp, agno); *used += tree_len; return 0; } /* Calculate the inobt btree size for some records. */ xfs_extlen_t xfs_iallocbt_calc_size( struct xfs_mount *mp, unsigned long long len) { return xfs_btree_calc_size(M_IGEO(mp)->inobt_mnr, len); } xfsprogs-5.3.0/libxfs/xfs_ialloc_btree.h0000644000175000017500000000414313570057155020222 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_IALLOC_BTREE_H__ #define __XFS_IALLOC_BTREE_H__ /* * Inode map on-disk structures */ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; /* * Btree block header size depends on a superblock flag. */ #define XFS_INOBT_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN) /* * Record, key, and pointer address macros for btree blocks. * * (note that some of these may appear unused, but they are used in userspace) */ #define XFS_INOBT_REC_ADDR(mp, block, index) \ ((xfs_inobt_rec_t *) \ ((char *)(block) + \ XFS_INOBT_BLOCK_LEN(mp) + \ (((index) - 1) * sizeof(xfs_inobt_rec_t)))) #define XFS_INOBT_KEY_ADDR(mp, block, index) \ ((xfs_inobt_key_t *) \ ((char *)(block) + \ XFS_INOBT_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_inobt_key_t))) #define XFS_INOBT_PTR_ADDR(mp, block, index, maxrecs) \ ((xfs_inobt_ptr_t *) \ ((char *)(block) + \ XFS_INOBT_BLOCK_LEN(mp) + \ (maxrecs) * sizeof(xfs_inobt_key_t) + \ ((index) - 1) * sizeof(xfs_inobt_ptr_t))) extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, xfs_btnum_t); extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int); /* ir_holemask to inode allocation bitmap conversion */ uint64_t xfs_inobt_irec_to_allocmask(struct xfs_inobt_rec_incore *); #if defined(DEBUG) || defined(XFS_WARN) int xfs_inobt_rec_check_count(struct xfs_mount *, struct xfs_inobt_rec_incore *); #else #define xfs_inobt_rec_check_count(mp, rec) 0 #endif /* DEBUG */ int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp, unsigned long long len); int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_btnum_t btnum, struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp); #endif /* __XFS_IALLOC_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_iext_tree.c0000644000175000017500000005627413570057155017575 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2017 Christoph Hellwig. */ // #include // #include // #include #include "libxfs_priv.h" #include "xfs_format.h" #include "xfs_bit.h" #include "xfs_log_format.h" #include "xfs_inode.h" #include "xfs_trace.h" /* * In-core extent record layout: * * +-------+----------------------------+ * | 00:53 | all 54 bits of startoff | * | 54:63 | low 10 bits of startblock | * +-------+----------------------------+ * | 00:20 | all 21 bits of length | * | 21 | unwritten extent bit | * | 22:63 | high 42 bits of startblock | * +-------+----------------------------+ */ #define XFS_IEXT_STARTOFF_MASK xfs_mask64lo(BMBT_STARTOFF_BITLEN) #define XFS_IEXT_LENGTH_MASK xfs_mask64lo(BMBT_BLOCKCOUNT_BITLEN) #define XFS_IEXT_STARTBLOCK_MASK xfs_mask64lo(BMBT_STARTBLOCK_BITLEN) struct xfs_iext_rec { uint64_t lo; uint64_t hi; }; /* * Given that the length can't be a zero, only an empty hi value indicates an * unused record. */ static bool xfs_iext_rec_is_empty(struct xfs_iext_rec *rec) { return rec->hi == 0; } static inline void xfs_iext_rec_clear(struct xfs_iext_rec *rec) { rec->lo = 0; rec->hi = 0; } static void xfs_iext_set( struct xfs_iext_rec *rec, struct xfs_bmbt_irec *irec) { ASSERT((irec->br_startoff & ~XFS_IEXT_STARTOFF_MASK) == 0); ASSERT((irec->br_blockcount & ~XFS_IEXT_LENGTH_MASK) == 0); ASSERT((irec->br_startblock & ~XFS_IEXT_STARTBLOCK_MASK) == 0); rec->lo = irec->br_startoff & XFS_IEXT_STARTOFF_MASK; rec->hi = irec->br_blockcount & XFS_IEXT_LENGTH_MASK; rec->lo |= (irec->br_startblock << 54); rec->hi |= ((irec->br_startblock & ~xfs_mask64lo(10)) << (22 - 10)); if (irec->br_state == XFS_EXT_UNWRITTEN) rec->hi |= (1 << 21); } static void xfs_iext_get( struct xfs_bmbt_irec *irec, struct xfs_iext_rec *rec) { irec->br_startoff = rec->lo & XFS_IEXT_STARTOFF_MASK; irec->br_blockcount = rec->hi & XFS_IEXT_LENGTH_MASK; irec->br_startblock = rec->lo >> 54; irec->br_startblock |= (rec->hi & xfs_mask64hi(42)) >> (22 - 10); if (rec->hi & (1 << 21)) irec->br_state = XFS_EXT_UNWRITTEN; else irec->br_state = XFS_EXT_NORM; } enum { NODE_SIZE = 256, KEYS_PER_NODE = NODE_SIZE / (sizeof(uint64_t) + sizeof(void *)), RECS_PER_LEAF = (NODE_SIZE - (2 * sizeof(struct xfs_iext_leaf *))) / sizeof(struct xfs_iext_rec), }; /* * In-core extent btree block layout: * * There are two types of blocks in the btree: leaf and inner (non-leaf) blocks. * * The leaf blocks are made up by %KEYS_PER_NODE extent records, which each * contain the startoffset, blockcount, startblock and unwritten extent flag. * See above for the exact format, followed by pointers to the previous and next * leaf blocks (if there are any). * * The inner (non-leaf) blocks first contain KEYS_PER_NODE lookup keys, followed * by an equal number of pointers to the btree blocks at the next lower level. * * +-------+-------+-------+-------+-------+----------+----------+ * Leaf: | rec 1 | rec 2 | rec 3 | rec 4 | rec N | prev-ptr | next-ptr | * +-------+-------+-------+-------+-------+----------+----------+ * * +-------+-------+-------+-------+-------+-------+------+-------+ * Inner: | key 1 | key 2 | key 3 | key N | ptr 1 | ptr 2 | ptr3 | ptr N | * +-------+-------+-------+-------+-------+-------+------+-------+ */ struct xfs_iext_node { uint64_t keys[KEYS_PER_NODE]; #define XFS_IEXT_KEY_INVALID (1ULL << 63) void *ptrs[KEYS_PER_NODE]; }; struct xfs_iext_leaf { struct xfs_iext_rec recs[RECS_PER_LEAF]; struct xfs_iext_leaf *prev; struct xfs_iext_leaf *next; }; inline xfs_extnum_t xfs_iext_count(struct xfs_ifork *ifp) { return ifp->if_bytes / sizeof(struct xfs_iext_rec); } static inline int xfs_iext_max_recs(struct xfs_ifork *ifp) { if (ifp->if_height == 1) return xfs_iext_count(ifp); return RECS_PER_LEAF; } static inline struct xfs_iext_rec *cur_rec(struct xfs_iext_cursor *cur) { return &cur->leaf->recs[cur->pos]; } static inline bool xfs_iext_valid(struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { if (!cur->leaf) return false; if (cur->pos < 0 || cur->pos >= xfs_iext_max_recs(ifp)) return false; if (xfs_iext_rec_is_empty(cur_rec(cur))) return false; return true; } static void * xfs_iext_find_first_leaf( struct xfs_ifork *ifp) { struct xfs_iext_node *node = ifp->if_u1.if_root; int height; if (!ifp->if_height) return NULL; for (height = ifp->if_height; height > 1; height--) { node = node->ptrs[0]; ASSERT(node); } return node; } static void * xfs_iext_find_last_leaf( struct xfs_ifork *ifp) { struct xfs_iext_node *node = ifp->if_u1.if_root; int height, i; if (!ifp->if_height) return NULL; for (height = ifp->if_height; height > 1; height--) { for (i = 1; i < KEYS_PER_NODE; i++) if (!node->ptrs[i]) break; node = node->ptrs[i - 1]; ASSERT(node); } return node; } void xfs_iext_first( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { cur->pos = 0; cur->leaf = xfs_iext_find_first_leaf(ifp); } void xfs_iext_last( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { int i; cur->leaf = xfs_iext_find_last_leaf(ifp); if (!cur->leaf) { cur->pos = 0; return; } for (i = 1; i < xfs_iext_max_recs(ifp); i++) { if (xfs_iext_rec_is_empty(&cur->leaf->recs[i])) break; } cur->pos = i - 1; } void xfs_iext_next( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { if (!cur->leaf) { ASSERT(cur->pos <= 0 || cur->pos >= RECS_PER_LEAF); xfs_iext_first(ifp, cur); return; } ASSERT(cur->pos >= 0); ASSERT(cur->pos < xfs_iext_max_recs(ifp)); cur->pos++; if (ifp->if_height > 1 && !xfs_iext_valid(ifp, cur) && cur->leaf->next) { cur->leaf = cur->leaf->next; cur->pos = 0; } } void xfs_iext_prev( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { if (!cur->leaf) { ASSERT(cur->pos <= 0 || cur->pos >= RECS_PER_LEAF); xfs_iext_last(ifp, cur); return; } ASSERT(cur->pos >= 0); ASSERT(cur->pos <= RECS_PER_LEAF); recurse: do { cur->pos--; if (xfs_iext_valid(ifp, cur)) return; } while (cur->pos > 0); if (ifp->if_height > 1 && cur->leaf->prev) { cur->leaf = cur->leaf->prev; cur->pos = RECS_PER_LEAF; goto recurse; } } static inline int xfs_iext_key_cmp( struct xfs_iext_node *node, int n, xfs_fileoff_t offset) { if (node->keys[n] > offset) return 1; if (node->keys[n] < offset) return -1; return 0; } static inline int xfs_iext_rec_cmp( struct xfs_iext_rec *rec, xfs_fileoff_t offset) { uint64_t rec_offset = rec->lo & XFS_IEXT_STARTOFF_MASK; uint32_t rec_len = rec->hi & XFS_IEXT_LENGTH_MASK; if (rec_offset > offset) return 1; if (rec_offset + rec_len <= offset) return -1; return 0; } static void * xfs_iext_find_level( struct xfs_ifork *ifp, xfs_fileoff_t offset, int level) { struct xfs_iext_node *node = ifp->if_u1.if_root; int height, i; if (!ifp->if_height) return NULL; for (height = ifp->if_height; height > level; height--) { for (i = 1; i < KEYS_PER_NODE; i++) if (xfs_iext_key_cmp(node, i, offset) > 0) break; node = node->ptrs[i - 1]; if (!node) break; } return node; } static int xfs_iext_node_pos( struct xfs_iext_node *node, xfs_fileoff_t offset) { int i; for (i = 1; i < KEYS_PER_NODE; i++) { if (xfs_iext_key_cmp(node, i, offset) > 0) break; } return i - 1; } static int xfs_iext_node_insert_pos( struct xfs_iext_node *node, xfs_fileoff_t offset) { int i; for (i = 0; i < KEYS_PER_NODE; i++) { if (xfs_iext_key_cmp(node, i, offset) > 0) return i; } return KEYS_PER_NODE; } static int xfs_iext_node_nr_entries( struct xfs_iext_node *node, int start) { int i; for (i = start; i < KEYS_PER_NODE; i++) { if (node->keys[i] == XFS_IEXT_KEY_INVALID) break; } return i; } static int xfs_iext_leaf_nr_entries( struct xfs_ifork *ifp, struct xfs_iext_leaf *leaf, int start) { int i; for (i = start; i < xfs_iext_max_recs(ifp); i++) { if (xfs_iext_rec_is_empty(&leaf->recs[i])) break; } return i; } static inline uint64_t xfs_iext_leaf_key( struct xfs_iext_leaf *leaf, int n) { return leaf->recs[n].lo & XFS_IEXT_STARTOFF_MASK; } static void xfs_iext_grow( struct xfs_ifork *ifp) { struct xfs_iext_node *node = kmem_zalloc(NODE_SIZE, KM_NOFS); int i; if (ifp->if_height == 1) { struct xfs_iext_leaf *prev = ifp->if_u1.if_root; node->keys[0] = xfs_iext_leaf_key(prev, 0); node->ptrs[0] = prev; } else { struct xfs_iext_node *prev = ifp->if_u1.if_root; ASSERT(ifp->if_height > 1); node->keys[0] = prev->keys[0]; node->ptrs[0] = prev; } for (i = 1; i < KEYS_PER_NODE; i++) node->keys[i] = XFS_IEXT_KEY_INVALID; ifp->if_u1.if_root = node; ifp->if_height++; } static void xfs_iext_update_node( struct xfs_ifork *ifp, xfs_fileoff_t old_offset, xfs_fileoff_t new_offset, int level, void *ptr) { struct xfs_iext_node *node = ifp->if_u1.if_root; int height, i; for (height = ifp->if_height; height > level; height--) { for (i = 0; i < KEYS_PER_NODE; i++) { if (i > 0 && xfs_iext_key_cmp(node, i, old_offset) > 0) break; if (node->keys[i] == old_offset) node->keys[i] = new_offset; } node = node->ptrs[i - 1]; ASSERT(node); } ASSERT(node == ptr); } static struct xfs_iext_node * xfs_iext_split_node( struct xfs_iext_node **nodep, int *pos, int *nr_entries) { struct xfs_iext_node *node = *nodep; struct xfs_iext_node *new = kmem_zalloc(NODE_SIZE, KM_NOFS); const int nr_move = KEYS_PER_NODE / 2; int nr_keep = nr_move + (KEYS_PER_NODE & 1); int i = 0; /* for sequential append operations just spill over into the new node */ if (*pos == KEYS_PER_NODE) { *nodep = new; *pos = 0; *nr_entries = 0; goto done; } for (i = 0; i < nr_move; i++) { new->keys[i] = node->keys[nr_keep + i]; new->ptrs[i] = node->ptrs[nr_keep + i]; node->keys[nr_keep + i] = XFS_IEXT_KEY_INVALID; node->ptrs[nr_keep + i] = NULL; } if (*pos >= nr_keep) { *nodep = new; *pos -= nr_keep; *nr_entries = nr_move; } else { *nr_entries = nr_keep; } done: for (; i < KEYS_PER_NODE; i++) new->keys[i] = XFS_IEXT_KEY_INVALID; return new; } static void xfs_iext_insert_node( struct xfs_ifork *ifp, uint64_t offset, void *ptr, int level) { struct xfs_iext_node *node, *new; int i, pos, nr_entries; again: if (ifp->if_height < level) xfs_iext_grow(ifp); new = NULL; node = xfs_iext_find_level(ifp, offset, level); pos = xfs_iext_node_insert_pos(node, offset); nr_entries = xfs_iext_node_nr_entries(node, pos); ASSERT(pos >= nr_entries || xfs_iext_key_cmp(node, pos, offset) != 0); ASSERT(nr_entries <= KEYS_PER_NODE); if (nr_entries == KEYS_PER_NODE) new = xfs_iext_split_node(&node, &pos, &nr_entries); /* * Update the pointers in higher levels if the first entry changes * in an existing node. */ if (node != new && pos == 0 && nr_entries > 0) xfs_iext_update_node(ifp, node->keys[0], offset, level, node); for (i = nr_entries; i > pos; i--) { node->keys[i] = node->keys[i - 1]; node->ptrs[i] = node->ptrs[i - 1]; } node->keys[pos] = offset; node->ptrs[pos] = ptr; if (new) { offset = new->keys[0]; ptr = new; level++; goto again; } } static struct xfs_iext_leaf * xfs_iext_split_leaf( struct xfs_iext_cursor *cur, int *nr_entries) { struct xfs_iext_leaf *leaf = cur->leaf; struct xfs_iext_leaf *new = kmem_zalloc(NODE_SIZE, KM_NOFS); const int nr_move = RECS_PER_LEAF / 2; int nr_keep = nr_move + (RECS_PER_LEAF & 1); int i; /* for sequential append operations just spill over into the new node */ if (cur->pos == RECS_PER_LEAF) { cur->leaf = new; cur->pos = 0; *nr_entries = 0; goto done; } for (i = 0; i < nr_move; i++) { new->recs[i] = leaf->recs[nr_keep + i]; xfs_iext_rec_clear(&leaf->recs[nr_keep + i]); } if (cur->pos >= nr_keep) { cur->leaf = new; cur->pos -= nr_keep; *nr_entries = nr_move; } else { *nr_entries = nr_keep; } done: if (leaf->next) leaf->next->prev = new; new->next = leaf->next; new->prev = leaf; leaf->next = new; return new; } static void xfs_iext_alloc_root( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { ASSERT(ifp->if_bytes == 0); ifp->if_u1.if_root = kmem_zalloc(sizeof(struct xfs_iext_rec), KM_NOFS); ifp->if_height = 1; /* now that we have a node step into it */ cur->leaf = ifp->if_u1.if_root; cur->pos = 0; } static void xfs_iext_realloc_root( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur) { size_t new_size = ifp->if_bytes + sizeof(struct xfs_iext_rec); void *new; /* account for the prev/next pointers */ if (new_size / sizeof(struct xfs_iext_rec) == RECS_PER_LEAF) new_size = NODE_SIZE; new = kmem_realloc(ifp->if_u1.if_root, new_size, KM_NOFS); memset(new + ifp->if_bytes, 0, new_size - ifp->if_bytes); ifp->if_u1.if_root = new; cur->leaf = new; } /* * Increment the sequence counter on extent tree changes. If we are on a COW * fork, this allows the writeback code to skip looking for a COW extent if the * COW fork hasn't changed. We use WRITE_ONCE here to ensure the update to the * sequence counter is seen before the modifications to the extent tree itself * take effect. */ static inline void xfs_iext_inc_seq(struct xfs_ifork *ifp, int state) { WRITE_ONCE(ifp->if_seq, READ_ONCE(ifp->if_seq) + 1); } void xfs_iext_insert( struct xfs_inode *ip, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *irec, int state) { struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state); xfs_fileoff_t offset = irec->br_startoff; struct xfs_iext_leaf *new = NULL; int nr_entries, i; xfs_iext_inc_seq(ifp, state); if (ifp->if_height == 0) xfs_iext_alloc_root(ifp, cur); else if (ifp->if_height == 1) xfs_iext_realloc_root(ifp, cur); nr_entries = xfs_iext_leaf_nr_entries(ifp, cur->leaf, cur->pos); ASSERT(nr_entries <= RECS_PER_LEAF); ASSERT(cur->pos >= nr_entries || xfs_iext_rec_cmp(cur_rec(cur), irec->br_startoff) != 0); if (nr_entries == RECS_PER_LEAF) new = xfs_iext_split_leaf(cur, &nr_entries); /* * Update the pointers in higher levels if the first entry changes * in an existing node. */ if (cur->leaf != new && cur->pos == 0 && nr_entries > 0) { xfs_iext_update_node(ifp, xfs_iext_leaf_key(cur->leaf, 0), offset, 1, cur->leaf); } for (i = nr_entries; i > cur->pos; i--) cur->leaf->recs[i] = cur->leaf->recs[i - 1]; xfs_iext_set(cur_rec(cur), irec); ifp->if_bytes += sizeof(struct xfs_iext_rec); trace_xfs_iext_insert(ip, cur, state, _RET_IP_); if (new) xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2); } static struct xfs_iext_node * xfs_iext_rebalance_node( struct xfs_iext_node *parent, int *pos, struct xfs_iext_node *node, int nr_entries) { /* * If the neighbouring nodes are completely full, or have different * parents, we might never be able to merge our node, and will only * delete it once the number of entries hits zero. */ if (nr_entries == 0) return node; if (*pos > 0) { struct xfs_iext_node *prev = parent->ptrs[*pos - 1]; int nr_prev = xfs_iext_node_nr_entries(prev, 0), i; if (nr_prev + nr_entries <= KEYS_PER_NODE) { for (i = 0; i < nr_entries; i++) { prev->keys[nr_prev + i] = node->keys[i]; prev->ptrs[nr_prev + i] = node->ptrs[i]; } return node; } } if (*pos + 1 < xfs_iext_node_nr_entries(parent, *pos)) { struct xfs_iext_node *next = parent->ptrs[*pos + 1]; int nr_next = xfs_iext_node_nr_entries(next, 0), i; if (nr_entries + nr_next <= KEYS_PER_NODE) { /* * Merge the next node into this node so that we don't * have to do an additional update of the keys in the * higher levels. */ for (i = 0; i < nr_next; i++) { node->keys[nr_entries + i] = next->keys[i]; node->ptrs[nr_entries + i] = next->ptrs[i]; } ++*pos; return next; } } return NULL; } static void xfs_iext_remove_node( struct xfs_ifork *ifp, xfs_fileoff_t offset, void *victim) { struct xfs_iext_node *node, *parent; int level = 2, pos, nr_entries, i; ASSERT(level <= ifp->if_height); node = xfs_iext_find_level(ifp, offset, level); pos = xfs_iext_node_pos(node, offset); again: ASSERT(node->ptrs[pos]); ASSERT(node->ptrs[pos] == victim); kmem_free(victim); nr_entries = xfs_iext_node_nr_entries(node, pos) - 1; offset = node->keys[0]; for (i = pos; i < nr_entries; i++) { node->keys[i] = node->keys[i + 1]; node->ptrs[i] = node->ptrs[i + 1]; } node->keys[nr_entries] = XFS_IEXT_KEY_INVALID; node->ptrs[nr_entries] = NULL; if (pos == 0 && nr_entries > 0) { xfs_iext_update_node(ifp, offset, node->keys[0], level, node); offset = node->keys[0]; } if (nr_entries >= KEYS_PER_NODE / 2) return; if (level < ifp->if_height) { /* * If we aren't at the root yet try to find a neighbour node to * merge with (or delete the node if it is empty), and then * recurse up to the next level. */ level++; parent = xfs_iext_find_level(ifp, offset, level); pos = xfs_iext_node_pos(parent, offset); ASSERT(pos != KEYS_PER_NODE); ASSERT(parent->ptrs[pos] == node); node = xfs_iext_rebalance_node(parent, &pos, node, nr_entries); if (node) { victim = node; node = parent; goto again; } } else if (nr_entries == 1) { /* * If we are at the root and only one entry is left we can just * free this node and update the root pointer. */ ASSERT(node == ifp->if_u1.if_root); ifp->if_u1.if_root = node->ptrs[0]; ifp->if_height--; kmem_free(node); } } static void xfs_iext_rebalance_leaf( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_iext_leaf *leaf, xfs_fileoff_t offset, int nr_entries) { /* * If the neighbouring nodes are completely full we might never be able * to merge our node, and will only delete it once the number of * entries hits zero. */ if (nr_entries == 0) goto remove_node; if (leaf->prev) { int nr_prev = xfs_iext_leaf_nr_entries(ifp, leaf->prev, 0), i; if (nr_prev + nr_entries <= RECS_PER_LEAF) { for (i = 0; i < nr_entries; i++) leaf->prev->recs[nr_prev + i] = leaf->recs[i]; if (cur->leaf == leaf) { cur->leaf = leaf->prev; cur->pos += nr_prev; } goto remove_node; } } if (leaf->next) { int nr_next = xfs_iext_leaf_nr_entries(ifp, leaf->next, 0), i; if (nr_entries + nr_next <= RECS_PER_LEAF) { /* * Merge the next node into this node so that we don't * have to do an additional update of the keys in the * higher levels. */ for (i = 0; i < nr_next; i++) { leaf->recs[nr_entries + i] = leaf->next->recs[i]; } if (cur->leaf == leaf->next) { cur->leaf = leaf; cur->pos += nr_entries; } offset = xfs_iext_leaf_key(leaf->next, 0); leaf = leaf->next; goto remove_node; } } return; remove_node: if (leaf->prev) leaf->prev->next = leaf->next; if (leaf->next) leaf->next->prev = leaf->prev; xfs_iext_remove_node(ifp, offset, leaf); } static void xfs_iext_free_last_leaf( struct xfs_ifork *ifp) { ifp->if_height--; kmem_free(ifp->if_u1.if_root); ifp->if_u1.if_root = NULL; } void xfs_iext_remove( struct xfs_inode *ip, struct xfs_iext_cursor *cur, int state) { struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state); struct xfs_iext_leaf *leaf = cur->leaf; xfs_fileoff_t offset = xfs_iext_leaf_key(leaf, 0); int i, nr_entries; trace_xfs_iext_remove(ip, cur, state, _RET_IP_); ASSERT(ifp->if_height > 0); ASSERT(ifp->if_u1.if_root != NULL); ASSERT(xfs_iext_valid(ifp, cur)); xfs_iext_inc_seq(ifp, state); nr_entries = xfs_iext_leaf_nr_entries(ifp, leaf, cur->pos) - 1; for (i = cur->pos; i < nr_entries; i++) leaf->recs[i] = leaf->recs[i + 1]; xfs_iext_rec_clear(&leaf->recs[nr_entries]); ifp->if_bytes -= sizeof(struct xfs_iext_rec); if (cur->pos == 0 && nr_entries > 0) { xfs_iext_update_node(ifp, offset, xfs_iext_leaf_key(leaf, 0), 1, leaf); offset = xfs_iext_leaf_key(leaf, 0); } else if (cur->pos == nr_entries) { if (ifp->if_height > 1 && leaf->next) cur->leaf = leaf->next; else cur->leaf = NULL; cur->pos = 0; } if (nr_entries >= RECS_PER_LEAF / 2) return; if (ifp->if_height > 1) xfs_iext_rebalance_leaf(ifp, cur, leaf, offset, nr_entries); else if (nr_entries == 0) xfs_iext_free_last_leaf(ifp); } /* * Lookup the extent covering bno. * * If there is an extent covering bno return the extent index, and store the * expanded extent structure in *gotp, and the extent cursor in *cur. * If there is no extent covering bno, but there is an extent after it (e.g. * it lies in a hole) return that extent in *gotp and its cursor in *cur * instead. * If bno is beyond the last extent return false, and return an invalid * cursor value. */ bool xfs_iext_lookup_extent( struct xfs_inode *ip, struct xfs_ifork *ifp, xfs_fileoff_t offset, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { XFS_STATS_INC(ip->i_mount, xs_look_exlist); cur->leaf = xfs_iext_find_level(ifp, offset, 1); if (!cur->leaf) { cur->pos = 0; return false; } for (cur->pos = 0; cur->pos < xfs_iext_max_recs(ifp); cur->pos++) { struct xfs_iext_rec *rec = cur_rec(cur); if (xfs_iext_rec_is_empty(rec)) break; if (xfs_iext_rec_cmp(rec, offset) >= 0) goto found; } /* Try looking in the next node for an entry > offset */ if (ifp->if_height == 1 || !cur->leaf->next) return false; cur->leaf = cur->leaf->next; cur->pos = 0; if (!xfs_iext_valid(ifp, cur)) return false; found: xfs_iext_get(gotp, cur_rec(cur)); return true; } /* * Returns the last extent before end, and if this extent doesn't cover * end, update end to the end of the extent. */ bool xfs_iext_lookup_extent_before( struct xfs_inode *ip, struct xfs_ifork *ifp, xfs_fileoff_t *end, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { /* could be optimized to not even look up the next on a match.. */ if (xfs_iext_lookup_extent(ip, ifp, *end - 1, cur, gotp) && gotp->br_startoff <= *end - 1) return true; if (!xfs_iext_prev_extent(ifp, cur, gotp)) return false; *end = gotp->br_startoff + gotp->br_blockcount; return true; } void xfs_iext_update_extent( struct xfs_inode *ip, int state, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *new) { struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state); xfs_iext_inc_seq(ifp, state); if (cur->pos == 0) { struct xfs_bmbt_irec old; xfs_iext_get(&old, cur_rec(cur)); if (new->br_startoff != old.br_startoff) { xfs_iext_update_node(ifp, old.br_startoff, new->br_startoff, 1, cur->leaf); } } trace_xfs_bmap_pre_update(ip, cur, state, _RET_IP_); xfs_iext_set(cur_rec(cur), new); trace_xfs_bmap_post_update(ip, cur, state, _RET_IP_); } /* * Return true if the cursor points at an extent and return the extent structure * in gotp. Else return false. */ bool xfs_iext_get_extent( struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { if (!xfs_iext_valid(ifp, cur)) return false; xfs_iext_get(gotp, cur_rec(cur)); return true; } /* * This is a recursive function, because of that we need to be extremely * careful with stack usage. */ static void xfs_iext_destroy_node( struct xfs_iext_node *node, int level) { int i; if (level > 1) { for (i = 0; i < KEYS_PER_NODE; i++) { if (node->keys[i] == XFS_IEXT_KEY_INVALID) break; xfs_iext_destroy_node(node->ptrs[i], level - 1); } } kmem_free(node); } void xfs_iext_destroy( struct xfs_ifork *ifp) { xfs_iext_destroy_node(ifp->if_u1.if_root, ifp->if_height); ifp->if_bytes = 0; ifp->if_height = 0; ifp->if_u1.if_root = NULL; } xfsprogs-5.3.0/libxfs/xfs_inode_buf.c0000644000175000017500000005507213570057155017532 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_ialloc.h" #include "xfs_dir2.h" /* * Check that none of the inode's in the buffer have a next * unlinked field of 0. */ #if defined(DEBUG) void xfs_inobp_check( xfs_mount_t *mp, xfs_buf_t *bp) { int i; xfs_dinode_t *dip; for (i = 0; i < M_IGEO(mp)->inodes_per_cluster; i++) { dip = xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize); if (!dip->di_next_unlinked) { xfs_alert(mp, "Detected bogus zero next_unlinked field in inode %d buffer 0x%llx.", i, (long long)bp->b_bn); } } } #endif bool xfs_dinode_good_version( struct xfs_mount *mp, __u8 version) { if (xfs_sb_version_hascrc(&mp->m_sb)) return version == 3; return version == 1 || version == 2; } /* * If we are doing readahead on an inode buffer, we might be in log recovery * reading an inode allocation buffer that hasn't yet been replayed, and hence * has not had the inode cores stamped into it. Hence for readahead, the buffer * may be potentially invalid. * * If the readahead buffer is invalid, we need to mark it with an error and * clear the DONE status of the buffer so that a followup read will re-read it * from disk. We don't report the error otherwise to avoid warnings during log * recovery and we don't get unnecssary panics on debug kernels. We use EIO here * because all we want to do is say readahead failed; there is no-one to report * the error to, so this will distinguish it from a non-ra verifier failure. * Changes to this readahead error behavour also need to be reflected in * xfs_dquot_buf_readahead_verify(). */ static void xfs_inode_buf_verify( struct xfs_buf *bp, bool readahead) { struct xfs_mount *mp = bp->b_mount; xfs_agnumber_t agno; int i; int ni; /* * Validate the magic number and version of every inode in the buffer */ agno = xfs_daddr_to_agno(mp, XFS_BUF_ADDR(bp)); ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; for (i = 0; i < ni; i++) { int di_ok; xfs_dinode_t *dip; xfs_agino_t unlinked_ino; dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); unlinked_ino = be32_to_cpu(dip->di_next_unlinked); di_ok = xfs_verify_magic16(bp, dip->di_magic) && xfs_dinode_good_version(mp, dip->di_version) && xfs_verify_agino_or_null(mp, agno, unlinked_ino); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP))) { if (readahead) { bp->b_flags &= ~XBF_DONE; xfs_buf_ioerror(bp, -EIO); return; } #ifdef DEBUG xfs_alert(mp, "bad inode magic/vsn daddr %lld #%d (magic=%x)", (unsigned long long)bp->b_bn, i, be16_to_cpu(dip->di_magic)); #endif xfs_buf_verifier_error(bp, -EFSCORRUPTED, __func__, dip, sizeof(*dip), NULL); return; } } } static void xfs_inode_buf_read_verify( struct xfs_buf *bp) { xfs_inode_buf_verify(bp, false); } static void xfs_inode_buf_readahead_verify( struct xfs_buf *bp) { xfs_inode_buf_verify(bp, true); } static void xfs_inode_buf_write_verify( struct xfs_buf *bp) { xfs_inode_buf_verify(bp, false); } const struct xfs_buf_ops xfs_inode_buf_ops = { .name = "xfs_inode", .magic16 = { cpu_to_be16(XFS_DINODE_MAGIC), cpu_to_be16(XFS_DINODE_MAGIC) }, .verify_read = xfs_inode_buf_read_verify, .verify_write = xfs_inode_buf_write_verify, }; const struct xfs_buf_ops xfs_inode_buf_ra_ops = { .name = "xfs_inode_ra", .magic16 = { cpu_to_be16(XFS_DINODE_MAGIC), cpu_to_be16(XFS_DINODE_MAGIC) }, .verify_read = xfs_inode_buf_readahead_verify, .verify_write = xfs_inode_buf_write_verify, }; /* * This routine is called to map an inode to the buffer containing the on-disk * version of the inode. It returns a pointer to the buffer containing the * on-disk inode in the bpp parameter, and in the dipp parameter it returns a * pointer to the on-disk inode within that buffer. * * If a non-zero error is returned, then the contents of bpp and dipp are * undefined. */ int xfs_imap_to_bp( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_imap *imap, struct xfs_dinode **dipp, struct xfs_buf **bpp, uint buf_flags, uint iget_flags) { struct xfs_buf *bp; int error; buf_flags |= XBF_UNMAPPED; error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, (int)imap->im_len, buf_flags, &bp, &xfs_inode_buf_ops); if (error) { if (error == -EAGAIN) { ASSERT(buf_flags & XBF_TRYLOCK); return error; } xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.", __func__, error); return error; } *bpp = bp; *dipp = xfs_buf_offset(bp, imap->im_boffset); return 0; } void xfs_inode_from_disk( struct xfs_inode *ip, struct xfs_dinode *from) { struct xfs_icdinode *to = &ip->i_d; struct inode *inode = VFS_I(ip); /* * Convert v1 inodes immediately to v2 inode format as this is the * minimum inode version format we support in the rest of the code. */ to->di_version = from->di_version; if (to->di_version == 1) { set_nlink(inode, be16_to_cpu(from->di_onlink)); to->di_projid_lo = 0; to->di_projid_hi = 0; to->di_version = 2; } else { set_nlink(inode, be32_to_cpu(from->di_nlink)); to->di_projid_lo = be16_to_cpu(from->di_projid_lo); to->di_projid_hi = be16_to_cpu(from->di_projid_hi); } to->di_format = from->di_format; to->di_uid = be32_to_cpu(from->di_uid); to->di_gid = be32_to_cpu(from->di_gid); to->di_flushiter = be16_to_cpu(from->di_flushiter); /* * Time is signed, so need to convert to signed 32 bit before * storing in inode timestamp which may be 64 bit. Otherwise * a time before epoch is converted to a time long after epoch * on 64 bit systems. */ inode->i_atime.tv_sec = (int)be32_to_cpu(from->di_atime.t_sec); inode->i_atime.tv_nsec = (int)be32_to_cpu(from->di_atime.t_nsec); inode->i_mtime.tv_sec = (int)be32_to_cpu(from->di_mtime.t_sec); inode->i_mtime.tv_nsec = (int)be32_to_cpu(from->di_mtime.t_nsec); inode->i_ctime.tv_sec = (int)be32_to_cpu(from->di_ctime.t_sec); inode->i_ctime.tv_nsec = (int)be32_to_cpu(from->di_ctime.t_nsec); inode->i_generation = be32_to_cpu(from->di_gen); inode->i_mode = be16_to_cpu(from->di_mode); to->di_size = be64_to_cpu(from->di_size); to->di_nblocks = be64_to_cpu(from->di_nblocks); to->di_extsize = be32_to_cpu(from->di_extsize); to->di_nextents = be32_to_cpu(from->di_nextents); to->di_anextents = be16_to_cpu(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = be32_to_cpu(from->di_dmevmask); to->di_dmstate = be16_to_cpu(from->di_dmstate); to->di_flags = be16_to_cpu(from->di_flags); if (to->di_version == 3) { inode_set_iversion_queried(inode, be64_to_cpu(from->di_changecount)); to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec); to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec); to->di_flags2 = be64_to_cpu(from->di_flags2); to->di_cowextsize = be32_to_cpu(from->di_cowextsize); } } void xfs_inode_to_disk( struct xfs_inode *ip, struct xfs_dinode *to, xfs_lsn_t lsn) { struct xfs_icdinode *from = &ip->i_d; struct inode *inode = VFS_I(ip); to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); to->di_onlink = 0; to->di_version = from->di_version; to->di_format = from->di_format; to->di_uid = cpu_to_be32(from->di_uid); to->di_gid = cpu_to_be32(from->di_gid); to->di_projid_lo = cpu_to_be16(from->di_projid_lo); to->di_projid_hi = cpu_to_be16(from->di_projid_hi); memset(to->di_pad, 0, sizeof(to->di_pad)); to->di_atime.t_sec = cpu_to_be32(inode->i_atime.tv_sec); to->di_atime.t_nsec = cpu_to_be32(inode->i_atime.tv_nsec); to->di_mtime.t_sec = cpu_to_be32(inode->i_mtime.tv_sec); to->di_mtime.t_nsec = cpu_to_be32(inode->i_mtime.tv_nsec); to->di_ctime.t_sec = cpu_to_be32(inode->i_ctime.tv_sec); to->di_ctime.t_nsec = cpu_to_be32(inode->i_ctime.tv_nsec); to->di_nlink = cpu_to_be32(inode->i_nlink); to->di_gen = cpu_to_be32(inode->i_generation); to->di_mode = cpu_to_be16(inode->i_mode); to->di_size = cpu_to_be64(from->di_size); to->di_nblocks = cpu_to_be64(from->di_nblocks); to->di_extsize = cpu_to_be32(from->di_extsize); to->di_nextents = cpu_to_be32(from->di_nextents); to->di_anextents = cpu_to_be16(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = cpu_to_be32(from->di_dmevmask); to->di_dmstate = cpu_to_be16(from->di_dmstate); to->di_flags = cpu_to_be16(from->di_flags); if (from->di_version == 3) { to->di_changecount = cpu_to_be64(inode_peek_iversion(inode)); to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); to->di_flags2 = cpu_to_be64(from->di_flags2); to->di_cowextsize = cpu_to_be32(from->di_cowextsize); to->di_ino = cpu_to_be64(ip->i_ino); to->di_lsn = cpu_to_be64(lsn); memset(to->di_pad2, 0, sizeof(to->di_pad2)); uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); to->di_flushiter = 0; } else { to->di_flushiter = cpu_to_be16(from->di_flushiter); } } void xfs_log_dinode_to_disk( struct xfs_log_dinode *from, struct xfs_dinode *to) { to->di_magic = cpu_to_be16(from->di_magic); to->di_mode = cpu_to_be16(from->di_mode); to->di_version = from->di_version; to->di_format = from->di_format; to->di_onlink = 0; to->di_uid = cpu_to_be32(from->di_uid); to->di_gid = cpu_to_be32(from->di_gid); to->di_nlink = cpu_to_be32(from->di_nlink); to->di_projid_lo = cpu_to_be16(from->di_projid_lo); to->di_projid_hi = cpu_to_be16(from->di_projid_hi); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); to->di_size = cpu_to_be64(from->di_size); to->di_nblocks = cpu_to_be64(from->di_nblocks); to->di_extsize = cpu_to_be32(from->di_extsize); to->di_nextents = cpu_to_be32(from->di_nextents); to->di_anextents = cpu_to_be16(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = cpu_to_be32(from->di_dmevmask); to->di_dmstate = cpu_to_be16(from->di_dmstate); to->di_flags = cpu_to_be16(from->di_flags); to->di_gen = cpu_to_be32(from->di_gen); if (from->di_version == 3) { to->di_changecount = cpu_to_be64(from->di_changecount); to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); to->di_flags2 = cpu_to_be64(from->di_flags2); to->di_cowextsize = cpu_to_be32(from->di_cowextsize); to->di_ino = cpu_to_be64(from->di_ino); to->di_lsn = cpu_to_be64(from->di_lsn); memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); uuid_copy(&to->di_uuid, &from->di_uuid); to->di_flushiter = 0; } else { to->di_flushiter = cpu_to_be16(from->di_flushiter); } } static xfs_failaddr_t xfs_dinode_verify_fork( struct xfs_dinode *dip, struct xfs_mount *mp, int whichfork) { uint32_t di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork); switch (XFS_DFORK_FORMAT(dip, whichfork)) { case XFS_DINODE_FMT_LOCAL: /* * no local regular files yet */ if (whichfork == XFS_DATA_FORK) { if (S_ISREG(be16_to_cpu(dip->di_mode))) return __this_address; if (be64_to_cpu(dip->di_size) > XFS_DFORK_SIZE(dip, mp, whichfork)) return __this_address; } if (di_nextents) return __this_address; break; case XFS_DINODE_FMT_EXTENTS: if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork)) return __this_address; break; case XFS_DINODE_FMT_BTREE: if (whichfork == XFS_ATTR_FORK) { if (di_nextents > MAXAEXTNUM) return __this_address; } else if (di_nextents > MAXEXTNUM) { return __this_address; } break; default: return __this_address; } return NULL; } static xfs_failaddr_t xfs_dinode_verify_forkoff( struct xfs_dinode *dip, struct xfs_mount *mp) { if (!XFS_DFORK_Q(dip)) return NULL; switch (dip->di_format) { case XFS_DINODE_FMT_DEV: if (dip->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3)) return __this_address; break; case XFS_DINODE_FMT_LOCAL: /* fall through ... */ case XFS_DINODE_FMT_EXTENTS: /* fall through ... */ case XFS_DINODE_FMT_BTREE: if (dip->di_forkoff >= (XFS_LITINO(mp, dip->di_version) >> 3)) return __this_address; break; default: return __this_address; } return NULL; } xfs_failaddr_t xfs_dinode_verify( struct xfs_mount *mp, xfs_ino_t ino, struct xfs_dinode *dip) { xfs_failaddr_t fa; uint16_t mode; uint16_t flags; uint64_t flags2; uint64_t di_size; if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) return __this_address; /* Verify v3 integrity information first */ if (dip->di_version >= 3) { if (!xfs_sb_version_hascrc(&mp->m_sb)) return __this_address; if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF)) return __this_address; if (be64_to_cpu(dip->di_ino) != ino) return __this_address; if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; } /* don't allow invalid i_size */ di_size = be64_to_cpu(dip->di_size); if (di_size & (1ULL << 63)) return __this_address; mode = be16_to_cpu(dip->di_mode); if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN) return __this_address; /* No zero-length symlinks/dirs. */ if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0) return __this_address; /* Fork checks carried over from xfs_iformat_fork */ if (mode && be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) > be64_to_cpu(dip->di_nblocks)) return __this_address; if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize) return __this_address; flags = be16_to_cpu(dip->di_flags); if (mode && (flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp) return __this_address; /* check for illegal values of forkoff */ fa = xfs_dinode_verify_forkoff(dip, mp); if (fa) return fa; /* Do we have appropriate data fork formats for the mode? */ switch (mode & S_IFMT) { case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: if (dip->di_format != XFS_DINODE_FMT_DEV) return __this_address; break; case S_IFREG: case S_IFLNK: case S_IFDIR: fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK); if (fa) return fa; break; case 0: /* Uninitialized inode ok. */ break; default: return __this_address; } if (XFS_DFORK_Q(dip)) { fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK); if (fa) return fa; } else { /* * If there is no fork offset, this may be a freshly-made inode * in a new disk cluster, in which case di_aformat is zeroed. * Otherwise, such an inode must be in EXTENTS format; this goes * for freed inodes as well. */ switch (dip->di_aformat) { case 0: case XFS_DINODE_FMT_EXTENTS: break; default: return __this_address; } if (dip->di_anextents) return __this_address; } /* extent size hint validation */ fa = xfs_inode_validate_extsize(mp, be32_to_cpu(dip->di_extsize), mode, flags); if (fa) return fa; /* only version 3 or greater inodes are extensively verified here */ if (dip->di_version < 3) return NULL; flags2 = be64_to_cpu(dip->di_flags2); /* don't allow reflink/cowextsize if we don't have reflink */ if ((flags2 & (XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)) && !xfs_sb_version_hasreflink(&mp->m_sb)) return __this_address; /* only regular files get reflink */ if ((flags2 & XFS_DIFLAG2_REFLINK) && (mode & S_IFMT) != S_IFREG) return __this_address; /* don't let reflink and realtime mix */ if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags & XFS_DIFLAG_REALTIME)) return __this_address; /* don't let reflink and dax mix */ if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags2 & XFS_DIFLAG2_DAX)) return __this_address; /* COW extent size hint validation */ fa = xfs_inode_validate_cowextsize(mp, be32_to_cpu(dip->di_cowextsize), mode, flags, flags2); if (fa) return fa; return NULL; } void xfs_dinode_calc_crc( struct xfs_mount *mp, struct xfs_dinode *dip) { uint32_t crc; if (dip->di_version < 3) return; ASSERT(xfs_sb_version_hascrc(&mp->m_sb)); crc = xfs_start_cksum_update((char *)dip, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF); dip->di_crc = xfs_end_cksum(crc); } /* * Read the disk inode attributes into the in-core inode structure. * * For version 5 superblocks, if we are initialising a new inode and we are not * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new * inode core with a random generation number. If we are keeping inodes around, * we need to read the inode cluster to get the existing generation number off * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode * format) then log recovery is dependent on the di_flushiter field being * initialised from the current on-disk value and hence we must also read the * inode off disk. */ int xfs_iread( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *ip, uint iget_flags) { xfs_buf_t *bp; xfs_dinode_t *dip; xfs_failaddr_t fa; int error; /* * Fill in the location information in the in-core inode. */ error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); if (error) return error; /* shortcut IO on inode allocation if possible */ if ((iget_flags & XFS_IGET_CREATE) && xfs_sb_version_hascrc(&mp->m_sb) && !(mp->m_flags & XFS_MOUNT_IKEEP)) { /* initialise the on-disk inode core */ memset(&ip->i_d, 0, sizeof(ip->i_d)); VFS_I(ip)->i_generation = prandom_u32(); ip->i_d.di_version = 3; return 0; } /* * Get pointers to the on-disk inode and the buffer containing it. */ error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); if (error) return error; /* even unallocated inodes are verified */ fa = xfs_dinode_verify(mp, ip->i_ino, dip); if (fa) { xfs_inode_verifier_error(ip, -EFSCORRUPTED, "dinode", dip, sizeof(*dip), fa); error = -EFSCORRUPTED; goto out_brelse; } /* * If the on-disk inode is already linked to a directory * entry, copy all of the inode into the in-core inode. * xfs_iformat_fork() handles copying in the inode format * specific information. * Otherwise, just get the truly permanent information. */ if (dip->di_mode) { xfs_inode_from_disk(ip, dip); error = xfs_iformat_fork(ip, dip); if (error) { #ifdef DEBUG xfs_alert(mp, "%s: xfs_iformat() returned error %d", __func__, error); #endif /* DEBUG */ goto out_brelse; } } else { /* * Partial initialisation of the in-core inode. Just the bits * that xfs_ialloc won't overwrite or relies on being correct. */ ip->i_d.di_version = dip->di_version; VFS_I(ip)->i_generation = be32_to_cpu(dip->di_gen); ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); /* * Make sure to pull in the mode here as well in * case the inode is released without being used. * This ensures that xfs_inactive() will see that * the inode is already free and not try to mess * with the uninitialized part of it. */ VFS_I(ip)->i_mode = 0; } ASSERT(ip->i_d.di_version >= 2); ip->i_delayed_blks = 0; /* * Mark the buffer containing the inode as something to keep * around for a while. This helps to keep recently accessed * meta-data in-core longer. */ xfs_buf_set_ref(bp, XFS_INO_REF); /* * Use xfs_trans_brelse() to release the buffer containing the on-disk * inode, because it was acquired with xfs_trans_read_buf() in * xfs_imap_to_bp() above. If tp is NULL, this is just a normal * brelse(). If we're within a transaction, then xfs_trans_brelse() * will only release the buffer if it is not dirty within the * transaction. It will be OK to release the buffer in this case, * because inodes on disk are never destroyed and we will be locking the * new in-core inode before putting it in the cache where other * processes can find it. Thus we don't have to worry about the inode * being changed just because we released the buffer. */ out_brelse: xfs_trans_brelse(tp, bp); return error; } /* * Validate di_extsize hint. * * The rules are documented at xfs_ioctl_setattr_check_extsize(). * These functions must be kept in sync with each other. */ xfs_failaddr_t xfs_inode_validate_extsize( struct xfs_mount *mp, uint32_t extsize, uint16_t mode, uint16_t flags) { bool rt_flag; bool hint_flag; bool inherit_flag; uint32_t extsize_bytes; uint32_t blocksize_bytes; rt_flag = (flags & XFS_DIFLAG_REALTIME); hint_flag = (flags & XFS_DIFLAG_EXTSIZE); inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT); extsize_bytes = XFS_FSB_TO_B(mp, extsize); if (rt_flag) blocksize_bytes = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog; else blocksize_bytes = mp->m_sb.sb_blocksize; if ((hint_flag || inherit_flag) && !(S_ISDIR(mode) || S_ISREG(mode))) return __this_address; if (hint_flag && !S_ISREG(mode)) return __this_address; if (inherit_flag && !S_ISDIR(mode)) return __this_address; if ((hint_flag || inherit_flag) && extsize == 0) return __this_address; /* free inodes get flags set to zero but extsize remains */ if (mode && !(hint_flag || inherit_flag) && extsize != 0) return __this_address; if (extsize_bytes % blocksize_bytes) return __this_address; if (extsize > MAXEXTLEN) return __this_address; if (!rt_flag && extsize > mp->m_sb.sb_agblocks / 2) return __this_address; return NULL; } /* * Validate di_cowextsize hint. * * The rules are documented at xfs_ioctl_setattr_check_cowextsize(). * These functions must be kept in sync with each other. */ xfs_failaddr_t xfs_inode_validate_cowextsize( struct xfs_mount *mp, uint32_t cowextsize, uint16_t mode, uint16_t flags, uint64_t flags2) { bool rt_flag; bool hint_flag; uint32_t cowextsize_bytes; rt_flag = (flags & XFS_DIFLAG_REALTIME); hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE); cowextsize_bytes = XFS_FSB_TO_B(mp, cowextsize); if (hint_flag && !xfs_sb_version_hasreflink(&mp->m_sb)) return __this_address; if (hint_flag && !(S_ISDIR(mode) || S_ISREG(mode))) return __this_address; if (hint_flag && cowextsize == 0) return __this_address; /* free inodes get flags set to zero but cowextsize remains */ if (mode && !hint_flag && cowextsize != 0) return __this_address; if (hint_flag && rt_flag) return __this_address; if (cowextsize_bytes % mp->m_sb.sb_blocksize) return __this_address; if (cowextsize > MAXEXTLEN) return __this_address; if (cowextsize > mp->m_sb.sb_agblocks / 2) return __this_address; return NULL; } xfsprogs-5.3.0/libxfs/xfs_inode_buf.h0000644000175000017500000000606413435336036017532 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_INODE_BUF_H__ #define __XFS_INODE_BUF_H__ struct xfs_inode; struct xfs_dinode; /* * In memory representation of the XFS inode. This is held in the in-core struct * xfs_inode and represents the current on disk values but the structure is not * in on-disk format. That is, this structure is always translated to on-disk * format specific structures at the appropriate time. */ struct xfs_icdinode { int8_t di_version; /* inode version */ int8_t di_format; /* format of di_c data */ uint16_t di_flushiter; /* incremented on flush */ uint32_t di_uid; /* owner's user id */ uint32_t di_gid; /* owner's group id */ uint16_t di_projid_lo; /* lower part of owner's project id */ uint16_t di_projid_hi; /* higher part of owner's project id */ xfs_fsize_t di_size; /* number of bytes in file */ xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */ xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ xfs_extnum_t di_nextents; /* number of extents in data fork */ xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ int8_t di_aformat; /* format of attr fork's data */ uint32_t di_dmevmask; /* DMIG event mask */ uint16_t di_dmstate; /* DMIG state info */ uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ uint64_t di_flags2; /* more random flags */ uint32_t di_cowextsize; /* basic cow extent size for file */ xfs_ictimestamp_t di_crtime; /* time created */ }; /* * Inode location information. Stored in the inode and passed to * xfs_imap_to_bp() to get a buffer and dinode for a given inode. */ struct xfs_imap { xfs_daddr_t im_blkno; /* starting BB of inode chunk */ unsigned short im_len; /* length in BBs of inode chunk */ unsigned short im_boffset; /* inode offset in block in bytes */ }; int xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *, struct xfs_imap *, struct xfs_dinode **, struct xfs_buf **, uint, uint); int xfs_iread(struct xfs_mount *, struct xfs_trans *, struct xfs_inode *, uint); void xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *); void xfs_inode_to_disk(struct xfs_inode *ip, struct xfs_dinode *to, xfs_lsn_t lsn); void xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from); void xfs_log_dinode_to_disk(struct xfs_log_dinode *from, struct xfs_dinode *to); bool xfs_dinode_good_version(struct xfs_mount *mp, __u8 version); #if defined(DEBUG) void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); #else #define xfs_inobp_check(mp, bp) #endif /* DEBUG */ xfs_failaddr_t xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino, struct xfs_dinode *dip); xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp, uint32_t extsize, uint16_t mode, uint16_t flags); xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp, uint32_t cowextsize, uint16_t mode, uint16_t flags, uint64_t flags2); #endif /* __XFS_INODE_BUF_H__ */ xfsprogs-5.3.0/libxfs/xfs_inode_fork.c0000644000175000017500000004647513570057155017726 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_btree.h" #include "xfs_bmap_btree.h" #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2_priv.h" #include "xfs_attr_leaf.h" kmem_zone_t *xfs_ifork_zone; STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); /* * Copy inode type and data and attr format specific information from the * on-disk inode to the in-core inode and fork structures. For fifos, devices, * and sockets this means set i_rdev to the proper value. For files, * directories, and symlinks this means to bring in the in-line data or extent * pointers as well as the attribute fork. For a fork in B-tree format, only * the root is immediately brought in-core. The rest will be read in later when * first referenced (see xfs_iread_extents()). */ int xfs_iformat_fork( struct xfs_inode *ip, struct xfs_dinode *dip) { struct inode *inode = VFS_I(ip); struct xfs_attr_shortform *atp; int size; int error = 0; xfs_fsize_t di_size; switch (inode->i_mode & S_IFMT) { case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: ip->i_d.di_size = 0; inode->i_rdev = xfs_to_linux_dev_t(xfs_dinode_get_rdev(dip)); break; case S_IFREG: case S_IFLNK: case S_IFDIR: switch (dip->di_format) { case XFS_DINODE_FMT_LOCAL: di_size = be64_to_cpu(dip->di_size); size = (int)di_size; error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); break; case XFS_DINODE_FMT_BTREE: error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); break; default: return -EFSCORRUPTED; } break; default: return -EFSCORRUPTED; } if (error) return error; if (xfs_is_reflink_inode(ip)) { ASSERT(ip->i_cowfp == NULL); xfs_ifork_init_cow(ip); } if (!XFS_DFORK_Q(dip)) return 0; ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); switch (dip->di_aformat) { case XFS_DINODE_FMT_LOCAL: atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); size = be16_to_cpu(atp->hdr.totsize); error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_BTREE: error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); break; default: error = -EFSCORRUPTED; break; } if (error) { kmem_zone_free(xfs_ifork_zone, ip->i_afp); ip->i_afp = NULL; if (ip->i_cowfp) kmem_zone_free(xfs_ifork_zone, ip->i_cowfp); ip->i_cowfp = NULL; xfs_idestroy_fork(ip, XFS_DATA_FORK); } return error; } void xfs_init_local_fork( struct xfs_inode *ip, int whichfork, const void *data, int size) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); int mem_size = size, real_size = 0; bool zero_terminate; /* * If we are using the local fork to store a symlink body we need to * zero-terminate it so that we can pass it back to the VFS directly. * Overallocate the in-memory fork by one for that and add a zero * to terminate it below. */ zero_terminate = S_ISLNK(VFS_I(ip)->i_mode); if (zero_terminate) mem_size++; if (size) { real_size = roundup(mem_size, 4); ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); memcpy(ifp->if_u1.if_data, data, size); if (zero_terminate) ifp->if_u1.if_data[size] = '\0'; } else { ifp->if_u1.if_data = NULL; } ifp->if_bytes = size; ifp->if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); ifp->if_flags |= XFS_IFINLINE; } /* * The file is in-lined in the on-disk inode. */ STATIC int xfs_iformat_local( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork, int size) { /* * If the size is unreasonable, then something * is wrong and we just bail out rather than crash in * kmem_alloc() or memcpy() below. */ if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { xfs_warn(ip->i_mount, "corrupt inode %Lu (bad size %d for local fork, size = %d).", (unsigned long long) ip->i_ino, size, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_local", dip, sizeof(*dip), __this_address); return -EFSCORRUPTED; } xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size); return 0; } /* * The file consists of a set of extents all of which fit into the on-disk * inode. */ STATIC int xfs_iformat_extents( struct xfs_inode *ip, struct xfs_dinode *dip, int whichfork) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); int state = xfs_bmap_fork_to_state(whichfork); int nex = XFS_DFORK_NEXTENTS(dip, whichfork); int size = nex * sizeof(xfs_bmbt_rec_t); struct xfs_iext_cursor icur; struct xfs_bmbt_rec *dp; struct xfs_bmbt_irec new; int i; /* * If the number of extents is unreasonable, then something is wrong and * we just bail out rather than crash in kmem_alloc() or memcpy() below. */ if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, mp, whichfork))) { xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).", (unsigned long long) ip->i_ino, nex); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_extents(1)", dip, sizeof(*dip), __this_address); return -EFSCORRUPTED; } ifp->if_bytes = 0; ifp->if_u1.if_root = NULL; ifp->if_height = 0; if (size) { dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); xfs_iext_first(ifp, &icur); for (i = 0; i < nex; i++, dp++) { xfs_failaddr_t fa; xfs_bmbt_disk_get_all(dp, &new); fa = xfs_bmap_validate_extent(ip, whichfork, &new); if (fa) { xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_extents(2)", dp, sizeof(*dp), fa); return -EFSCORRUPTED; } xfs_iext_insert(ip, &icur, &new, state); trace_xfs_read_extent(ip, &icur, state, _THIS_IP_); xfs_iext_next(ifp, &icur); } } ifp->if_flags |= XFS_IFEXTENTS; return 0; } /* * The file has too many extents to fit into * the inode, so they are in B-tree format. * Allocate a buffer for the root of the B-tree * and copy the root into it. The i_extents * field will remain NULL until all of the * extents are read in (when they are needed). */ STATIC int xfs_iformat_btree( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork) { struct xfs_mount *mp = ip->i_mount; xfs_bmdr_block_t *dfp; struct xfs_ifork *ifp; /* REFERENCED */ int nrecs; int size; int level; ifp = XFS_IFORK_PTR(ip, whichfork); dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); size = XFS_BMAP_BROOT_SPACE(mp, dfp); nrecs = be16_to_cpu(dfp->bb_numrecs); level = be16_to_cpu(dfp->bb_level); /* * blow out if -- fork has less extents than can fit in * fork (fork shouldn't be a btree format), root btree * block has more records than can fit into the fork, * or the number of extents is greater than the number of * blocks. */ if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= XFS_IFORK_MAXEXT(ip, whichfork) || nrecs == 0 || XFS_BMDR_SPACE_CALC(nrecs) > XFS_DFORK_SIZE(dip, mp, whichfork) || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks) || level == 0 || level > XFS_BTREE_MAXLEVELS) { xfs_warn(mp, "corrupt inode %Lu (btree).", (unsigned long long) ip->i_ino); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_btree", dfp, size, __this_address); return -EFSCORRUPTED; } ifp->if_broot_bytes = size; ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS); ASSERT(ifp->if_broot != NULL); /* * Copy and convert from the on-disk structure * to the in-memory structure. */ xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), ifp->if_broot, size); ifp->if_flags &= ~XFS_IFEXTENTS; ifp->if_flags |= XFS_IFBROOT; ifp->if_bytes = 0; ifp->if_u1.if_root = NULL; ifp->if_height = 0; return 0; } /* * Reallocate the space for if_broot based on the number of records * being added or deleted as indicated in rec_diff. Move the records * and pointers in if_broot to fit the new size. When shrinking this * will eliminate holes between the records and pointers created by * the caller. When growing this will create holes to be filled in * by the caller. * * The caller must not request to add more records than would fit in * the on-disk inode root. If the if_broot is currently NULL, then * if we are adding records, one will be allocated. The caller must also * not request that the number of records go below zero, although * it can go to zero. * * ip -- the inode whose if_broot area is changing * ext_diff -- the change in the number of records, positive or negative, * requested for the if_broot array. */ void xfs_iroot_realloc( xfs_inode_t *ip, int rec_diff, int whichfork) { struct xfs_mount *mp = ip->i_mount; int cur_max; struct xfs_ifork *ifp; struct xfs_btree_block *new_broot; int new_max; size_t new_size; char *np; char *op; /* * Handle the degenerate case quietly. */ if (rec_diff == 0) { return; } ifp = XFS_IFORK_PTR(ip, whichfork); if (rec_diff > 0) { /* * If there wasn't any memory allocated before, just * allocate it now and get out. */ if (ifp->if_broot_bytes == 0) { new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff); ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); ifp->if_broot_bytes = (int)new_size; return; } /* * If there is already an existing if_broot, then we need * to realloc() it and shift the pointers to their new * location. The records don't change location because * they are kept butted up against the btree block header. */ cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); new_max = cur_max + rec_diff; new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, KM_SLEEP | KM_NOFS); op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, ifp->if_broot_bytes); np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, (int)new_size); ifp->if_broot_bytes = (int)new_size; ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= XFS_IFORK_SIZE(ip, whichfork)); memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t)); return; } /* * rec_diff is less than 0. In this case, we are shrinking the * if_broot buffer. It must already exist. If we go to zero * records, just get rid of the root and clear the status bit. */ ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); new_max = cur_max + rec_diff; ASSERT(new_max >= 0); if (new_max > 0) new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); else new_size = 0; if (new_size > 0) { new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); /* * First copy over the btree block header. */ memcpy(new_broot, ifp->if_broot, XFS_BMBT_BLOCK_LEN(ip->i_mount)); } else { new_broot = NULL; ifp->if_flags &= ~XFS_IFBROOT; } /* * Only copy the records and pointers if there are any. */ if (new_max > 0) { /* * First copy the records. */ op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1); np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1); memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t)); /* * Then copy the pointers. */ op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, ifp->if_broot_bytes); np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1, (int)new_size); memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); } kmem_free(ifp->if_broot); ifp->if_broot = new_broot; ifp->if_broot_bytes = (int)new_size; if (ifp->if_broot) ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= XFS_IFORK_SIZE(ip, whichfork)); return; } /* * This is called when the amount of space needed for if_data * is increased or decreased. The change in size is indicated by * the number of bytes that need to be added or deleted in the * byte_diff parameter. * * If the amount of space needed has decreased below the size of the * inline buffer, then switch to using the inline buffer. Otherwise, * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer * to what is needed. * * ip -- the inode whose if_data area is changing * byte_diff -- the change in the number of bytes, positive or negative, * requested for the if_data array. */ void xfs_idata_realloc( struct xfs_inode *ip, int byte_diff, int whichfork) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); int new_size = (int)ifp->if_bytes + byte_diff; ASSERT(new_size >= 0); ASSERT(new_size <= XFS_IFORK_SIZE(ip, whichfork)); if (byte_diff == 0) return; if (new_size == 0) { kmem_free(ifp->if_u1.if_data); ifp->if_u1.if_data = NULL; ifp->if_bytes = 0; return; } /* * For inline data, the underlying buffer must be a multiple of 4 bytes * in size so that it can be logged and stay on word boundaries. * We enforce that here. */ ifp->if_u1.if_data = kmem_realloc(ifp->if_u1.if_data, roundup(new_size, 4), KM_SLEEP | KM_NOFS); ifp->if_bytes = new_size; } void xfs_idestroy_fork( xfs_inode_t *ip, int whichfork) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(ip, whichfork); if (ifp->if_broot != NULL) { kmem_free(ifp->if_broot); ifp->if_broot = NULL; } /* * If the format is local, then we can't have an extents * array so just look for an inline data array. If we're * not local then we may or may not have an extents list, * so check and free it up if we do. */ if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { if (ifp->if_u1.if_data != NULL) { kmem_free(ifp->if_u1.if_data); ifp->if_u1.if_data = NULL; } } else if ((ifp->if_flags & XFS_IFEXTENTS) && ifp->if_height) { xfs_iext_destroy(ifp); } if (whichfork == XFS_ATTR_FORK) { kmem_zone_free(xfs_ifork_zone, ip->i_afp); ip->i_afp = NULL; } else if (whichfork == XFS_COW_FORK) { kmem_zone_free(xfs_ifork_zone, ip->i_cowfp); ip->i_cowfp = NULL; } } /* * Convert in-core extents to on-disk form * * In the case of the data fork, the in-core and on-disk fork sizes can be * different due to delayed allocation extents. We only copy on-disk extents * here, so callers must always use the physical fork size to determine the * size of the buffer passed to this routine. We will return the size actually * used. */ int xfs_iextents_copy( struct xfs_inode *ip, struct xfs_bmbt_rec *dp, int whichfork) { int state = xfs_bmap_fork_to_state(whichfork); struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_iext_cursor icur; struct xfs_bmbt_irec rec; int copied = 0; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); ASSERT(ifp->if_bytes > 0); for_each_xfs_iext(ifp, &icur, &rec) { if (isnullstartblock(rec.br_startblock)) continue; ASSERT(xfs_bmap_validate_extent(ip, whichfork, &rec) == NULL); xfs_bmbt_disk_set_all(dp, &rec); trace_xfs_write_extent(ip, &icur, state, _RET_IP_); copied += sizeof(struct xfs_bmbt_rec); dp++; } ASSERT(copied > 0); ASSERT(copied <= ifp->if_bytes); return copied; } /* * Each of the following cases stores data into the same region * of the on-disk inode, so only one of them can be valid at * any given time. While it is possible to have conflicting formats * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is * in EXTENTS format, this can only happen when the fork has * changed formats after being modified but before being flushed. * In these cases, the format always takes precedence, because the * format indicates the current state of the fork. */ void xfs_iflush_fork( xfs_inode_t *ip, xfs_dinode_t *dip, xfs_inode_log_item_t *iip, int whichfork) { char *cp; struct xfs_ifork *ifp; xfs_mount_t *mp; static const short brootflag[2] = { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; static const short dataflag[2] = { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; static const short extflag[2] = { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; if (!iip) return; ifp = XFS_IFORK_PTR(ip, whichfork); /* * This can happen if we gave up in iformat in an error path, * for the attribute fork. */ if (!ifp) { ASSERT(whichfork == XFS_ATTR_FORK); return; } cp = XFS_DFORK_PTR(dip, whichfork); mp = ip->i_mount; switch (XFS_IFORK_FORMAT(ip, whichfork)) { case XFS_DINODE_FMT_LOCAL: if ((iip->ili_fields & dataflag[whichfork]) && (ifp->if_bytes > 0)) { ASSERT(ifp->if_u1.if_data != NULL); ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); } break; case XFS_DINODE_FMT_EXTENTS: ASSERT((ifp->if_flags & XFS_IFEXTENTS) || !(iip->ili_fields & extflag[whichfork])); if ((iip->ili_fields & extflag[whichfork]) && (ifp->if_bytes > 0)) { ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp, whichfork); } break; case XFS_DINODE_FMT_BTREE: if ((iip->ili_fields & brootflag[whichfork]) && (ifp->if_broot_bytes > 0)) { ASSERT(ifp->if_broot != NULL); ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= XFS_IFORK_SIZE(ip, whichfork)); xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes, (xfs_bmdr_block_t *)cp, XFS_DFORK_SIZE(dip, mp, whichfork)); } break; case XFS_DINODE_FMT_DEV: if (iip->ili_fields & XFS_ILOG_DEV) { ASSERT(whichfork == XFS_DATA_FORK); xfs_dinode_put_rdev(dip, linux_to_xfs_dev_t(VFS_I(ip)->i_rdev)); } break; default: ASSERT(0); break; } } /* Convert bmap state flags to an inode fork. */ struct xfs_ifork * xfs_iext_state_to_fork( struct xfs_inode *ip, int state) { if (state & BMAP_COWFORK) return ip->i_cowfp; else if (state & BMAP_ATTRFORK) return ip->i_afp; return &ip->i_df; } /* * Initialize an inode's copy-on-write fork. */ void xfs_ifork_init_cow( struct xfs_inode *ip) { if (ip->i_cowfp) return; ip->i_cowfp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); ip->i_cowfp->if_flags = XFS_IFEXTENTS; ip->i_cformat = XFS_DINODE_FMT_EXTENTS; ip->i_cnextents = 0; } /* Default fork content verifiers. */ struct xfs_ifork_ops xfs_default_ifork_ops = { .verify_attr = xfs_attr_shortform_verify, .verify_dir = xfs_dir2_sf_verify, .verify_symlink = xfs_symlink_shortform_verify, }; /* Verify the inline contents of the data fork of an inode. */ xfs_failaddr_t xfs_ifork_verify_data( struct xfs_inode *ip, struct xfs_ifork_ops *ops) { /* Non-local data fork, we're done. */ if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) return NULL; /* Check the inline data fork if there is one. */ switch (VFS_I(ip)->i_mode & S_IFMT) { case S_IFDIR: return ops->verify_dir(ip); case S_IFLNK: return ops->verify_symlink(ip); default: return NULL; } } /* Verify the inline contents of the attr fork of an inode. */ xfs_failaddr_t xfs_ifork_verify_attr( struct xfs_inode *ip, struct xfs_ifork_ops *ops) { /* There has to be an attr fork allocated if aformat is local. */ if (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) return NULL; if (!XFS_IFORK_PTR(ip, XFS_ATTR_FORK)) return __this_address; return ops->verify_attr(ip); } xfsprogs-5.3.0/libxfs/xfs_inode_fork.h0000644000175000017500000001353113570057155017716 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_INODE_FORK_H__ #define __XFS_INODE_FORK_H__ struct xfs_inode_log_item; struct xfs_dinode; /* * File incore extent information, present for each of data & attr forks. */ struct xfs_ifork { int if_bytes; /* bytes in if_u1 */ unsigned int if_seq; /* fork mod counter */ struct xfs_btree_block *if_broot; /* file's incore btree root */ short if_broot_bytes; /* bytes allocated for root */ unsigned char if_flags; /* per-fork flags */ int if_height; /* height of the extent tree */ union { void *if_root; /* extent tree root */ char *if_data; /* inline file data */ } if_u1; }; /* * Per-fork incore inode flags. */ #define XFS_IFINLINE 0x01 /* Inline data is read in */ #define XFS_IFEXTENTS 0x02 /* All extent pointers are read in */ #define XFS_IFBROOT 0x04 /* i_broot points to the bmap b-tree root */ /* * Fork handling. */ #define XFS_IFORK_Q(ip) ((ip)->i_d.di_forkoff != 0) #define XFS_IFORK_BOFF(ip) ((int)((ip)->i_d.di_forkoff << 3)) #define XFS_IFORK_PTR(ip,w) \ ((w) == XFS_DATA_FORK ? \ &(ip)->i_df : \ ((w) == XFS_ATTR_FORK ? \ (ip)->i_afp : \ (ip)->i_cowfp)) #define XFS_IFORK_DSIZE(ip) \ (XFS_IFORK_Q(ip) ? \ XFS_IFORK_BOFF(ip) : \ XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version)) #define XFS_IFORK_ASIZE(ip) \ (XFS_IFORK_Q(ip) ? \ XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version) - \ XFS_IFORK_BOFF(ip) : \ 0) #define XFS_IFORK_SIZE(ip,w) \ ((w) == XFS_DATA_FORK ? \ XFS_IFORK_DSIZE(ip) : \ ((w) == XFS_ATTR_FORK ? \ XFS_IFORK_ASIZE(ip) : \ 0)) #define XFS_IFORK_FORMAT(ip,w) \ ((w) == XFS_DATA_FORK ? \ (ip)->i_d.di_format : \ ((w) == XFS_ATTR_FORK ? \ (ip)->i_d.di_aformat : \ (ip)->i_cformat)) #define XFS_IFORK_FMT_SET(ip,w,n) \ ((w) == XFS_DATA_FORK ? \ ((ip)->i_d.di_format = (n)) : \ ((w) == XFS_ATTR_FORK ? \ ((ip)->i_d.di_aformat = (n)) : \ ((ip)->i_cformat = (n)))) #define XFS_IFORK_NEXTENTS(ip,w) \ ((w) == XFS_DATA_FORK ? \ (ip)->i_d.di_nextents : \ ((w) == XFS_ATTR_FORK ? \ (ip)->i_d.di_anextents : \ (ip)->i_cnextents)) #define XFS_IFORK_NEXT_SET(ip,w,n) \ ((w) == XFS_DATA_FORK ? \ ((ip)->i_d.di_nextents = (n)) : \ ((w) == XFS_ATTR_FORK ? \ ((ip)->i_d.di_anextents = (n)) : \ ((ip)->i_cnextents = (n)))) #define XFS_IFORK_MAXEXT(ip, w) \ (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t)) struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state); int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *); void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *, struct xfs_inode_log_item *, int); void xfs_idestroy_fork(struct xfs_inode *, int); void xfs_idata_realloc(struct xfs_inode *, int, int); void xfs_iroot_realloc(struct xfs_inode *, int, int); int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, int); void xfs_init_local_fork(struct xfs_inode *, int, const void *, int); xfs_extnum_t xfs_iext_count(struct xfs_ifork *ifp); void xfs_iext_insert(struct xfs_inode *, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *, int); void xfs_iext_remove(struct xfs_inode *, struct xfs_iext_cursor *, int); void xfs_iext_destroy(struct xfs_ifork *); bool xfs_iext_lookup_extent(struct xfs_inode *ip, struct xfs_ifork *ifp, xfs_fileoff_t bno, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp); bool xfs_iext_lookup_extent_before(struct xfs_inode *ip, struct xfs_ifork *ifp, xfs_fileoff_t *end, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp); bool xfs_iext_get_extent(struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp); void xfs_iext_update_extent(struct xfs_inode *ip, int state, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp); void xfs_iext_first(struct xfs_ifork *, struct xfs_iext_cursor *); void xfs_iext_last(struct xfs_ifork *, struct xfs_iext_cursor *); void xfs_iext_next(struct xfs_ifork *, struct xfs_iext_cursor *); void xfs_iext_prev(struct xfs_ifork *, struct xfs_iext_cursor *); static inline bool xfs_iext_next_extent(struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { xfs_iext_next(ifp, cur); return xfs_iext_get_extent(ifp, cur, gotp); } static inline bool xfs_iext_prev_extent(struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { xfs_iext_prev(ifp, cur); return xfs_iext_get_extent(ifp, cur, gotp); } /* * Return the extent after cur in gotp without updating the cursor. */ static inline bool xfs_iext_peek_next_extent(struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { struct xfs_iext_cursor ncur = *cur; xfs_iext_next(ifp, &ncur); return xfs_iext_get_extent(ifp, &ncur, gotp); } /* * Return the extent before cur in gotp without updating the cursor. */ static inline bool xfs_iext_peek_prev_extent(struct xfs_ifork *ifp, struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp) { struct xfs_iext_cursor ncur = *cur; xfs_iext_prev(ifp, &ncur); return xfs_iext_get_extent(ifp, &ncur, gotp); } #define for_each_xfs_iext(ifp, ext, got) \ for (xfs_iext_first((ifp), (ext)); \ xfs_iext_get_extent((ifp), (ext), (got)); \ xfs_iext_next((ifp), (ext))) extern struct kmem_zone *xfs_ifork_zone; extern void xfs_ifork_init_cow(struct xfs_inode *ip); typedef xfs_failaddr_t (*xfs_ifork_verifier_t)(struct xfs_inode *); struct xfs_ifork_ops { xfs_ifork_verifier_t verify_symlink; xfs_ifork_verifier_t verify_dir; xfs_ifork_verifier_t verify_attr; }; extern struct xfs_ifork_ops xfs_default_ifork_ops; xfs_failaddr_t xfs_ifork_verify_data(struct xfs_inode *ip, struct xfs_ifork_ops *ops); xfs_failaddr_t xfs_ifork_verify_attr(struct xfs_inode *ip, struct xfs_ifork_ops *ops); #endif /* __XFS_INODE_FORK_H__ */ xfsprogs-5.3.0/libxfs/xfs_log_format.h0000644000175000017500000007100713435336036017730 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_LOG_FORMAT_H__ #define __XFS_LOG_FORMAT_H__ struct xfs_mount; struct xfs_trans_res; /* * On-disk Log Format definitions. * * This file contains all the on-disk format definitions used within the log. It * includes the physical log structure itself, as well as all the log item * format structures that are written into the log and intepreted by log * recovery. We start with the physical log format definitions, and then work * through all the log items definitions and everything they encode into the * log. */ typedef uint32_t xlog_tid_t; #define XLOG_MIN_ICLOGS 2 #define XLOG_MAX_ICLOGS 8 #define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */ #define XLOG_VERSION_1 1 #define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ #define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) #define XLOG_MIN_RECORD_BSIZE (16*1024) /* eventually 32k */ #define XLOG_BIG_RECORD_BSIZE (32*1024) /* 32k buffers */ #define XLOG_MAX_RECORD_BSIZE (256*1024) #define XLOG_HEADER_CYCLE_SIZE (32*1024) /* cycle data in header */ #define XLOG_MIN_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */ #define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */ #define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */ #define XLOG_BTOLSUNIT(log, b) (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \ (log)->l_mp->m_sb.sb_logsunit) #define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit) #define XLOG_HEADER_SIZE 512 /* Minimum number of transactions that must fit in the log (defined by mkfs) */ #define XFS_MIN_LOG_FACTOR 3 #define XLOG_REC_SHIFT(log) \ BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) #define XLOG_TOTAL_REC_SHIFT(log) \ BTOBB(XLOG_MAX_ICLOGS << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) /* get lsn fields */ #define CYCLE_LSN(lsn) ((uint)((lsn)>>32)) #define BLOCK_LSN(lsn) ((uint)(lsn)) /* this is used in a spot where we might otherwise double-endian-flip */ #define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0]) static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block) { return ((xfs_lsn_t)cycle << 32) | block; } static inline uint xlog_get_cycle(char *ptr) { if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM) return be32_to_cpu(*((__be32 *)ptr + 1)); else return be32_to_cpu(*(__be32 *)ptr); } /* Log Clients */ #define XFS_TRANSACTION 0x69 #define XFS_VOLUME 0x2 #define XFS_LOG 0xaa #define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */ /* * Log item for unmount records. * * The unmount record used to have a string "Unmount filesystem--" in the * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE). * We just write the magic number now; see xfs_log_unmount_write. */ struct xfs_unmount_log_format { uint16_t magic; /* XLOG_UNMOUNT_TYPE */ uint16_t pad1; uint32_t pad2; /* may as well make it 64 bits */ }; /* Region types for iovec's i_type */ #define XLOG_REG_TYPE_BFORMAT 1 #define XLOG_REG_TYPE_BCHUNK 2 #define XLOG_REG_TYPE_EFI_FORMAT 3 #define XLOG_REG_TYPE_EFD_FORMAT 4 #define XLOG_REG_TYPE_IFORMAT 5 #define XLOG_REG_TYPE_ICORE 6 #define XLOG_REG_TYPE_IEXT 7 #define XLOG_REG_TYPE_IBROOT 8 #define XLOG_REG_TYPE_ILOCAL 9 #define XLOG_REG_TYPE_IATTR_EXT 10 #define XLOG_REG_TYPE_IATTR_BROOT 11 #define XLOG_REG_TYPE_IATTR_LOCAL 12 #define XLOG_REG_TYPE_QFORMAT 13 #define XLOG_REG_TYPE_DQUOT 14 #define XLOG_REG_TYPE_QUOTAOFF 15 #define XLOG_REG_TYPE_LRHEADER 16 #define XLOG_REG_TYPE_UNMOUNT 17 #define XLOG_REG_TYPE_COMMIT 18 #define XLOG_REG_TYPE_TRANSHDR 19 #define XLOG_REG_TYPE_ICREATE 20 #define XLOG_REG_TYPE_RUI_FORMAT 21 #define XLOG_REG_TYPE_RUD_FORMAT 22 #define XLOG_REG_TYPE_CUI_FORMAT 23 #define XLOG_REG_TYPE_CUD_FORMAT 24 #define XLOG_REG_TYPE_BUI_FORMAT 25 #define XLOG_REG_TYPE_BUD_FORMAT 26 #define XLOG_REG_TYPE_MAX 26 /* * Flags to log operation header * * The first write of a new transaction will be preceded with a start * record, XLOG_START_TRANS. Once a transaction is committed, a commit * record is written, XLOG_COMMIT_TRANS. If a single region can not fit into * the remainder of the current active in-core log, it is split up into * multiple regions. Each partial region will be marked with a * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS. * */ #define XLOG_START_TRANS 0x01 /* Start a new transaction */ #define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */ #define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */ #define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */ #define XLOG_END_TRANS 0x10 /* End a continued transaction */ #define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */ typedef struct xlog_op_header { __be32 oh_tid; /* transaction id of operation : 4 b */ __be32 oh_len; /* bytes in data region : 4 b */ __u8 oh_clientid; /* who sent me this : 1 b */ __u8 oh_flags; /* : 1 b */ __u16 oh_res2; /* 32 bit align : 2 b */ } xlog_op_header_t; /* valid values for h_fmt */ #define XLOG_FMT_UNKNOWN 0 #define XLOG_FMT_LINUX_LE 1 #define XLOG_FMT_LINUX_BE 2 #define XLOG_FMT_IRIX_BE 3 /* our fmt */ #ifdef XFS_NATIVE_HOST #define XLOG_FMT XLOG_FMT_LINUX_BE #else #define XLOG_FMT XLOG_FMT_LINUX_LE #endif typedef struct xlog_rec_header { __be32 h_magicno; /* log record (LR) identifier : 4 */ __be32 h_cycle; /* write cycle of log : 4 */ __be32 h_version; /* LR version : 4 */ __be32 h_len; /* len in bytes; should be 64-bit aligned: 4 */ __be64 h_lsn; /* lsn of this LR : 8 */ __be64 h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ __le32 h_crc; /* crc of log record : 4 */ __be32 h_prev_block; /* block number to previous LR : 4 */ __be32 h_num_logops; /* number of log operations in this LR : 4 */ __be32 h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* new fields */ __be32 h_fmt; /* format of log record : 4 */ uuid_t h_fs_uuid; /* uuid of FS : 16 */ __be32 h_size; /* iclog size : 4 */ } xlog_rec_header_t; typedef struct xlog_rec_ext_header { __be32 xh_cycle; /* write cycle of log : 4 */ __be32 xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ } xlog_rec_ext_header_t; /* * Quite misnamed, because this union lays out the actual on-disk log buffer. */ typedef union xlog_in_core2 { xlog_rec_header_t hic_header; xlog_rec_ext_header_t hic_xheader; char hic_sector[XLOG_HEADER_SIZE]; } xlog_in_core_2_t; /* not an on-disk structure, but needed by log recovery in userspace */ typedef struct xfs_log_iovec { void *i_addr; /* beginning address of region */ int i_len; /* length in bytes of region */ uint i_type; /* type of region */ } xfs_log_iovec_t; /* * Transaction Header definitions. * * This is the structure written in the log at the head of every transaction. It * identifies the type and id of the transaction, and contains the number of * items logged by the transaction so we know how many to expect during * recovery. * * Do not change the below structure without redoing the code in * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). */ typedef struct xfs_trans_header { uint th_magic; /* magic number */ uint th_type; /* transaction type */ int32_t th_tid; /* transaction id (unused) */ uint th_num_items; /* num items logged by trans */ } xfs_trans_header_t; #define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ /* * The only type valid for th_type in CIL-enabled file system logs: */ #define XFS_TRANS_CHECKPOINT 40 /* * Log item types. */ #define XFS_LI_EFI 0x1236 #define XFS_LI_EFD 0x1237 #define XFS_LI_IUNLINK 0x1238 #define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ #define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ #define XFS_LI_DQUOT 0x123d #define XFS_LI_QUOTAOFF 0x123e #define XFS_LI_ICREATE 0x123f #define XFS_LI_RUI 0x1240 /* rmap update intent */ #define XFS_LI_RUD 0x1241 #define XFS_LI_CUI 0x1242 /* refcount update intent */ #define XFS_LI_CUD 0x1243 #define XFS_LI_BUI 0x1244 /* bmbt update intent */ #define XFS_LI_BUD 0x1245 #define XFS_LI_TYPE_DESC \ { XFS_LI_EFI, "XFS_LI_EFI" }, \ { XFS_LI_EFD, "XFS_LI_EFD" }, \ { XFS_LI_IUNLINK, "XFS_LI_IUNLINK" }, \ { XFS_LI_INODE, "XFS_LI_INODE" }, \ { XFS_LI_BUF, "XFS_LI_BUF" }, \ { XFS_LI_DQUOT, "XFS_LI_DQUOT" }, \ { XFS_LI_QUOTAOFF, "XFS_LI_QUOTAOFF" }, \ { XFS_LI_ICREATE, "XFS_LI_ICREATE" }, \ { XFS_LI_RUI, "XFS_LI_RUI" }, \ { XFS_LI_RUD, "XFS_LI_RUD" }, \ { XFS_LI_CUI, "XFS_LI_CUI" }, \ { XFS_LI_CUD, "XFS_LI_CUD" }, \ { XFS_LI_BUI, "XFS_LI_BUI" }, \ { XFS_LI_BUD, "XFS_LI_BUD" } /* * Inode Log Item Format definitions. * * This is the structure used to lay out an inode log item in the * log. The size of the inline data/extents/b-tree root to be logged * (if any) is indicated in the ilf_dsize field. Changes to this structure * must be added on to the end. */ struct xfs_inode_log_format { uint16_t ilf_type; /* inode log item type */ uint16_t ilf_size; /* size of this item */ uint32_t ilf_fields; /* flags for fields logged */ uint16_t ilf_asize; /* size of attr d/ext/root */ uint16_t ilf_dsize; /* size of data/ext/root */ uint32_t ilf_pad; /* pad for 64 bit boundary */ uint64_t ilf_ino; /* inode number */ union { uint32_t ilfu_rdev; /* rdev value for dev inode*/ uint8_t __pad[16]; /* unused */ } ilf_u; int64_t ilf_blkno; /* blkno of inode buffer */ int32_t ilf_len; /* len of inode buffer */ int32_t ilf_boffset; /* off of inode in buffer */ }; /* * Old 32 bit systems will log in this format without the 64 bit * alignment padding. Recovery will detect this and convert it to the * correct format. */ struct xfs_inode_log_format_32 { uint16_t ilf_type; /* inode log item type */ uint16_t ilf_size; /* size of this item */ uint32_t ilf_fields; /* flags for fields logged */ uint16_t ilf_asize; /* size of attr d/ext/root */ uint16_t ilf_dsize; /* size of data/ext/root */ uint64_t ilf_ino; /* inode number */ union { uint32_t ilfu_rdev; /* rdev value for dev inode*/ uint8_t __pad[16]; /* unused */ } ilf_u; int64_t ilf_blkno; /* blkno of inode buffer */ int32_t ilf_len; /* len of inode buffer */ int32_t ilf_boffset; /* off of inode in buffer */ } __attribute__((packed)); /* * Flags for xfs_trans_log_inode flags field. */ #define XFS_ILOG_CORE 0x001 /* log standard inode fields */ #define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */ #define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */ #define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */ #define XFS_ILOG_DEV 0x010 /* log the dev field */ #define XFS_ILOG_UUID 0x020 /* added long ago, but never used */ #define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ #define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ #define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ #define XFS_ILOG_DOWNER 0x200 /* change the data fork owner on replay */ #define XFS_ILOG_AOWNER 0x400 /* change the attr fork owner on replay */ /* * The timestamps are dirty, but not necessarily anything else in the inode * core. Unlike the other fields above this one must never make it to disk * in the ilf_fields of the inode_log_format, but is purely store in-memory in * ili_fields in the inode_log_item. */ #define XFS_ILOG_TIMESTAMP 0x4000 #define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ XFS_ILOG_ABROOT | XFS_ILOG_DOWNER | \ XFS_ILOG_AOWNER) #define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ XFS_ILOG_DBROOT) #define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ XFS_ILOG_ABROOT) #define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \ XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ XFS_ILOG_DEV | XFS_ILOG_ADATA | \ XFS_ILOG_AEXT | XFS_ILOG_ABROOT | \ XFS_ILOG_TIMESTAMP | XFS_ILOG_DOWNER | \ XFS_ILOG_AOWNER) static inline int xfs_ilog_fbroot(int w) { return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT); } static inline int xfs_ilog_fext(int w) { return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT); } static inline int xfs_ilog_fdata(int w) { return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA); } /* * Incore version of the on-disk inode core structures. We log this directly * into the journal in host CPU format (for better or worse) and as such * directly mirrors the xfs_dinode structure as it must contain all the same * information. */ typedef struct xfs_ictimestamp { int32_t t_sec; /* timestamp seconds */ int32_t t_nsec; /* timestamp nanoseconds */ } xfs_ictimestamp_t; /* * Define the format of the inode core that is logged. This structure must be * kept identical to struct xfs_dinode except for the endianness annotations. */ struct xfs_log_dinode { uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ uint16_t di_mode; /* mode and type of file */ int8_t di_version; /* inode version */ int8_t di_format; /* format of di_c data */ uint8_t di_pad3[2]; /* unused in v2/3 inodes */ uint32_t di_uid; /* owner's user id */ uint32_t di_gid; /* owner's group id */ uint32_t di_nlink; /* number of links to file */ uint16_t di_projid_lo; /* lower part of owner's project id */ uint16_t di_projid_hi; /* higher part of owner's project id */ uint8_t di_pad[6]; /* unused, zeroed space */ uint16_t di_flushiter; /* incremented on flush */ xfs_ictimestamp_t di_atime; /* time last accessed */ xfs_ictimestamp_t di_mtime; /* time last modified */ xfs_ictimestamp_t di_ctime; /* time created/inode modified */ xfs_fsize_t di_size; /* number of bytes in file */ xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */ xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ xfs_extnum_t di_nextents; /* number of extents in data fork */ xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ int8_t di_aformat; /* format of attr fork's data */ uint32_t di_dmevmask; /* DMIG event mask */ uint16_t di_dmstate; /* DMIG state info */ uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ uint32_t di_gen; /* generation number */ /* di_next_unlinked is the only non-core field in the old dinode */ xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ /* start of the extended dinode, writable fields */ uint32_t di_crc; /* CRC of the inode */ uint64_t di_changecount; /* number of attribute changes */ xfs_lsn_t di_lsn; /* flush sequence */ uint64_t di_flags2; /* more random flags */ uint32_t di_cowextsize; /* basic cow extent size for file */ uint8_t di_pad2[12]; /* more padding for future expansion */ /* fields only written to during inode creation */ xfs_ictimestamp_t di_crtime; /* time created */ xfs_ino_t di_ino; /* inode number */ uuid_t di_uuid; /* UUID of the filesystem */ /* structure must be padded to 64 bit alignment */ }; static inline uint xfs_log_dinode_size(int version) { if (version == 3) return sizeof(struct xfs_log_dinode); return offsetof(struct xfs_log_dinode, di_next_unlinked); } /* * Buffer Log Format defintions * * These are the physical dirty bitmap defintions for the log format structure. */ #define XFS_BLF_CHUNK 128 #define XFS_BLF_SHIFT 7 #define BIT_TO_WORD_SHIFT 5 #define NBWORD (NBBY * sizeof(unsigned int)) /* * This flag indicates that the buffer contains on disk inodes * and requires special recovery handling. */ #define XFS_BLF_INODE_BUF (1<<0) /* * This flag indicates that the buffer should not be replayed * during recovery because its blocks are being freed. */ #define XFS_BLF_CANCEL (1<<1) /* * This flag indicates that the buffer contains on disk * user or group dquots and may require special recovery handling. */ #define XFS_BLF_UDQUOT_BUF (1<<2) #define XFS_BLF_PDQUOT_BUF (1<<3) #define XFS_BLF_GDQUOT_BUF (1<<4) /* * This is the structure used to lay out a buf log item in the * log. The data map describes which 128 byte chunks of the buffer * have been logged. */ #define XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD) typedef struct xfs_buf_log_format { unsigned short blf_type; /* buf log item type indicator */ unsigned short blf_size; /* size of this item */ unsigned short blf_flags; /* misc state */ unsigned short blf_len; /* number of blocks in this buf */ int64_t blf_blkno; /* starting blkno of this buf */ unsigned int blf_map_size; /* used size of data bitmap in words */ unsigned int blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */ } xfs_buf_log_format_t; /* * All buffers now need to tell recovery where the magic number * is so that it can verify and calculate the CRCs on the buffer correctly * once the changes have been replayed into the buffer. * * The type value is held in the upper 5 bits of the blf_flags field, which is * an unsigned 16 bit field. Hence we need to shift it 11 bits up and down. */ #define XFS_BLFT_BITS 5 #define XFS_BLFT_SHIFT 11 #define XFS_BLFT_MASK (((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT) enum xfs_blft { XFS_BLFT_UNKNOWN_BUF = 0, XFS_BLFT_UDQUOT_BUF, XFS_BLFT_PDQUOT_BUF, XFS_BLFT_GDQUOT_BUF, XFS_BLFT_BTREE_BUF, XFS_BLFT_AGF_BUF, XFS_BLFT_AGFL_BUF, XFS_BLFT_AGI_BUF, XFS_BLFT_DINO_BUF, XFS_BLFT_SYMLINK_BUF, XFS_BLFT_DIR_BLOCK_BUF, XFS_BLFT_DIR_DATA_BUF, XFS_BLFT_DIR_FREE_BUF, XFS_BLFT_DIR_LEAF1_BUF, XFS_BLFT_DIR_LEAFN_BUF, XFS_BLFT_DA_NODE_BUF, XFS_BLFT_ATTR_LEAF_BUF, XFS_BLFT_ATTR_RMT_BUF, XFS_BLFT_SB_BUF, XFS_BLFT_RTBITMAP_BUF, XFS_BLFT_RTSUMMARY_BUF, XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS), }; static inline void xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type) { ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF); blf->blf_flags &= ~XFS_BLFT_MASK; blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK); } static inline uint16_t xfs_blft_from_flags(struct xfs_buf_log_format *blf) { return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT; } /* * EFI/EFD log format definitions */ typedef struct xfs_extent { xfs_fsblock_t ext_start; xfs_extlen_t ext_len; } xfs_extent_t; /* * Since an xfs_extent_t has types (start:64, len: 32) * there are different alignments on 32 bit and 64 bit kernels. * So we provide the different variants for use by a * conversion routine. */ typedef struct xfs_extent_32 { uint64_t ext_start; uint32_t ext_len; } __attribute__((packed)) xfs_extent_32_t; typedef struct xfs_extent_64 { uint64_t ext_start; uint32_t ext_len; uint32_t ext_pad; } xfs_extent_64_t; /* * This is the structure used to lay out an efi log item in the * log. The efi_extents field is a variable size array whose * size is given by efi_nextents. */ typedef struct xfs_efi_log_format { uint16_t efi_type; /* efi log item type */ uint16_t efi_size; /* size of this item */ uint32_t efi_nextents; /* # extents to free */ uint64_t efi_id; /* efi identifier */ xfs_extent_t efi_extents[1]; /* array of extents to free */ } xfs_efi_log_format_t; typedef struct xfs_efi_log_format_32 { uint16_t efi_type; /* efi log item type */ uint16_t efi_size; /* size of this item */ uint32_t efi_nextents; /* # extents to free */ uint64_t efi_id; /* efi identifier */ xfs_extent_32_t efi_extents[1]; /* array of extents to free */ } __attribute__((packed)) xfs_efi_log_format_32_t; typedef struct xfs_efi_log_format_64 { uint16_t efi_type; /* efi log item type */ uint16_t efi_size; /* size of this item */ uint32_t efi_nextents; /* # extents to free */ uint64_t efi_id; /* efi identifier */ xfs_extent_64_t efi_extents[1]; /* array of extents to free */ } xfs_efi_log_format_64_t; /* * This is the structure used to lay out an efd log item in the * log. The efd_extents array is a variable size array whose * size is given by efd_nextents; */ typedef struct xfs_efd_log_format { uint16_t efd_type; /* efd log item type */ uint16_t efd_size; /* size of this item */ uint32_t efd_nextents; /* # of extents freed */ uint64_t efd_efi_id; /* id of corresponding efi */ xfs_extent_t efd_extents[1]; /* array of extents freed */ } xfs_efd_log_format_t; typedef struct xfs_efd_log_format_32 { uint16_t efd_type; /* efd log item type */ uint16_t efd_size; /* size of this item */ uint32_t efd_nextents; /* # of extents freed */ uint64_t efd_efi_id; /* id of corresponding efi */ xfs_extent_32_t efd_extents[1]; /* array of extents freed */ } __attribute__((packed)) xfs_efd_log_format_32_t; typedef struct xfs_efd_log_format_64 { uint16_t efd_type; /* efd log item type */ uint16_t efd_size; /* size of this item */ uint32_t efd_nextents; /* # of extents freed */ uint64_t efd_efi_id; /* id of corresponding efi */ xfs_extent_64_t efd_extents[1]; /* array of extents freed */ } xfs_efd_log_format_64_t; /* * RUI/RUD (reverse mapping) log format definitions */ struct xfs_map_extent { uint64_t me_owner; uint64_t me_startblock; uint64_t me_startoff; uint32_t me_len; uint32_t me_flags; }; /* rmap me_flags: upper bits are flags, lower byte is type code */ #define XFS_RMAP_EXTENT_MAP 1 #define XFS_RMAP_EXTENT_MAP_SHARED 2 #define XFS_RMAP_EXTENT_UNMAP 3 #define XFS_RMAP_EXTENT_UNMAP_SHARED 4 #define XFS_RMAP_EXTENT_CONVERT 5 #define XFS_RMAP_EXTENT_CONVERT_SHARED 6 #define XFS_RMAP_EXTENT_ALLOC 7 #define XFS_RMAP_EXTENT_FREE 8 #define XFS_RMAP_EXTENT_TYPE_MASK 0xFF #define XFS_RMAP_EXTENT_ATTR_FORK (1U << 31) #define XFS_RMAP_EXTENT_BMBT_BLOCK (1U << 30) #define XFS_RMAP_EXTENT_UNWRITTEN (1U << 29) #define XFS_RMAP_EXTENT_FLAGS (XFS_RMAP_EXTENT_TYPE_MASK | \ XFS_RMAP_EXTENT_ATTR_FORK | \ XFS_RMAP_EXTENT_BMBT_BLOCK | \ XFS_RMAP_EXTENT_UNWRITTEN) /* * This is the structure used to lay out an rui log item in the * log. The rui_extents field is a variable size array whose * size is given by rui_nextents. */ struct xfs_rui_log_format { uint16_t rui_type; /* rui log item type */ uint16_t rui_size; /* size of this item */ uint32_t rui_nextents; /* # extents to free */ uint64_t rui_id; /* rui identifier */ struct xfs_map_extent rui_extents[]; /* array of extents to rmap */ }; static inline size_t xfs_rui_log_format_sizeof( unsigned int nr) { return sizeof(struct xfs_rui_log_format) + nr * sizeof(struct xfs_map_extent); } /* * This is the structure used to lay out an rud log item in the * log. The rud_extents array is a variable size array whose * size is given by rud_nextents; */ struct xfs_rud_log_format { uint16_t rud_type; /* rud log item type */ uint16_t rud_size; /* size of this item */ uint32_t __pad; uint64_t rud_rui_id; /* id of corresponding rui */ }; /* * CUI/CUD (refcount update) log format definitions */ struct xfs_phys_extent { uint64_t pe_startblock; uint32_t pe_len; uint32_t pe_flags; }; /* refcount pe_flags: upper bits are flags, lower byte is type code */ /* Type codes are taken directly from enum xfs_refcount_intent_type. */ #define XFS_REFCOUNT_EXTENT_TYPE_MASK 0xFF #define XFS_REFCOUNT_EXTENT_FLAGS (XFS_REFCOUNT_EXTENT_TYPE_MASK) /* * This is the structure used to lay out a cui log item in the * log. The cui_extents field is a variable size array whose * size is given by cui_nextents. */ struct xfs_cui_log_format { uint16_t cui_type; /* cui log item type */ uint16_t cui_size; /* size of this item */ uint32_t cui_nextents; /* # extents to free */ uint64_t cui_id; /* cui identifier */ struct xfs_phys_extent cui_extents[]; /* array of extents */ }; static inline size_t xfs_cui_log_format_sizeof( unsigned int nr) { return sizeof(struct xfs_cui_log_format) + nr * sizeof(struct xfs_phys_extent); } /* * This is the structure used to lay out a cud log item in the * log. The cud_extents array is a variable size array whose * size is given by cud_nextents; */ struct xfs_cud_log_format { uint16_t cud_type; /* cud log item type */ uint16_t cud_size; /* size of this item */ uint32_t __pad; uint64_t cud_cui_id; /* id of corresponding cui */ }; /* * BUI/BUD (inode block mapping) log format definitions */ /* bmbt me_flags: upper bits are flags, lower byte is type code */ /* Type codes are taken directly from enum xfs_bmap_intent_type. */ #define XFS_BMAP_EXTENT_TYPE_MASK 0xFF #define XFS_BMAP_EXTENT_ATTR_FORK (1U << 31) #define XFS_BMAP_EXTENT_UNWRITTEN (1U << 30) #define XFS_BMAP_EXTENT_FLAGS (XFS_BMAP_EXTENT_TYPE_MASK | \ XFS_BMAP_EXTENT_ATTR_FORK | \ XFS_BMAP_EXTENT_UNWRITTEN) /* * This is the structure used to lay out an bui log item in the * log. The bui_extents field is a variable size array whose * size is given by bui_nextents. */ struct xfs_bui_log_format { uint16_t bui_type; /* bui log item type */ uint16_t bui_size; /* size of this item */ uint32_t bui_nextents; /* # extents to free */ uint64_t bui_id; /* bui identifier */ struct xfs_map_extent bui_extents[]; /* array of extents to bmap */ }; static inline size_t xfs_bui_log_format_sizeof( unsigned int nr) { return sizeof(struct xfs_bui_log_format) + nr * sizeof(struct xfs_map_extent); } /* * This is the structure used to lay out an bud log item in the * log. The bud_extents array is a variable size array whose * size is given by bud_nextents; */ struct xfs_bud_log_format { uint16_t bud_type; /* bud log item type */ uint16_t bud_size; /* size of this item */ uint32_t __pad; uint64_t bud_bui_id; /* id of corresponding bui */ }; /* * Dquot Log format definitions. * * The first two fields must be the type and size fitting into * 32 bits : log_recovery code assumes that. */ typedef struct xfs_dq_logformat { uint16_t qlf_type; /* dquot log item type */ uint16_t qlf_size; /* size of this item */ xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */ int64_t qlf_blkno; /* blkno of dquot buffer */ int32_t qlf_len; /* len of dquot buffer */ uint32_t qlf_boffset; /* off of dquot in buffer */ } xfs_dq_logformat_t; /* * log format struct for QUOTAOFF records. * The first two fields must be the type and size fitting into * 32 bits : log_recovery code assumes that. * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer * to the first and ensures that the first logitem is taken out of the AIL * only when the last one is securely committed. */ typedef struct xfs_qoff_logformat { unsigned short qf_type; /* quotaoff log item type */ unsigned short qf_size; /* size of this item */ unsigned int qf_flags; /* USR and/or GRP */ char qf_pad[12]; /* padding for future */ } xfs_qoff_logformat_t; /* * Disk quotas status in m_qflags, and also sb_qflags. 16 bits. */ #define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ #define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ #define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ #define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */ #define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */ #define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */ #define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ /* * Conversion to and from the combined OQUOTA flag (if necessary) * is done only in xfs_sb_qflags_to_disk() and xfs_sb_qflags_from_disk() */ #define XFS_GQUOTA_ENFD 0x0080 /* group quota limits enforced */ #define XFS_GQUOTA_CHKD 0x0100 /* quotacheck run on group quotas */ #define XFS_PQUOTA_ENFD 0x0200 /* project quota limits enforced */ #define XFS_PQUOTA_CHKD 0x0400 /* quotacheck run on project quotas */ #define XFS_ALL_QUOTA_ACCT \ (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT) #define XFS_ALL_QUOTA_ENFD \ (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD) #define XFS_ALL_QUOTA_CHKD \ (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD) #define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\ XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD|\ XFS_PQUOTA_CHKD) /* * Inode create log item structure * * Log recovery assumes the first two entries are the type and size and they fit * in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so * decoding can be done correctly. */ struct xfs_icreate_log { uint16_t icl_type; /* type of log format structure */ uint16_t icl_size; /* size of log format structure */ __be32 icl_ag; /* ag being allocated in */ __be32 icl_agbno; /* start block of inode range */ __be32 icl_count; /* number of inodes to initialise */ __be32 icl_isize; /* size of inodes */ __be32 icl_length; /* length of extent to initialise */ __be32 icl_gen; /* inode generation number to use */ }; #endif /* __XFS_LOG_FORMAT_H__ */ xfsprogs-5.3.0/libxfs/xfs_log_rlimit.c0000644000175000017500000001004413570057155017727 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013 Jie Liu. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_trans_space.h" #include "xfs_da_btree.h" #include "xfs_bmap_btree.h" /* * Calculate the maximum length in bytes that would be required for a local * attribute value as large attributes out of line are not logged. */ STATIC int xfs_log_calc_max_attrsetm_res( struct xfs_mount *mp) { int size; int nblks; size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - MAXNAMELEN - 1; nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); nblks += XFS_B_TO_FSB(mp, size); nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); return M_RES(mp)->tr_attrsetm.tr_logres + M_RES(mp)->tr_attrsetrt.tr_logres * nblks; } /* * Iterate over the log space reservation table to figure out and return * the maximum one in terms of the pre-calculated values which were done * at mount time. */ void xfs_log_get_max_trans_res( struct xfs_mount *mp, struct xfs_trans_res *max_resp) { struct xfs_trans_res *resp; struct xfs_trans_res *end_resp; int log_space = 0; int attr_space; attr_space = xfs_log_calc_max_attrsetm_res(mp); resp = (struct xfs_trans_res *)M_RES(mp); end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); for (; resp < end_resp; resp++) { int tmp = resp->tr_logcount > 1 ? resp->tr_logres * resp->tr_logcount : resp->tr_logres; if (log_space < tmp) { log_space = tmp; *max_resp = *resp; /* struct copy */ } } if (attr_space > log_space) { *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ max_resp->tr_logres = attr_space; } } /* * Calculate the minimum valid log size for the given superblock configuration. * Used to calculate the minimum log size at mkfs time, and to determine if * the log is large enough or not at mount time. Returns the minimum size in * filesystem block size units. */ int xfs_log_calc_minimum_size( struct xfs_mount *mp) { struct xfs_trans_res tres = {0}; int max_logres; int min_logblks = 0; int lsunit = 0; xfs_log_get_max_trans_res(mp, &tres); max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); if (tres.tr_logcount > 1) max_logres *= tres.tr_logcount; if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) lsunit = BTOBB(mp->m_sb.sb_logsunit); /* * Two factors should be taken into account for calculating the minimum * log space. * 1) The fundamental limitation is that no single transaction can be * larger than half size of the log. * * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR * define, which is set to 3. That means we can definitely fit * maximally sized 2 transactions in the log. We'll use this same * value here. * * 2) If the lsunit option is specified, a transaction requires 2 LSU * for the reservation because there are two log writes that can * require padding - the transaction data and the commit record which * are written separately and both can require padding to the LSU. * Consider that we can have an active CIL reservation holding 2*LSU, * but the CIL is not over a push threshold, in this case, if we * don't have enough log space for at one new transaction, which * includes another 2*LSU in the reservation, we will run into dead * loop situation in log space grant procedure. i.e. * xlog_grant_head_wait(). * * Hence the log size needs to be able to contain two maximally sized * and padded transactions, which is (2 * (2 * LSU + maxlres)). * * Also, the log size should be a multiple of the log stripe unit, round * it up to lsunit boundary if lsunit is specified. */ if (lsunit) { min_logblks = roundup_64(BTOBB(max_logres), lsunit) + 2 * lsunit; } else min_logblks = BTOBB(max_logres) + 2 * BBSIZE; min_logblks *= XFS_MIN_LOG_FACTOR; return XFS_BB_TO_FSB(mp, min_logblks); } xfsprogs-5.3.0/libxfs/xfs_quota_defs.h0000644000175000017500000001350113570057155017726 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_QUOTA_DEFS_H__ #define __XFS_QUOTA_DEFS_H__ /* * Quota definitions shared between user and kernel source trees. */ /* * Even though users may not have quota limits occupying all 64-bits, * they may need 64-bit accounting. Hence, 64-bit quota-counters, * and quota-limits. This is a waste in the common case, but hey ... */ typedef uint64_t xfs_qcnt_t; typedef uint16_t xfs_qwarncnt_t; #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 /* * flags for q_flags field in the dquot. */ #define XFS_DQ_USER 0x0001 /* a user quota */ #define XFS_DQ_PROJ 0x0002 /* project quota */ #define XFS_DQ_GROUP 0x0004 /* a group quota */ #define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */ #define XFS_DQ_FREEING 0x0010 /* dquot is being torn down */ #define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) #define XFS_DQ_FLAGS \ { XFS_DQ_USER, "USER" }, \ { XFS_DQ_PROJ, "PROJ" }, \ { XFS_DQ_GROUP, "GROUP" }, \ { XFS_DQ_DIRTY, "DIRTY" }, \ { XFS_DQ_FREEING, "FREEING" } /* * We have the possibility of all three quota types being active at once, and * hence free space modification requires modification of all three current * dquots in a single transaction. For this case we need to have a reservation * of at least 3 dquots. * * However, a chmod operation can change both UID and GID in a single * transaction, resulting in requiring {old, new} x {uid, gid} dquots to be * modified. Hence for this case we need to reserve space for at least 4 dquots. * * And in the worst case, there's a rename operation that can be modifying up to * 4 inodes with dquots attached to them. In reality, the only inodes that can * have their dquots modified are the source and destination directory inodes * due to directory name creation and removal. That can require space allocation * and/or freeing on both directory inodes, and hence all three dquots on each * inode can be modified. And if the directories are world writeable, all the * dquots can be unique and so 6 dquots can be modified.... * * And, of course, we also need to take into account the dquot log format item * used to describe each dquot. */ #define XFS_DQUOT_LOGRES(mp) \ ((sizeof(struct xfs_dq_logformat) + sizeof(struct xfs_disk_dquot)) * 6) #define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) #define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) #define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT) #define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) #define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) #define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) #define XFS_IS_PQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_PQUOTA_ENFD) /* * Incore only flags for quotaoff - these bits get cleared when quota(s) * are in the process of getting turned off. These flags are in m_qflags but * never in sb_qflags. */ #define XFS_UQUOTA_ACTIVE 0x1000 /* uquotas are being turned off */ #define XFS_GQUOTA_ACTIVE 0x2000 /* gquotas are being turned off */ #define XFS_PQUOTA_ACTIVE 0x4000 /* pquotas are being turned off */ #define XFS_ALL_QUOTA_ACTIVE \ (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE) /* * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees * quota will be not be switched off as long as that inode lock is held. */ #define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ XFS_GQUOTA_ACTIVE | \ XFS_PQUOTA_ACTIVE)) #define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) #define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) #define XFS_IS_PQUOTA_ON(mp) ((mp)->m_qflags & XFS_PQUOTA_ACTIVE) /* * Flags to tell various functions what to do. Not all of these are meaningful * to a single function. None of these XFS_QMOPT_* flags are meant to have * persistent values (ie. their values can and will change between versions) */ #define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ #define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */ #define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ #define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ #define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */ #define XFS_QMOPT_ENOSPC 0x0004000 /* enospc instead of edquot (prj) */ /* * flags to xfs_trans_mod_dquot to indicate which field needs to be * modified. */ #define XFS_QMOPT_RES_REGBLKS 0x0010000 #define XFS_QMOPT_RES_RTBLKS 0x0020000 #define XFS_QMOPT_BCOUNT 0x0040000 #define XFS_QMOPT_ICOUNT 0x0080000 #define XFS_QMOPT_RTBCOUNT 0x0100000 #define XFS_QMOPT_DELBCOUNT 0x0200000 #define XFS_QMOPT_DELRTBCOUNT 0x0400000 #define XFS_QMOPT_RES_INOS 0x0800000 /* * flags for dqalloc. */ #define XFS_QMOPT_INHERIT 0x1000000 /* * flags to xfs_trans_mod_dquot. */ #define XFS_TRANS_DQ_RES_BLKS XFS_QMOPT_RES_REGBLKS #define XFS_TRANS_DQ_RES_RTBLKS XFS_QMOPT_RES_RTBLKS #define XFS_TRANS_DQ_RES_INOS XFS_QMOPT_RES_INOS #define XFS_TRANS_DQ_BCOUNT XFS_QMOPT_BCOUNT #define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT #define XFS_TRANS_DQ_ICOUNT XFS_QMOPT_ICOUNT #define XFS_TRANS_DQ_RTBCOUNT XFS_QMOPT_RTBCOUNT #define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT #define XFS_QMOPT_QUOTALL \ (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) extern xfs_failaddr_t xfs_dquot_verify(struct xfs_mount *mp, struct xfs_disk_dquot *ddq, xfs_dqid_t id, uint type); extern xfs_failaddr_t xfs_dqblk_verify(struct xfs_mount *mp, struct xfs_dqblk *dqb, xfs_dqid_t id, uint type); extern int xfs_calc_dquots_per_chunk(unsigned int nbblks); extern void xfs_dqblk_repair(struct xfs_mount *mp, struct xfs_dqblk *dqb, xfs_dqid_t id, uint type); #endif /* __XFS_QUOTA_H__ */ xfsprogs-5.3.0/libxfs/xfs_refcount.c0000644000175000017500000013473213570057155017426 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_btree.h" #include "xfs_bmap.h" #include "xfs_refcount_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_bit.h" #include "xfs_refcount.h" #include "xfs_rmap.h" /* Allowable refcount adjustment amounts. */ enum xfs_refc_adjust_op { XFS_REFCOUNT_ADJUST_INCREASE = 1, XFS_REFCOUNT_ADJUST_DECREASE = -1, XFS_REFCOUNT_ADJUST_COW_ALLOC = 0, XFS_REFCOUNT_ADJUST_COW_FREE = -1, }; STATIC int __xfs_refcount_cow_alloc(struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t aglen); STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t aglen); /* * Look up the first record less than or equal to [bno, len] in the btree * given by cur. */ int xfs_refcount_lookup_le( struct xfs_btree_cur *cur, xfs_agblock_t bno, int *stat) { trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, XFS_LOOKUP_LE); cur->bc_rec.rc.rc_startblock = bno; cur->bc_rec.rc.rc_blockcount = 0; return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); } /* * Look up the first record greater than or equal to [bno, len] in the btree * given by cur. */ int xfs_refcount_lookup_ge( struct xfs_btree_cur *cur, xfs_agblock_t bno, int *stat) { trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, XFS_LOOKUP_GE); cur->bc_rec.rc.rc_startblock = bno; cur->bc_rec.rc.rc_blockcount = 0; return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); } /* * Look up the first record equal to [bno, len] in the btree * given by cur. */ int xfs_refcount_lookup_eq( struct xfs_btree_cur *cur, xfs_agblock_t bno, int *stat) { trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, XFS_LOOKUP_LE); cur->bc_rec.rc.rc_startblock = bno; cur->bc_rec.rc.rc_blockcount = 0; return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); } /* Convert on-disk record to in-core format. */ void xfs_refcount_btrec_to_irec( union xfs_btree_rec *rec, struct xfs_refcount_irec *irec) { irec->rc_startblock = be32_to_cpu(rec->refc.rc_startblock); irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount); irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount); } /* * Get the data from the pointed-to record. */ int xfs_refcount_get_rec( struct xfs_btree_cur *cur, struct xfs_refcount_irec *irec, int *stat) { struct xfs_mount *mp = cur->bc_mp; xfs_agnumber_t agno = cur->bc_private.a.agno; union xfs_btree_rec *rec; int error; xfs_agblock_t realstart; error = xfs_btree_get_rec(cur, &rec, stat); if (error || !*stat) return error; xfs_refcount_btrec_to_irec(rec, irec); agno = cur->bc_private.a.agno; if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN) goto out_bad_rec; /* handle special COW-staging state */ realstart = irec->rc_startblock; if (realstart & XFS_REFC_COW_START) { if (irec->rc_refcount != 1) goto out_bad_rec; realstart &= ~XFS_REFC_COW_START; } else if (irec->rc_refcount < 2) { goto out_bad_rec; } /* check for valid extent range, including overflow */ if (!xfs_verify_agbno(mp, agno, realstart)) goto out_bad_rec; if (realstart > realstart + irec->rc_blockcount) goto out_bad_rec; if (!xfs_verify_agbno(mp, agno, realstart + irec->rc_blockcount - 1)) goto out_bad_rec; if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT) goto out_bad_rec; trace_xfs_refcount_get(cur->bc_mp, cur->bc_private.a.agno, irec); return 0; out_bad_rec: xfs_warn(mp, "Refcount BTree record corruption in AG %d detected!", agno); xfs_warn(mp, "Start block 0x%x, block count 0x%x, references 0x%x", irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount); return -EFSCORRUPTED; } /* * Update the record referred to by cur to the value given * by [bno, len, refcount]. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int xfs_refcount_update( struct xfs_btree_cur *cur, struct xfs_refcount_irec *irec) { union xfs_btree_rec rec; int error; trace_xfs_refcount_update(cur->bc_mp, cur->bc_private.a.agno, irec); rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock); rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); error = xfs_btree_update(cur, &rec); if (error) trace_xfs_refcount_update_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Insert the record referred to by cur to the value given * by [bno, len, refcount]. * This either works (return 0) or gets an EFSCORRUPTED error. */ int xfs_refcount_insert( struct xfs_btree_cur *cur, struct xfs_refcount_irec *irec, int *i) { int error; trace_xfs_refcount_insert(cur->bc_mp, cur->bc_private.a.agno, irec); cur->bc_rec.rc.rc_startblock = irec->rc_startblock; cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; cur->bc_rec.rc.rc_refcount = irec->rc_refcount; error = xfs_btree_insert(cur, i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); out_error: if (error) trace_xfs_refcount_insert_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Remove the record referred to by cur, then set the pointer to the spot * where the record could be re-inserted, in case we want to increment or * decrement the cursor. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int xfs_refcount_delete( struct xfs_btree_cur *cur, int *i) { struct xfs_refcount_irec irec; int found_rec; int error; error = xfs_refcount_get_rec(cur, &irec, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); trace_xfs_refcount_delete(cur->bc_mp, cur->bc_private.a.agno, &irec); error = xfs_btree_delete(cur, i); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); if (error) goto out_error; error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec); out_error: if (error) trace_xfs_refcount_delete_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Adjusting the Reference Count * * As stated elsewhere, the reference count btree (refcbt) stores * >1 reference counts for extents of physical blocks. In this * operation, we're either raising or lowering the reference count of * some subrange stored in the tree: * * <------ adjustment range ------> * ----+ +---+-----+ +--+--------+--------- * 2 | | 3 | 4 | |17| 55 | 10 * ----+ +---+-----+ +--+--------+--------- * X axis is physical blocks number; * reference counts are the numbers inside the rectangles * * The first thing we need to do is to ensure that there are no * refcount extents crossing either boundary of the range to be * adjusted. For any extent that does cross a boundary, split it into * two extents so that we can increment the refcount of one of the * pieces later: * * <------ adjustment range ------> * ----+ +---+-----+ +--+--------+----+---- * 2 | | 3 | 2 | |17| 55 | 10 | 10 * ----+ +---+-----+ +--+--------+----+---- * * For this next step, let's assume that all the physical blocks in * the adjustment range are mapped to a file and are therefore in use * at least once. Therefore, we can infer that any gap in the * refcount tree within the adjustment range represents a physical * extent with refcount == 1: * * <------ adjustment range ------> * ----+---+---+-----+-+--+--------+----+---- * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 * ----+---+---+-----+-+--+--------+----+---- * ^ * * For each extent that falls within the interval range, figure out * which extent is to the left or the right of that extent. Now we * have a left, current, and right extent. If the new reference count * of the center extent enables us to merge left, center, and right * into one record covering all three, do so. If the center extent is * at the left end of the range, abuts the left extent, and its new * reference count matches the left extent's record, then merge them. * If the center extent is at the right end of the range, abuts the * right extent, and the reference counts match, merge those. In the * example, we can left merge (assuming an increment operation): * * <------ adjustment range ------> * --------+---+-----+-+--+--------+----+---- * 2 | 3 | 2 |1|17| 55 | 10 | 10 * --------+---+-----+-+--+--------+----+---- * ^ * * For all other extents within the range, adjust the reference count * or delete it if the refcount falls below 2. If we were * incrementing, the end result looks like this: * * <------ adjustment range ------> * --------+---+-----+-+--+--------+----+---- * 2 | 4 | 3 |2|18| 56 | 11 | 10 * --------+---+-----+-+--+--------+----+---- * * The result of a decrement operation looks as such: * * <------ adjustment range ------> * ----+ +---+ +--+--------+----+---- * 2 | | 2 | |16| 54 | 9 | 10 * ----+ +---+ +--+--------+----+---- * DDDD 111111DD * * The blocks marked "D" are freed; the blocks marked "1" are only * referenced once and therefore the record is removed from the * refcount btree. */ /* Next block after this extent. */ static inline xfs_agblock_t xfs_refc_next( struct xfs_refcount_irec *rc) { return rc->rc_startblock + rc->rc_blockcount; } /* * Split a refcount extent that crosses agbno. */ STATIC int xfs_refcount_split_extent( struct xfs_btree_cur *cur, xfs_agblock_t agbno, bool *shape_changed) { struct xfs_refcount_irec rcext, tmp; int found_rec; int error; *shape_changed = false; error = xfs_refcount_lookup_le(cur, agbno, &found_rec); if (error) goto out_error; if (!found_rec) return 0; error = xfs_refcount_get_rec(cur, &rcext, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) return 0; *shape_changed = true; trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_private.a.agno, &rcext, agbno); /* Establish the right extent. */ tmp = rcext; tmp.rc_startblock = agbno; tmp.rc_blockcount -= (agbno - rcext.rc_startblock); error = xfs_refcount_update(cur, &tmp); if (error) goto out_error; /* Insert the left extent. */ tmp = rcext; tmp.rc_blockcount = agbno - rcext.rc_startblock; error = xfs_refcount_insert(cur, &tmp, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); return error; out_error: trace_xfs_refcount_split_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Merge the left, center, and right extents. */ STATIC int xfs_refcount_merge_center_extents( struct xfs_btree_cur *cur, struct xfs_refcount_irec *left, struct xfs_refcount_irec *center, struct xfs_refcount_irec *right, unsigned long long extlen, xfs_extlen_t *aglen) { int error; int found_rec; trace_xfs_refcount_merge_center_extents(cur->bc_mp, cur->bc_private.a.agno, left, center, right); /* * Make sure the center and right extents are not in the btree. * If the center extent was synthesized, the first delete call * removes the right extent and we skip the second deletion. * If center and right were in the btree, then the first delete * call removes the center and the second one removes the right * extent. */ error = xfs_refcount_lookup_ge(cur, center->rc_startblock, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); error = xfs_refcount_delete(cur, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); if (center->rc_refcount > 1) { error = xfs_refcount_delete(cur, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); } /* Enlarge the left extent. */ error = xfs_refcount_lookup_le(cur, left->rc_startblock, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); left->rc_blockcount = extlen; error = xfs_refcount_update(cur, left); if (error) goto out_error; *aglen = 0; return error; out_error: trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Merge with the left extent. */ STATIC int xfs_refcount_merge_left_extent( struct xfs_btree_cur *cur, struct xfs_refcount_irec *left, struct xfs_refcount_irec *cleft, xfs_agblock_t *agbno, xfs_extlen_t *aglen) { int error; int found_rec; trace_xfs_refcount_merge_left_extent(cur->bc_mp, cur->bc_private.a.agno, left, cleft); /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ if (cleft->rc_refcount > 1) { error = xfs_refcount_lookup_le(cur, cleft->rc_startblock, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); error = xfs_refcount_delete(cur, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); } /* Enlarge the left extent. */ error = xfs_refcount_lookup_le(cur, left->rc_startblock, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); left->rc_blockcount += cleft->rc_blockcount; error = xfs_refcount_update(cur, left); if (error) goto out_error; *agbno += cleft->rc_blockcount; *aglen -= cleft->rc_blockcount; return error; out_error: trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Merge with the right extent. */ STATIC int xfs_refcount_merge_right_extent( struct xfs_btree_cur *cur, struct xfs_refcount_irec *right, struct xfs_refcount_irec *cright, xfs_extlen_t *aglen) { int error; int found_rec; trace_xfs_refcount_merge_right_extent(cur->bc_mp, cur->bc_private.a.agno, cright, right); /* * If the extent ending at agbno+aglen (cright) wasn't synthesized, * remove it. */ if (cright->rc_refcount > 1) { error = xfs_refcount_lookup_le(cur, cright->rc_startblock, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); error = xfs_refcount_delete(cur, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); } /* Enlarge the right extent. */ error = xfs_refcount_lookup_le(cur, right->rc_startblock, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); right->rc_startblock -= cright->rc_blockcount; right->rc_blockcount += cright->rc_blockcount; error = xfs_refcount_update(cur, right); if (error) goto out_error; *aglen -= cright->rc_blockcount; return error; out_error: trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } #define XFS_FIND_RCEXT_SHARED 1 #define XFS_FIND_RCEXT_COW 2 /* * Find the left extent and the one after it (cleft). This function assumes * that we've already split any extent crossing agbno. */ STATIC int xfs_refcount_find_left_extents( struct xfs_btree_cur *cur, struct xfs_refcount_irec *left, struct xfs_refcount_irec *cleft, xfs_agblock_t agbno, xfs_extlen_t aglen, int flags) { struct xfs_refcount_irec tmp; int error; int found_rec; left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec); if (error) goto out_error; if (!found_rec) return 0; error = xfs_refcount_get_rec(cur, &tmp, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); if (xfs_refc_next(&tmp) != agbno) return 0; if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) return 0; if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) return 0; /* We have a left extent; retrieve (or invent) the next right one */ *left = tmp; error = xfs_btree_increment(cur, 0, &found_rec); if (error) goto out_error; if (found_rec) { error = xfs_refcount_get_rec(cur, &tmp, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); /* if tmp starts at the end of our range, just use that */ if (tmp.rc_startblock == agbno) *cleft = tmp; else { /* * There's a gap in the refcntbt at the start of the * range we're interested in (refcount == 1) so * synthesize the implied extent and pass it back. * We assume here that the agbno/aglen range was * passed in from a data fork extent mapping and * therefore is allocated to exactly one owner. */ cleft->rc_startblock = agbno; cleft->rc_blockcount = min(aglen, tmp.rc_startblock - agbno); cleft->rc_refcount = 1; } } else { /* * No extents, so pretend that there's one covering the whole * range. */ cleft->rc_startblock = agbno; cleft->rc_blockcount = aglen; cleft->rc_refcount = 1; } trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno, left, cleft, agbno); return error; out_error: trace_xfs_refcount_find_left_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Find the right extent and the one before it (cright). This function * assumes that we've already split any extents crossing agbno + aglen. */ STATIC int xfs_refcount_find_right_extents( struct xfs_btree_cur *cur, struct xfs_refcount_irec *right, struct xfs_refcount_irec *cright, xfs_agblock_t agbno, xfs_extlen_t aglen, int flags) { struct xfs_refcount_irec tmp; int error; int found_rec; right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec); if (error) goto out_error; if (!found_rec) return 0; error = xfs_refcount_get_rec(cur, &tmp, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); if (tmp.rc_startblock != agbno + aglen) return 0; if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) return 0; if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) return 0; /* We have a right extent; retrieve (or invent) the next left one */ *right = tmp; error = xfs_btree_decrement(cur, 0, &found_rec); if (error) goto out_error; if (found_rec) { error = xfs_refcount_get_rec(cur, &tmp, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); /* if tmp ends at the end of our range, just use that */ if (xfs_refc_next(&tmp) == agbno + aglen) *cright = tmp; else { /* * There's a gap in the refcntbt at the end of the * range we're interested in (refcount == 1) so * create the implied extent and pass it back. * We assume here that the agbno/aglen range was * passed in from a data fork extent mapping and * therefore is allocated to exactly one owner. */ cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); cright->rc_blockcount = right->rc_startblock - cright->rc_startblock; cright->rc_refcount = 1; } } else { /* * No extents, so pretend that there's one covering the whole * range. */ cright->rc_startblock = agbno; cright->rc_blockcount = aglen; cright->rc_refcount = 1; } trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno, cright, right, agbno + aglen); return error; out_error: trace_xfs_refcount_find_right_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* Is this extent valid? */ static inline bool xfs_refc_valid( struct xfs_refcount_irec *rc) { return rc->rc_startblock != NULLAGBLOCK; } /* * Try to merge with any extents on the boundaries of the adjustment range. */ STATIC int xfs_refcount_merge_extents( struct xfs_btree_cur *cur, xfs_agblock_t *agbno, xfs_extlen_t *aglen, enum xfs_refc_adjust_op adjust, int flags, bool *shape_changed) { struct xfs_refcount_irec left = {0}, cleft = {0}; struct xfs_refcount_irec cright = {0}, right = {0}; int error; unsigned long long ulen; bool cequal; *shape_changed = false; /* * Find the extent just below agbno [left], just above agbno [cleft], * just below (agbno + aglen) [cright], and just above (agbno + aglen) * [right]. */ error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno, *aglen, flags); if (error) return error; error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno, *aglen, flags); if (error) return error; /* No left or right extent to merge; exit. */ if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) return 0; cequal = (cleft.rc_startblock == cright.rc_startblock) && (cleft.rc_blockcount == cright.rc_blockcount); /* Try to merge left, cleft, and right. cleft must == cright. */ ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + right.rc_blockcount; if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && left.rc_refcount == cleft.rc_refcount + adjust && right.rc_refcount == cleft.rc_refcount + adjust && ulen < MAXREFCEXTLEN) { *shape_changed = true; return xfs_refcount_merge_center_extents(cur, &left, &cleft, &right, ulen, aglen); } /* Try to merge left and cleft. */ ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && left.rc_refcount == cleft.rc_refcount + adjust && ulen < MAXREFCEXTLEN) { *shape_changed = true; error = xfs_refcount_merge_left_extent(cur, &left, &cleft, agbno, aglen); if (error) return error; /* * If we just merged left + cleft and cleft == cright, * we no longer have a cright to merge with right. We're done. */ if (cequal) return 0; } /* Try to merge cright and right. */ ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && right.rc_refcount == cright.rc_refcount + adjust && ulen < MAXREFCEXTLEN) { *shape_changed = true; return xfs_refcount_merge_right_extent(cur, &right, &cright, aglen); } return error; } /* * XXX: This is a pretty hand-wavy estimate. The penalty for guessing * true incorrectly is a shutdown FS; the penalty for guessing false * incorrectly is more transaction rolls than might be necessary. * Be conservative here. */ static bool xfs_refcount_still_have_space( struct xfs_btree_cur *cur) { unsigned long overhead; overhead = cur->bc_private.a.priv.refc.shape_changes * xfs_allocfree_log_count(cur->bc_mp, 1); overhead *= cur->bc_mp->m_sb.sb_blocksize; /* * Only allow 2 refcount extent updates per transaction if the * refcount continue update "error" has been injected. */ if (cur->bc_private.a.priv.refc.nr_ops > 2 && XFS_TEST_ERROR(false, cur->bc_mp, XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE)) return false; if (cur->bc_private.a.priv.refc.nr_ops == 0) return true; else if (overhead > cur->bc_tp->t_log_res) return false; return cur->bc_tp->t_log_res - overhead > cur->bc_private.a.priv.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD; } /* * Adjust the refcounts of middle extents. At this point we should have * split extents that crossed the adjustment range; merged with adjacent * extents; and updated agbno/aglen to reflect the merges. Therefore, * all we have to do is update the extents inside [agbno, agbno + aglen]. */ STATIC int xfs_refcount_adjust_extents( struct xfs_btree_cur *cur, xfs_agblock_t *agbno, xfs_extlen_t *aglen, enum xfs_refc_adjust_op adj, struct xfs_owner_info *oinfo) { struct xfs_refcount_irec ext, tmp; int error; int found_rec, found_tmp; xfs_fsblock_t fsbno; /* Merging did all the work already. */ if (*aglen == 0) return 0; error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); if (error) goto out_error; while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { error = xfs_refcount_get_rec(cur, &ext, &found_rec); if (error) goto out_error; if (!found_rec) { ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; ext.rc_blockcount = 0; ext.rc_refcount = 0; } /* * Deal with a hole in the refcount tree; if a file maps to * these blocks and there's no refcountbt record, pretend that * there is one with refcount == 1. */ if (ext.rc_startblock != *agbno) { tmp.rc_startblock = *agbno; tmp.rc_blockcount = min(*aglen, ext.rc_startblock - *agbno); tmp.rc_refcount = 1 + adj; trace_xfs_refcount_modify_extent(cur->bc_mp, cur->bc_private.a.agno, &tmp); /* * Either cover the hole (increment) or * delete the range (decrement). */ if (tmp.rc_refcount) { error = xfs_refcount_insert(cur, &tmp, &found_tmp); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_tmp == 1, out_error); cur->bc_private.a.priv.refc.nr_ops++; } else { fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno, tmp.rc_startblock); xfs_bmap_add_free(cur->bc_tp, fsbno, tmp.rc_blockcount, oinfo); } (*agbno) += tmp.rc_blockcount; (*aglen) -= tmp.rc_blockcount; error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); if (error) goto out_error; } /* Stop if there's nothing left to modify */ if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) break; /* * Adjust the reference count and either update the tree * (incr) or free the blocks (decr). */ if (ext.rc_refcount == MAXREFCOUNT) goto skip; ext.rc_refcount += adj; trace_xfs_refcount_modify_extent(cur->bc_mp, cur->bc_private.a.agno, &ext); if (ext.rc_refcount > 1) { error = xfs_refcount_update(cur, &ext); if (error) goto out_error; cur->bc_private.a.priv.refc.nr_ops++; } else if (ext.rc_refcount == 1) { error = xfs_refcount_delete(cur, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); cur->bc_private.a.priv.refc.nr_ops++; goto advloop; } else { fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno, ext.rc_startblock); xfs_bmap_add_free(cur->bc_tp, fsbno, ext.rc_blockcount, oinfo); } skip: error = xfs_btree_increment(cur, 0, &found_rec); if (error) goto out_error; advloop: (*agbno) += ext.rc_blockcount; (*aglen) -= ext.rc_blockcount; } return error; out_error: trace_xfs_refcount_modify_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* Adjust the reference count of a range of AG blocks. */ STATIC int xfs_refcount_adjust( struct xfs_btree_cur *cur, xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *new_agbno, xfs_extlen_t *new_aglen, enum xfs_refc_adjust_op adj, struct xfs_owner_info *oinfo) { bool shape_changed; int shape_changes = 0; int error; *new_agbno = agbno; *new_aglen = aglen; if (adj == XFS_REFCOUNT_ADJUST_INCREASE) trace_xfs_refcount_increase(cur->bc_mp, cur->bc_private.a.agno, agbno, aglen); else trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_private.a.agno, agbno, aglen); /* * Ensure that no rcextents cross the boundary of the adjustment range. */ error = xfs_refcount_split_extent(cur, agbno, &shape_changed); if (error) goto out_error; if (shape_changed) shape_changes++; error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); if (error) goto out_error; if (shape_changed) shape_changes++; /* * Try to merge with the left or right extents of the range. */ error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj, XFS_FIND_RCEXT_SHARED, &shape_changed); if (error) goto out_error; if (shape_changed) shape_changes++; if (shape_changes) cur->bc_private.a.priv.refc.shape_changes++; /* Now that we've taken care of the ends, adjust the middle extents */ error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, adj, oinfo); if (error) goto out_error; return 0; out_error: trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* Clean up after calling xfs_refcount_finish_one. */ void xfs_refcount_finish_one_cleanup( struct xfs_trans *tp, struct xfs_btree_cur *rcur, int error) { struct xfs_buf *agbp; if (rcur == NULL) return; agbp = rcur->bc_private.a.agbp; xfs_btree_del_cursor(rcur, error); if (error) xfs_trans_brelse(tp, agbp); } /* * Process one of the deferred refcount operations. We pass back the * btree cursor to maintain our lock on the btree between calls. * This saves time and eliminates a buffer deadlock between the * superblock and the AGF because we'll always grab them in the same * order. */ int xfs_refcount_finish_one( struct xfs_trans *tp, enum xfs_refcount_intent_type type, xfs_fsblock_t startblock, xfs_extlen_t blockcount, xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len, struct xfs_btree_cur **pcur) { struct xfs_mount *mp = tp->t_mountp; struct xfs_btree_cur *rcur; struct xfs_buf *agbp = NULL; int error = 0; xfs_agnumber_t agno; xfs_agblock_t bno; xfs_agblock_t new_agbno; unsigned long nr_ops = 0; int shape_changes = 0; agno = XFS_FSB_TO_AGNO(mp, startblock); ASSERT(agno != NULLAGNUMBER); bno = XFS_FSB_TO_AGBNO(mp, startblock); trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock), type, XFS_FSB_TO_AGBNO(mp, startblock), blockcount); if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REFCOUNT_FINISH_ONE)) return -EIO; /* * If we haven't gotten a cursor or the cursor AG doesn't match * the startblock, get one now. */ rcur = *pcur; if (rcur != NULL && rcur->bc_private.a.agno != agno) { nr_ops = rcur->bc_private.a.priv.refc.nr_ops; shape_changes = rcur->bc_private.a.priv.refc.shape_changes; xfs_refcount_finish_one_cleanup(tp, rcur, 0); rcur = NULL; *pcur = NULL; } if (rcur == NULL) { error = xfs_alloc_read_agf(tp->t_mountp, tp, agno, XFS_ALLOC_FLAG_FREEING, &agbp); if (error) return error; if (!agbp) return -EFSCORRUPTED; rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); if (!rcur) { error = -ENOMEM; goto out_cur; } rcur->bc_private.a.priv.refc.nr_ops = nr_ops; rcur->bc_private.a.priv.refc.shape_changes = shape_changes; } *pcur = rcur; switch (type) { case XFS_REFCOUNT_INCREASE: error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, new_len, XFS_REFCOUNT_ADJUST_INCREASE, NULL); *new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); break; case XFS_REFCOUNT_DECREASE: error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, new_len, XFS_REFCOUNT_ADJUST_DECREASE, NULL); *new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); break; case XFS_REFCOUNT_ALLOC_COW: *new_fsb = startblock + blockcount; *new_len = 0; error = __xfs_refcount_cow_alloc(rcur, bno, blockcount); break; case XFS_REFCOUNT_FREE_COW: *new_fsb = startblock + blockcount; *new_len = 0; error = __xfs_refcount_cow_free(rcur, bno, blockcount); break; default: ASSERT(0); error = -EFSCORRUPTED; } if (!error && *new_len > 0) trace_xfs_refcount_finish_one_leftover(mp, agno, type, bno, blockcount, new_agbno, *new_len); return error; out_cur: xfs_trans_brelse(tp, agbp); return error; } /* * Record a refcount intent for later processing. */ static int __xfs_refcount_add( struct xfs_trans *tp, enum xfs_refcount_intent_type type, xfs_fsblock_t startblock, xfs_extlen_t blockcount) { struct xfs_refcount_intent *ri; trace_xfs_refcount_defer(tp->t_mountp, XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type, XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), blockcount); ri = kmem_alloc(sizeof(struct xfs_refcount_intent), KM_SLEEP | KM_NOFS); INIT_LIST_HEAD(&ri->ri_list); ri->ri_type = type; ri->ri_startblock = startblock; ri->ri_blockcount = blockcount; xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_REFCOUNT, &ri->ri_list); return 0; } /* * Increase the reference count of the blocks backing a file's extent. */ int xfs_refcount_increase_extent( struct xfs_trans *tp, struct xfs_bmbt_irec *PREV) { if (!xfs_sb_version_hasreflink(&tp->t_mountp->m_sb)) return 0; return __xfs_refcount_add(tp, XFS_REFCOUNT_INCREASE, PREV->br_startblock, PREV->br_blockcount); } /* * Decrease the reference count of the blocks backing a file's extent. */ int xfs_refcount_decrease_extent( struct xfs_trans *tp, struct xfs_bmbt_irec *PREV) { if (!xfs_sb_version_hasreflink(&tp->t_mountp->m_sb)) return 0; return __xfs_refcount_add(tp, XFS_REFCOUNT_DECREASE, PREV->br_startblock, PREV->br_blockcount); } /* * Given an AG extent, find the lowest-numbered run of shared blocks * within that range and return the range in fbno/flen. If * find_end_of_shared is set, return the longest contiguous extent of * shared blocks; if not, just return the first extent we find. If no * shared blocks are found, fbno and flen will be set to NULLAGBLOCK * and 0, respectively. */ int xfs_refcount_find_shared( struct xfs_btree_cur *cur, xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno, xfs_extlen_t *flen, bool find_end_of_shared) { struct xfs_refcount_irec tmp; int i; int have; int error; trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_private.a.agno, agbno, aglen); /* By default, skip the whole range */ *fbno = NULLAGBLOCK; *flen = 0; /* Try to find a refcount extent that crosses the start */ error = xfs_refcount_lookup_le(cur, agbno, &have); if (error) goto out_error; if (!have) { /* No left extent, look at the next one */ error = xfs_btree_increment(cur, 0, &have); if (error) goto out_error; if (!have) goto done; } error = xfs_refcount_get_rec(cur, &tmp, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); /* If the extent ends before the start, look at the next one */ if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) { error = xfs_btree_increment(cur, 0, &have); if (error) goto out_error; if (!have) goto done; error = xfs_refcount_get_rec(cur, &tmp, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); } /* If the extent starts after the range we want, bail out */ if (tmp.rc_startblock >= agbno + aglen) goto done; /* We found the start of a shared extent! */ if (tmp.rc_startblock < agbno) { tmp.rc_blockcount -= (agbno - tmp.rc_startblock); tmp.rc_startblock = agbno; } *fbno = tmp.rc_startblock; *flen = min(tmp.rc_blockcount, agbno + aglen - *fbno); if (!find_end_of_shared) goto done; /* Otherwise, find the end of this shared extent */ while (*fbno + *flen < agbno + aglen) { error = xfs_btree_increment(cur, 0, &have); if (error) goto out_error; if (!have) break; error = xfs_refcount_get_rec(cur, &tmp, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); if (tmp.rc_startblock >= agbno + aglen || tmp.rc_startblock != *fbno + *flen) break; *flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno); } done: trace_xfs_refcount_find_shared_result(cur->bc_mp, cur->bc_private.a.agno, *fbno, *flen); out_error: if (error) trace_xfs_refcount_find_shared_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Recovering CoW Blocks After a Crash * * Due to the way that the copy on write mechanism works, there's a window of * opportunity in which we can lose track of allocated blocks during a crash. * Because CoW uses delayed allocation in the in-core CoW fork, writeback * causes blocks to be allocated and stored in the CoW fork. The blocks are * no longer in the free space btree but are not otherwise recorded anywhere * until the write completes and the blocks are mapped into the file. A crash * in between allocation and remapping results in the replacement blocks being * lost. This situation is exacerbated by the CoW extent size hint because * allocations can hang around for long time. * * However, there is a place where we can record these allocations before they * become mappings -- the reference count btree. The btree does not record * extents with refcount == 1, so we can record allocations with a refcount of * 1. Blocks being used for CoW writeout cannot be shared, so there should be * no conflict with shared block records. These mappings should be created * when we allocate blocks to the CoW fork and deleted when they're removed * from the CoW fork. * * Minor nit: records for in-progress CoW allocations and records for shared * extents must never be merged, to preserve the property that (except for CoW * allocations) there are no refcount btree entries with refcount == 1. The * only time this could potentially happen is when unsharing a block that's * adjacent to CoW allocations, so we must be careful to avoid this. * * At mount time we recover lost CoW allocations by searching the refcount * btree for these refcount == 1 mappings. These represent CoW allocations * that were in progress at the time the filesystem went down, so we can free * them to get the space back. * * This mechanism is superior to creating EFIs for unmapped CoW extents for * several reasons -- first, EFIs pin the tail of the log and would have to be * periodically relogged to avoid filling up the log. Second, CoW completions * will have to file an EFD and create new EFIs for whatever remains in the * CoW fork; this partially takes care of (1) but extent-size reservations * will have to periodically relog even if there's no writeout in progress. * This can happen if the CoW extent size hint is set, which you really want. * Third, EFIs cannot currently be automatically relogged into newer * transactions to advance the log tail. Fourth, stuffing the log full of * EFIs places an upper bound on the number of CoW allocations that can be * held filesystem-wide at any given time. Recording them in the refcount * btree doesn't require us to maintain any state in memory and doesn't pin * the log. */ /* * Adjust the refcounts of CoW allocations. These allocations are "magic" * in that they're not referenced anywhere else in the filesystem, so we * stash them in the refcount btree with a refcount of 1 until either file * remapping (or CoW cancellation) happens. */ STATIC int xfs_refcount_adjust_cow_extents( struct xfs_btree_cur *cur, xfs_agblock_t agbno, xfs_extlen_t aglen, enum xfs_refc_adjust_op adj) { struct xfs_refcount_irec ext, tmp; int error; int found_rec, found_tmp; if (aglen == 0) return 0; /* Find any overlapping refcount records */ error = xfs_refcount_lookup_ge(cur, agbno, &found_rec); if (error) goto out_error; error = xfs_refcount_get_rec(cur, &ext, &found_rec); if (error) goto out_error; if (!found_rec) { ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks + XFS_REFC_COW_START; ext.rc_blockcount = 0; ext.rc_refcount = 0; } switch (adj) { case XFS_REFCOUNT_ADJUST_COW_ALLOC: /* Adding a CoW reservation, there should be nothing here. */ XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, ext.rc_startblock >= agbno + aglen, out_error); tmp.rc_startblock = agbno; tmp.rc_blockcount = aglen; tmp.rc_refcount = 1; trace_xfs_refcount_modify_extent(cur->bc_mp, cur->bc_private.a.agno, &tmp); error = xfs_refcount_insert(cur, &tmp, &found_tmp); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_tmp == 1, out_error); break; case XFS_REFCOUNT_ADJUST_COW_FREE: /* Removing a CoW reservation, there should be one extent. */ XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, ext.rc_startblock == agbno, out_error); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, ext.rc_blockcount == aglen, out_error); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, ext.rc_refcount == 1, out_error); ext.rc_refcount = 0; trace_xfs_refcount_modify_extent(cur->bc_mp, cur->bc_private.a.agno, &ext); error = xfs_refcount_delete(cur, &found_rec); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); break; default: ASSERT(0); } return error; out_error: trace_xfs_refcount_modify_extent_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Add or remove refcount btree entries for CoW reservations. */ STATIC int xfs_refcount_adjust_cow( struct xfs_btree_cur *cur, xfs_agblock_t agbno, xfs_extlen_t aglen, enum xfs_refc_adjust_op adj) { bool shape_changed; int error; agbno += XFS_REFC_COW_START; /* * Ensure that no rcextents cross the boundary of the adjustment range. */ error = xfs_refcount_split_extent(cur, agbno, &shape_changed); if (error) goto out_error; error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); if (error) goto out_error; /* * Try to merge with the left or right extents of the range. */ error = xfs_refcount_merge_extents(cur, &agbno, &aglen, adj, XFS_FIND_RCEXT_COW, &shape_changed); if (error) goto out_error; /* Now that we've taken care of the ends, adjust the middle extents */ error = xfs_refcount_adjust_cow_extents(cur, agbno, aglen, adj); if (error) goto out_error; return 0; out_error: trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Record a CoW allocation in the refcount btree. */ STATIC int __xfs_refcount_cow_alloc( struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t aglen) { trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno, agbno, aglen); /* Add refcount btree reservation */ return xfs_refcount_adjust_cow(rcur, agbno, aglen, XFS_REFCOUNT_ADJUST_COW_ALLOC); } /* * Remove a CoW allocation from the refcount btree. */ STATIC int __xfs_refcount_cow_free( struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t aglen) { trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno, agbno, aglen); /* Remove refcount btree reservation */ return xfs_refcount_adjust_cow(rcur, agbno, aglen, XFS_REFCOUNT_ADJUST_COW_FREE); } /* Record a CoW staging extent in the refcount btree. */ int xfs_refcount_alloc_cow_extent( struct xfs_trans *tp, xfs_fsblock_t fsb, xfs_extlen_t len) { struct xfs_mount *mp = tp->t_mountp; int error; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return 0; error = __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len); if (error) return error; /* Add rmap entry */ return xfs_rmap_alloc_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); } /* Forget a CoW staging event in the refcount btree. */ int xfs_refcount_free_cow_extent( struct xfs_trans *tp, xfs_fsblock_t fsb, xfs_extlen_t len) { struct xfs_mount *mp = tp->t_mountp; int error; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return 0; /* Remove rmap entry */ error = xfs_rmap_free_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); if (error) return error; return __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len); } struct xfs_refcount_recovery { struct list_head rr_list; struct xfs_refcount_irec rr_rrec; }; /* Stuff an extent on the recovery list. */ STATIC int xfs_refcount_recover_extent( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, void *priv) { struct list_head *debris = priv; struct xfs_refcount_recovery *rr; if (be32_to_cpu(rec->refc.rc_refcount) != 1) return -EFSCORRUPTED; rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), KM_SLEEP); xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec); list_add_tail(&rr->rr_list, debris); return 0; } /* Find and remove leftover CoW reservations. */ int xfs_refcount_recover_cow_leftovers( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_trans *tp; struct xfs_btree_cur *cur; struct xfs_buf *agbp; struct xfs_refcount_recovery *rr, *n; struct list_head debris; union xfs_btree_irec low; union xfs_btree_irec high; xfs_fsblock_t fsb; xfs_agblock_t agbno; int error; if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START) return -EOPNOTSUPP; INIT_LIST_HEAD(&debris); /* * In this first part, we use an empty transaction to gather up * all the leftover CoW extents so that we can subsequently * delete them. The empty transaction is used to avoid * a buffer lock deadlock if there happens to be a loop in the * refcountbt because we're allowed to re-grab a buffer that is * already attached to our transaction. When we're done * recording the CoW debris we cancel the (empty) transaction * and everything goes away cleanly. */ error = xfs_trans_alloc_empty(mp, &tp); if (error) return error; error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); if (error) goto out_trans; if (!agbp) { error = -ENOMEM; goto out_trans; } cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); /* Find all the leftover CoW staging extents. */ memset(&low, 0, sizeof(low)); memset(&high, 0, sizeof(high)); low.rc.rc_startblock = XFS_REFC_COW_START; high.rc.rc_startblock = -1U; error = xfs_btree_query_range(cur, &low, &high, xfs_refcount_recover_extent, &debris); xfs_btree_del_cursor(cur, error); xfs_trans_brelse(tp, agbp); xfs_trans_cancel(tp); if (error) goto out_free; /* Now iterate the list to free the leftovers */ list_for_each_entry_safe(rr, n, &debris, rr_list) { /* Set up transaction. */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); if (error) goto out_free; trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec); /* Free the orphan record */ agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START; fsb = XFS_AGB_TO_FSB(mp, agno, agbno); error = xfs_refcount_free_cow_extent(tp, fsb, rr->rr_rrec.rc_blockcount); if (error) goto out_trans; /* Free the block. */ xfs_bmap_add_free(tp, fsb, rr->rr_rrec.rc_blockcount, NULL); error = xfs_trans_commit(tp); if (error) goto out_free; list_del(&rr->rr_list); kmem_free(rr); } return error; out_trans: xfs_trans_cancel(tp); out_free: /* Free the leftover list */ list_for_each_entry_safe(rr, n, &debris, rr_list) { list_del(&rr->rr_list); kmem_free(rr); } return error; } /* Is there a record covering a given extent? */ int xfs_refcount_has_record( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists) { union xfs_btree_irec low; union xfs_btree_irec high; memset(&low, 0, sizeof(low)); low.rc.rc_startblock = bno; memset(&high, 0xFF, sizeof(high)); high.rc.rc_startblock = bno + len - 1; return xfs_btree_has_record(cur, &low, &high, exists); } xfsprogs-5.3.0/libxfs/xfs_refcount.h0000644000175000017500000000553113435336036017423 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_REFCOUNT_H__ #define __XFS_REFCOUNT_H__ extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno, int *stat); extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur, xfs_agblock_t bno, int *stat); extern int xfs_refcount_lookup_eq(struct xfs_btree_cur *cur, xfs_agblock_t bno, int *stat); extern int xfs_refcount_get_rec(struct xfs_btree_cur *cur, struct xfs_refcount_irec *irec, int *stat); enum xfs_refcount_intent_type { XFS_REFCOUNT_INCREASE = 1, XFS_REFCOUNT_DECREASE, XFS_REFCOUNT_ALLOC_COW, XFS_REFCOUNT_FREE_COW, }; struct xfs_refcount_intent { struct list_head ri_list; enum xfs_refcount_intent_type ri_type; xfs_fsblock_t ri_startblock; xfs_extlen_t ri_blockcount; }; extern int xfs_refcount_increase_extent(struct xfs_trans *tp, struct xfs_bmbt_irec *irec); extern int xfs_refcount_decrease_extent(struct xfs_trans *tp, struct xfs_bmbt_irec *irec); extern void xfs_refcount_finish_one_cleanup(struct xfs_trans *tp, struct xfs_btree_cur *rcur, int error); extern int xfs_refcount_finish_one(struct xfs_trans *tp, enum xfs_refcount_intent_type type, xfs_fsblock_t startblock, xfs_extlen_t blockcount, xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len, struct xfs_btree_cur **pcur); extern int xfs_refcount_find_shared(struct xfs_btree_cur *cur, xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno, xfs_extlen_t *flen, bool find_end_of_shared); extern int xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb, xfs_extlen_t len); extern int xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb, xfs_extlen_t len); extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp, xfs_agnumber_t agno); /* * While we're adjusting the refcounts records of an extent, we have * to keep an eye on the number of extents we're dirtying -- run too * many in a single transaction and we'll exceed the transaction's * reservation and crash the fs. Each record adds 12 bytes to the * log (plus any key updates) so we'll conservatively assume 32 bytes * per record. We must also leave space for btree splits on both ends * of the range and space for the CUD and a new CUI. */ #define XFS_REFCOUNT_ITEM_OVERHEAD 32 static inline xfs_fileoff_t xfs_refcount_max_unmap(int log_res) { return (log_res * 3 / 4) / XFS_REFCOUNT_ITEM_OVERHEAD; } extern int xfs_refcount_has_record(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists); union xfs_btree_rec; extern void xfs_refcount_btrec_to_irec(union xfs_btree_rec *rec, struct xfs_refcount_irec *irec); extern int xfs_refcount_insert(struct xfs_btree_cur *cur, struct xfs_refcount_irec *irec, int *stat); #endif /* __XFS_REFCOUNT_H__ */ xfsprogs-5.3.0/libxfs/xfs_refcount_btree.c0000644000175000017500000002471713570057155020610 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_btree.h" #include "xfs_refcount_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_rmap.h" static struct xfs_btree_cur * xfs_refcountbt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agbp, cur->bc_private.a.agno); } STATIC void xfs_refcountbt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int inc) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); ASSERT(ptr->s != 0); agf->agf_refcount_root = ptr->s; be32_add_cpu(&agf->agf_refcount_level, inc); pag->pagf_refcount_level += inc; xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL); } STATIC int xfs_refcountbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); struct xfs_alloc_arg args; /* block allocation args */ int error; /* error return value */ memset(&args, 0, sizeof(args)); args.tp = cur->bc_tp; args.mp = cur->bc_mp; args.type = XFS_ALLOCTYPE_NEAR_BNO; args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno, xfs_refc_block(args.mp)); args.oinfo = XFS_RMAP_OINFO_REFC; args.minlen = args.maxlen = args.prod = 1; args.resv = XFS_AG_RESV_METADATA; error = xfs_alloc_vextent(&args); if (error) goto out_error; trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno, args.agbno, 1); if (args.fsbno == NULLFSBLOCK) { *stat = 0; return 0; } ASSERT(args.agno == cur->bc_private.a.agno); ASSERT(args.len == 1); new->s = cpu_to_be32(args.agbno); be32_add_cpu(&agf->agf_refcount_blocks, 1); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); *stat = 1; return 0; out_error: return error; } STATIC int xfs_refcountbt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); int error; trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_private.a.agno, XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1); be32_add_cpu(&agf->agf_refcount_blocks, -1); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); error = xfs_free_extent(cur->bc_tp, fsbno, 1, &XFS_RMAP_OINFO_REFC, XFS_AG_RESV_METADATA); if (error) return error; return error; } STATIC int xfs_refcountbt_get_minrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_refc_mnr[level != 0]; } STATIC int xfs_refcountbt_get_maxrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_refc_mxr[level != 0]; } STATIC void xfs_refcountbt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->refc.rc_startblock = rec->refc.rc_startblock; } STATIC void xfs_refcountbt_init_high_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { __u32 x; x = be32_to_cpu(rec->refc.rc_startblock); x += be32_to_cpu(rec->refc.rc_blockcount) - 1; key->refc.rc_startblock = cpu_to_be32(x); } STATIC void xfs_refcountbt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock); rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount); rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount); } STATIC void xfs_refcountbt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); ptr->s = agf->agf_refcount_root; } STATIC int64_t xfs_refcountbt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { struct xfs_refcount_irec *rec = &cur->bc_rec.rc; struct xfs_refcount_key *kp = &key->refc; return (int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock; } STATIC int64_t xfs_refcountbt_diff_two_keys( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return (int64_t)be32_to_cpu(k1->refc.rc_startblock) - be32_to_cpu(k2->refc.rc_startblock); } STATIC xfs_failaddr_t xfs_refcountbt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_perag *pag = bp->b_pag; xfs_failaddr_t fa; unsigned int level; if (!xfs_verify_magic(bp, block->bb_magic)) return __this_address; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return __this_address; fa = xfs_btree_sblock_v5hdr_verify(bp); if (fa) return fa; level = be16_to_cpu(block->bb_level); if (pag && pag->pagf_init) { if (level >= pag->pagf_refcount_level) return __this_address; } else if (level >= mp->m_refc_maxlevels) return __this_address; return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]); } STATIC void xfs_refcountbt_read_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; if (!xfs_btree_sblock_verify_crc(bp)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_refcountbt_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } if (bp->b_error) trace_xfs_btree_corrupt(bp, _RET_IP_); } STATIC void xfs_refcountbt_write_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_refcountbt_verify(bp); if (fa) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } xfs_btree_sblock_calc_crc(bp); } const struct xfs_buf_ops xfs_refcountbt_buf_ops = { .name = "xfs_refcountbt", .magic = { 0, cpu_to_be32(XFS_REFC_CRC_MAGIC) }, .verify_read = xfs_refcountbt_read_verify, .verify_write = xfs_refcountbt_write_verify, .verify_struct = xfs_refcountbt_verify, }; STATIC int xfs_refcountbt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be32_to_cpu(k1->refc.rc_startblock) < be32_to_cpu(k2->refc.rc_startblock); } STATIC int xfs_refcountbt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return be32_to_cpu(r1->refc.rc_startblock) + be32_to_cpu(r1->refc.rc_blockcount) <= be32_to_cpu(r2->refc.rc_startblock); } static const struct xfs_btree_ops xfs_refcountbt_ops = { .rec_len = sizeof(struct xfs_refcount_rec), .key_len = sizeof(struct xfs_refcount_key), .dup_cursor = xfs_refcountbt_dup_cursor, .set_root = xfs_refcountbt_set_root, .alloc_block = xfs_refcountbt_alloc_block, .free_block = xfs_refcountbt_free_block, .get_minrecs = xfs_refcountbt_get_minrecs, .get_maxrecs = xfs_refcountbt_get_maxrecs, .init_key_from_rec = xfs_refcountbt_init_key_from_rec, .init_high_key_from_rec = xfs_refcountbt_init_high_key_from_rec, .init_rec_from_cur = xfs_refcountbt_init_rec_from_cur, .init_ptr_from_cur = xfs_refcountbt_init_ptr_from_cur, .key_diff = xfs_refcountbt_key_diff, .buf_ops = &xfs_refcountbt_buf_ops, .diff_two_keys = xfs_refcountbt_diff_two_keys, .keys_inorder = xfs_refcountbt_keys_inorder, .recs_inorder = xfs_refcountbt_recs_inorder, }; /* * Allocate a new refcount btree cursor. */ struct xfs_btree_cur * xfs_refcountbt_init_cursor( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno) { struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); struct xfs_btree_cur *cur; ASSERT(agno != NULLAGNUMBER); ASSERT(agno < mp->m_sb.sb_agcount); cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_btnum = XFS_BTNUM_REFC; cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_ops = &xfs_refcountbt_ops; cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2); cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level); cur->bc_private.a.agbp = agbp; cur->bc_private.a.agno = agno; cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_private.a.priv.refc.nr_ops = 0; cur->bc_private.a.priv.refc.shape_changes = 0; return cur; } /* * Calculate the number of records in a refcount btree block. */ int xfs_refcountbt_maxrecs( int blocklen, bool leaf) { blocklen -= XFS_REFCOUNT_BLOCK_LEN; if (leaf) return blocklen / sizeof(struct xfs_refcount_rec); return blocklen / (sizeof(struct xfs_refcount_key) + sizeof(xfs_refcount_ptr_t)); } /* Compute the maximum height of a refcount btree. */ void xfs_refcountbt_compute_maxlevels( struct xfs_mount *mp) { mp->m_refc_maxlevels = xfs_btree_compute_maxlevels( mp->m_refc_mnr, mp->m_sb.sb_agblocks); } /* Calculate the refcount btree size for some records. */ xfs_extlen_t xfs_refcountbt_calc_size( struct xfs_mount *mp, unsigned long long len) { return xfs_btree_calc_size(mp->m_refc_mnr, len); } /* * Calculate the maximum refcount btree size. */ xfs_extlen_t xfs_refcountbt_max_size( struct xfs_mount *mp, xfs_agblock_t agblocks) { /* Bail out if we're uninitialized, which can happen in mkfs. */ if (mp->m_refc_mxr[0] == 0) return 0; return xfs_refcountbt_calc_size(mp, agblocks); } /* * Figure out how many blocks to reserve and how many are used by this btree. */ int xfs_refcountbt_calc_reserves( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used) { struct xfs_buf *agbp; struct xfs_agf *agf; xfs_agblock_t agblocks; xfs_extlen_t tree_len; int error; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return 0; error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); if (error) return error; agf = XFS_BUF_TO_AGF(agbp); agblocks = be32_to_cpu(agf->agf_length); tree_len = be32_to_cpu(agf->agf_refcount_blocks); xfs_trans_brelse(tp, agbp); /* * The log is permanently allocated, so the space it occupies will * never be available for the kinds of things that would require btree * expansion. We therefore can pretend the space isn't there. */ if (mp->m_sb.sb_logstart && XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno) agblocks -= mp->m_sb.sb_logblocks; *ask += xfs_refcountbt_max_size(mp, agblocks); *used += tree_len; return error; } xfsprogs-5.3.0/libxfs/xfs_refcount_btree.h0000644000175000017500000000344213435336036020603 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_REFCOUNT_BTREE_H__ #define __XFS_REFCOUNT_BTREE_H__ /* * Reference Count Btree on-disk structures */ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; /* * Btree block header size */ #define XFS_REFCOUNT_BLOCK_LEN XFS_BTREE_SBLOCK_CRC_LEN /* * Record, key, and pointer address macros for btree blocks. * * (note that some of these may appear unused, but they are used in userspace) */ #define XFS_REFCOUNT_REC_ADDR(block, index) \ ((struct xfs_refcount_rec *) \ ((char *)(block) + \ XFS_REFCOUNT_BLOCK_LEN + \ (((index) - 1) * sizeof(struct xfs_refcount_rec)))) #define XFS_REFCOUNT_KEY_ADDR(block, index) \ ((struct xfs_refcount_key *) \ ((char *)(block) + \ XFS_REFCOUNT_BLOCK_LEN + \ ((index) - 1) * sizeof(struct xfs_refcount_key))) #define XFS_REFCOUNT_PTR_ADDR(block, index, maxrecs) \ ((xfs_refcount_ptr_t *) \ ((char *)(block) + \ XFS_REFCOUNT_BLOCK_LEN + \ (maxrecs) * sizeof(struct xfs_refcount_key) + \ ((index) - 1) * sizeof(xfs_refcount_ptr_t))) extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno); extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf); extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp); extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp, unsigned long long len); extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp, xfs_agblock_t agblocks); extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); #endif /* __XFS_REFCOUNT_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_rmap.c0000644000175000017500000021174113570057155016534 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_btree.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_rmap.h" #include "xfs_rmap_btree.h" #include "xfs_trace.h" #include "xfs_inode.h" /* * Lookup the first record less than or equal to [bno, len, owner, offset] * in the btree given by cur. */ int xfs_rmap_lookup_le( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags, int *stat) { cur->bc_rec.r.rm_startblock = bno; cur->bc_rec.r.rm_blockcount = len; cur->bc_rec.r.rm_owner = owner; cur->bc_rec.r.rm_offset = offset; cur->bc_rec.r.rm_flags = flags; return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); } /* * Lookup the record exactly matching [bno, len, owner, offset] * in the btree given by cur. */ int xfs_rmap_lookup_eq( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags, int *stat) { cur->bc_rec.r.rm_startblock = bno; cur->bc_rec.r.rm_blockcount = len; cur->bc_rec.r.rm_owner = owner; cur->bc_rec.r.rm_offset = offset; cur->bc_rec.r.rm_flags = flags; return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); } /* * Update the record referred to by cur to the value given * by [bno, len, owner, offset]. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int xfs_rmap_update( struct xfs_btree_cur *cur, struct xfs_rmap_irec *irec) { union xfs_btree_rec rec; int error; trace_xfs_rmap_update(cur->bc_mp, cur->bc_private.a.agno, irec->rm_startblock, irec->rm_blockcount, irec->rm_owner, irec->rm_offset, irec->rm_flags); rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock); rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount); rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner); rec.rmap.rm_offset = cpu_to_be64( xfs_rmap_irec_offset_pack(irec)); error = xfs_btree_update(cur, &rec); if (error) trace_xfs_rmap_update_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } int xfs_rmap_insert( struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags) { int i; int error; trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, agbno, len, owner, offset, flags); error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 0, done); rcur->bc_rec.r.rm_startblock = agbno; rcur->bc_rec.r.rm_blockcount = len; rcur->bc_rec.r.rm_owner = owner; rcur->bc_rec.r.rm_offset = offset; rcur->bc_rec.r.rm_flags = flags; error = xfs_btree_insert(rcur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); done: if (error) trace_xfs_rmap_insert_error(rcur->bc_mp, rcur->bc_private.a.agno, error, _RET_IP_); return error; } STATIC int xfs_rmap_delete( struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags) { int i; int error; trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_private.a.agno, agbno, len, owner, offset, flags); error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); error = xfs_btree_delete(rcur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); done: if (error) trace_xfs_rmap_delete_error(rcur->bc_mp, rcur->bc_private.a.agno, error, _RET_IP_); return error; } /* Convert an internal btree record to an rmap record. */ int xfs_rmap_btrec_to_irec( union xfs_btree_rec *rec, struct xfs_rmap_irec *irec) { irec->rm_flags = 0; irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock); irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount); irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner); return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset), irec); } /* * Get the data from the pointed-to record. */ int xfs_rmap_get_rec( struct xfs_btree_cur *cur, struct xfs_rmap_irec *irec, int *stat) { struct xfs_mount *mp = cur->bc_mp; xfs_agnumber_t agno = cur->bc_private.a.agno; union xfs_btree_rec *rec; int error; error = xfs_btree_get_rec(cur, &rec, stat); if (error || !*stat) return error; if (xfs_rmap_btrec_to_irec(rec, irec)) goto out_bad_rec; if (irec->rm_blockcount == 0) goto out_bad_rec; if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) { if (irec->rm_owner != XFS_RMAP_OWN_FS) goto out_bad_rec; if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1) goto out_bad_rec; } else { /* check for valid extent range, including overflow */ if (!xfs_verify_agbno(mp, agno, irec->rm_startblock)) goto out_bad_rec; if (irec->rm_startblock > irec->rm_startblock + irec->rm_blockcount) goto out_bad_rec; if (!xfs_verify_agbno(mp, agno, irec->rm_startblock + irec->rm_blockcount - 1)) goto out_bad_rec; } if (!(xfs_verify_ino(mp, irec->rm_owner) || (irec->rm_owner <= XFS_RMAP_OWN_FS && irec->rm_owner >= XFS_RMAP_OWN_MIN))) goto out_bad_rec; return 0; out_bad_rec: xfs_warn(mp, "Reverse Mapping BTree record corruption in AG %d detected!", agno); xfs_warn(mp, "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x", irec->rm_owner, irec->rm_flags, irec->rm_startblock, irec->rm_blockcount); return -EFSCORRUPTED; } struct xfs_find_left_neighbor_info { struct xfs_rmap_irec high; struct xfs_rmap_irec *irec; int *stat; }; /* For each rmap given, figure out if it matches the key we want. */ STATIC int xfs_rmap_find_left_neighbor_helper( struct xfs_btree_cur *cur, struct xfs_rmap_irec *rec, void *priv) { struct xfs_find_left_neighbor_info *info = priv; trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp, cur->bc_private.a.agno, rec->rm_startblock, rec->rm_blockcount, rec->rm_owner, rec->rm_offset, rec->rm_flags); if (rec->rm_owner != info->high.rm_owner) return XFS_BTREE_QUERY_RANGE_CONTINUE; if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) && !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) && rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset) return XFS_BTREE_QUERY_RANGE_CONTINUE; *info->irec = *rec; *info->stat = 1; return XFS_BTREE_QUERY_RANGE_ABORT; } /* * Find the record to the left of the given extent, being careful only to * return a match with the same owner and adjacent physical and logical * block ranges. */ int xfs_rmap_find_left_neighbor( struct xfs_btree_cur *cur, xfs_agblock_t bno, uint64_t owner, uint64_t offset, unsigned int flags, struct xfs_rmap_irec *irec, int *stat) { struct xfs_find_left_neighbor_info info; int error; *stat = 0; if (bno == 0) return 0; info.high.rm_startblock = bno - 1; info.high.rm_owner = owner; if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK)) { if (offset == 0) return 0; info.high.rm_offset = offset - 1; } else info.high.rm_offset = 0; info.high.rm_flags = flags; info.high.rm_blockcount = 0; info.irec = irec; info.stat = stat; trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp, cur->bc_private.a.agno, bno, 0, owner, offset, flags); error = xfs_rmap_query_range(cur, &info.high, &info.high, xfs_rmap_find_left_neighbor_helper, &info); if (error == XFS_BTREE_QUERY_RANGE_ABORT) error = 0; if (*stat) trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp, cur->bc_private.a.agno, irec->rm_startblock, irec->rm_blockcount, irec->rm_owner, irec->rm_offset, irec->rm_flags); return error; } /* For each rmap given, figure out if it matches the key we want. */ STATIC int xfs_rmap_lookup_le_range_helper( struct xfs_btree_cur *cur, struct xfs_rmap_irec *rec, void *priv) { struct xfs_find_left_neighbor_info *info = priv; trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp, cur->bc_private.a.agno, rec->rm_startblock, rec->rm_blockcount, rec->rm_owner, rec->rm_offset, rec->rm_flags); if (rec->rm_owner != info->high.rm_owner) return XFS_BTREE_QUERY_RANGE_CONTINUE; if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) && !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) && (rec->rm_offset > info->high.rm_offset || rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset)) return XFS_BTREE_QUERY_RANGE_CONTINUE; *info->irec = *rec; *info->stat = 1; return XFS_BTREE_QUERY_RANGE_ABORT; } /* * Find the record to the left of the given extent, being careful only to * return a match with the same owner and overlapping physical and logical * block ranges. This is the overlapping-interval version of * xfs_rmap_lookup_le. */ int xfs_rmap_lookup_le_range( struct xfs_btree_cur *cur, xfs_agblock_t bno, uint64_t owner, uint64_t offset, unsigned int flags, struct xfs_rmap_irec *irec, int *stat) { struct xfs_find_left_neighbor_info info; int error; info.high.rm_startblock = bno; info.high.rm_owner = owner; if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK)) info.high.rm_offset = offset; else info.high.rm_offset = 0; info.high.rm_flags = flags; info.high.rm_blockcount = 0; *stat = 0; info.irec = irec; info.stat = stat; trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_private.a.agno, bno, 0, owner, offset, flags); error = xfs_rmap_query_range(cur, &info.high, &info.high, xfs_rmap_lookup_le_range_helper, &info); if (error == XFS_BTREE_QUERY_RANGE_ABORT) error = 0; if (*stat) trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, cur->bc_private.a.agno, irec->rm_startblock, irec->rm_blockcount, irec->rm_owner, irec->rm_offset, irec->rm_flags); return error; } /* * Perform all the relevant owner checks for a removal op. If we're doing an * unknown-owner removal then we have no owner information to check. */ static int xfs_rmap_free_check_owner( struct xfs_mount *mp, uint64_t ltoff, struct xfs_rmap_irec *rec, xfs_filblks_t len, uint64_t owner, uint64_t offset, unsigned int flags) { int error = 0; if (owner == XFS_RMAP_OWN_UNKNOWN) return 0; /* Make sure the unwritten flag matches. */ XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == (rec->rm_flags & XFS_RMAP_UNWRITTEN), out); /* Make sure the owner matches what we expect to find in the tree. */ XFS_WANT_CORRUPTED_GOTO(mp, owner == rec->rm_owner, out); /* Check the offset, if necessary. */ if (XFS_RMAP_NON_INODE_OWNER(owner)) goto out; if (flags & XFS_RMAP_BMBT_BLOCK) { XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_flags & XFS_RMAP_BMBT_BLOCK, out); } else { XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_offset <= offset, out); XFS_WANT_CORRUPTED_GOTO(mp, ltoff + rec->rm_blockcount >= offset + len, out); } out: return error; } /* * Find the extent in the rmap btree and remove it. * * The record we find should always be an exact match for the extent that we're * looking for, since we insert them into the btree without modification. * * Special Case #1: when growing the filesystem, we "free" an extent when * growing the last AG. This extent is new space and so it is not tracked as * used space in the btree. The growfs code will pass in an owner of * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this * extent. We verify that - the extent lookup result in a record that does not * overlap. * * Special Case #2: EFIs do not record the owner of the extent, so when * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap * btree to ignore the owner (i.e. wildcard match) so we don't trigger * corruption checks during log recovery. */ STATIC int xfs_rmap_unmap( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool unwritten, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = cur->bc_mp; struct xfs_rmap_irec ltrec; uint64_t ltoff; int error = 0; int i; uint64_t owner; uint64_t offset; unsigned int flags; bool ignore_off; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) || (flags & XFS_RMAP_BMBT_BLOCK); if (unwritten) flags |= XFS_RMAP_UNWRITTEN; trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); /* * We should always have a left record because there's a static record * for the AG headers at rm_startblock == 0 created by mkfs/growfs that * will not ever be removed from the tree. */ error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); error = xfs_rmap_get_rec(cur, <rec, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, cur->bc_private.a.agno, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags); ltoff = ltrec.rm_offset; /* * For growfs, the incoming extent must be beyond the left record we * just found as it is new space and won't be used by anyone. This is * just a corruption check as we don't actually do anything with this * extent. Note that we need to use >= instead of > because it might * be the case that the "left" extent goes all the way to EOFS. */ if (owner == XFS_RMAP_OWN_NULL) { XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock + ltrec.rm_blockcount, out_error); goto out_done; } /* * If we're doing an unknown-owner removal for EFI recovery, we expect * to find the full range in the rmapbt or nothing at all. If we * don't find any rmaps overlapping either end of the range, we're * done. Hopefully this means that the EFI creator already queued * (and finished) a RUI to remove the rmap. */ if (owner == XFS_RMAP_OWN_UNKNOWN && ltrec.rm_startblock + ltrec.rm_blockcount <= bno) { struct xfs_rmap_irec rtrec; error = xfs_btree_increment(cur, 0, &i); if (error) goto out_error; if (i == 0) goto out_done; error = xfs_rmap_get_rec(cur, &rtrec, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); if (rtrec.rm_startblock >= bno + len) goto out_done; } /* Make sure the extent we found covers the entire freeing range. */ XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && ltrec.rm_startblock + ltrec.rm_blockcount >= bno + len, out_error); /* Check owner information. */ error = xfs_rmap_free_check_owner(mp, ltoff, <rec, len, owner, offset, flags); if (error) goto out_error; if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { /* exact match, simply remove the record from rmap tree */ trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags); error = xfs_btree_delete(cur, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); } else if (ltrec.rm_startblock == bno) { /* * overlap left hand side of extent: move the start, trim the * length and update the current record. * * ltbno ltlen * Orig: |oooooooooooooooooooo| * Freeing: |fffffffff| * Result: |rrrrrrrrrr| * bno len */ ltrec.rm_startblock += len; ltrec.rm_blockcount -= len; if (!ignore_off) ltrec.rm_offset += len; error = xfs_rmap_update(cur, <rec); if (error) goto out_error; } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) { /* * overlap right hand side of extent: trim the length and update * the current record. * * ltbno ltlen * Orig: |oooooooooooooooooooo| * Freeing: |fffffffff| * Result: |rrrrrrrrrr| * bno len */ ltrec.rm_blockcount -= len; error = xfs_rmap_update(cur, <rec); if (error) goto out_error; } else { /* * overlap middle of extent: trim the length of the existing * record to the length of the new left-extent size, increment * the insertion position so we can insert a new record * containing the remaining right-extent space. * * ltbno ltlen * Orig: |oooooooooooooooooooo| * Freeing: |fffffffff| * Result: |rrrrr| |rrrr| * bno len */ xfs_extlen_t orig_len = ltrec.rm_blockcount; ltrec.rm_blockcount = bno - ltrec.rm_startblock; error = xfs_rmap_update(cur, <rec); if (error) goto out_error; error = xfs_btree_increment(cur, 0, &i); if (error) goto out_error; cur->bc_rec.r.rm_startblock = bno + len; cur->bc_rec.r.rm_blockcount = orig_len - len - ltrec.rm_blockcount; cur->bc_rec.r.rm_owner = ltrec.rm_owner; if (ignore_off) cur->bc_rec.r.rm_offset = 0; else cur->bc_rec.r.rm_offset = offset + len; cur->bc_rec.r.rm_flags = flags; trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, cur->bc_rec.r.rm_startblock, cur->bc_rec.r.rm_blockcount, cur->bc_rec.r.rm_owner, cur->bc_rec.r.rm_offset, cur->bc_rec.r.rm_flags); error = xfs_btree_insert(cur, &i); if (error) goto out_error; } out_done: trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); out_error: if (error) trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Remove a reference to an extent in the rmap btree. */ int xfs_rmap_free( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = tp->t_mountp; struct xfs_btree_cur *cur; int error; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 0; cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); error = xfs_rmap_unmap(cur, bno, len, false, oinfo); xfs_btree_del_cursor(cur, error); return error; } /* * A mergeable rmap must have the same owner and the same values for * the unwritten, attr_fork, and bmbt flags. The startblock and * offset are checked separately. */ static bool xfs_rmap_is_mergeable( struct xfs_rmap_irec *irec, uint64_t owner, unsigned int flags) { if (irec->rm_owner == XFS_RMAP_OWN_NULL) return false; if (irec->rm_owner != owner) return false; if ((flags & XFS_RMAP_UNWRITTEN) ^ (irec->rm_flags & XFS_RMAP_UNWRITTEN)) return false; if ((flags & XFS_RMAP_ATTR_FORK) ^ (irec->rm_flags & XFS_RMAP_ATTR_FORK)) return false; if ((flags & XFS_RMAP_BMBT_BLOCK) ^ (irec->rm_flags & XFS_RMAP_BMBT_BLOCK)) return false; return true; } /* * When we allocate a new block, the first thing we do is add a reference to * the extent in the rmap btree. This takes the form of a [agbno, length, * owner, offset] record. Flags are encoded in the high bits of the offset * field. */ STATIC int xfs_rmap_map( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool unwritten, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = cur->bc_mp; struct xfs_rmap_irec ltrec; struct xfs_rmap_irec gtrec; int have_gt; int have_lt; int error = 0; int i; uint64_t owner; uint64_t offset; unsigned int flags = 0; bool ignore_off; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); ASSERT(owner != 0); ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) || (flags & XFS_RMAP_BMBT_BLOCK); if (unwritten) flags |= XFS_RMAP_UNWRITTEN; trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); ASSERT(!xfs_rmap_should_skip_owner_update(oinfo)); /* * For the initial lookup, look for an exact match or the left-adjacent * record for our insertion point. This will also give us the record for * start block contiguity tests. */ error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &have_lt); if (error) goto out_error; if (have_lt) { error = xfs_rmap_get_rec(cur, <rec, &have_lt); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error); trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, cur->bc_private.a.agno, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags); if (!xfs_rmap_is_mergeable(<rec, owner, flags)) have_lt = 0; } XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 0 || ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error); /* * Increment the cursor to see if we have a right-adjacent record to our * insertion point. This will give us the record for end block * contiguity tests. */ error = xfs_btree_increment(cur, 0, &have_gt); if (error) goto out_error; if (have_gt) { error = xfs_rmap_get_rec(cur, >rec, &have_gt); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error); XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock, out_error); trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, cur->bc_private.a.agno, gtrec.rm_startblock, gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_offset, gtrec.rm_flags); if (!xfs_rmap_is_mergeable(>rec, owner, flags)) have_gt = 0; } /* * Note: cursor currently points one record to the right of ltrec, even * if there is no record in the tree to the right. */ if (have_lt && ltrec.rm_startblock + ltrec.rm_blockcount == bno && (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) { /* * left edge contiguous, merge into left record. * * ltbno ltlen * orig: |ooooooooo| * adding: |aaaaaaaaa| * result: |rrrrrrrrrrrrrrrrrrr| * bno len */ ltrec.rm_blockcount += len; if (have_gt && bno + len == gtrec.rm_startblock && (ignore_off || offset + len == gtrec.rm_offset) && (unsigned long)ltrec.rm_blockcount + len + gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) { /* * right edge also contiguous, delete right record * and merge into left record. * * ltbno ltlen gtbno gtlen * orig: |ooooooooo| |ooooooooo| * adding: |aaaaaaaaa| * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr| */ ltrec.rm_blockcount += gtrec.rm_blockcount; trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, gtrec.rm_startblock, gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_offset, gtrec.rm_flags); error = xfs_btree_delete(cur, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); } /* point the cursor back to the left record and update */ error = xfs_btree_decrement(cur, 0, &have_gt); if (error) goto out_error; error = xfs_rmap_update(cur, <rec); if (error) goto out_error; } else if (have_gt && bno + len == gtrec.rm_startblock && (ignore_off || offset + len == gtrec.rm_offset)) { /* * right edge contiguous, merge into right record. * * gtbno gtlen * Orig: |ooooooooo| * adding: |aaaaaaaaa| * Result: |rrrrrrrrrrrrrrrrrrr| * bno len */ gtrec.rm_startblock = bno; gtrec.rm_blockcount += len; if (!ignore_off) gtrec.rm_offset = offset; error = xfs_rmap_update(cur, >rec); if (error) goto out_error; } else { /* * no contiguous edge with identical owner, insert * new record at current cursor position. */ cur->bc_rec.r.rm_startblock = bno; cur->bc_rec.r.rm_blockcount = len; cur->bc_rec.r.rm_owner = owner; cur->bc_rec.r.rm_offset = offset; cur->bc_rec.r.rm_flags = flags; trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len, owner, offset, flags); error = xfs_btree_insert(cur, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); } trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); out_error: if (error) trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Add a reference to an extent in the rmap btree. */ int xfs_rmap_alloc( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = tp->t_mountp; struct xfs_btree_cur *cur; int error; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 0; cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); error = xfs_rmap_map(cur, bno, len, false, oinfo); xfs_btree_del_cursor(cur, error); return error; } #define RMAP_LEFT_CONTIG (1 << 0) #define RMAP_RIGHT_CONTIG (1 << 1) #define RMAP_LEFT_FILLING (1 << 2) #define RMAP_RIGHT_FILLING (1 << 3) #define RMAP_LEFT_VALID (1 << 6) #define RMAP_RIGHT_VALID (1 << 7) #define LEFT r[0] #define RIGHT r[1] #define PREV r[2] #define NEW r[3] /* * Convert an unwritten extent to a real extent or vice versa. * Does not handle overlapping extents. */ STATIC int xfs_rmap_convert( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool unwritten, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = cur->bc_mp; struct xfs_rmap_irec r[4]; /* neighbor extent entries */ /* left is 0, right is 1, */ /* prev is 2, new is 3 */ uint64_t owner; uint64_t offset; uint64_t new_endoff; unsigned int oldext; unsigned int newext; unsigned int flags = 0; int i; int state = 0; int error; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) || (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)))); oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0; new_endoff = offset + len; trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); /* * For the initial lookup, look for an exact match or the left-adjacent * record for our insertion point. This will also give us the record for * start block contiguity tests. */ error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_rmap_get_rec(cur, &PREV, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, cur->bc_private.a.agno, PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_owner, PREV.rm_offset, PREV.rm_flags); ASSERT(PREV.rm_offset <= offset); ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff); ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext); newext = ~oldext & XFS_RMAP_UNWRITTEN; /* * Set flags determining what part of the previous oldext allocation * extent is being replaced by a newext allocation. */ if (PREV.rm_offset == offset) state |= RMAP_LEFT_FILLING; if (PREV.rm_offset + PREV.rm_blockcount == new_endoff) state |= RMAP_RIGHT_FILLING; /* * Decrement the cursor to see if we have a left-adjacent record to our * insertion point. This will give us the record for end block * contiguity tests. */ error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; if (i) { state |= RMAP_LEFT_VALID; error = xfs_rmap_get_rec(cur, &LEFT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); XFS_WANT_CORRUPTED_GOTO(mp, LEFT.rm_startblock + LEFT.rm_blockcount <= bno, done); trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp, cur->bc_private.a.agno, LEFT.rm_startblock, LEFT.rm_blockcount, LEFT.rm_owner, LEFT.rm_offset, LEFT.rm_flags); if (LEFT.rm_startblock + LEFT.rm_blockcount == bno && LEFT.rm_offset + LEFT.rm_blockcount == offset && xfs_rmap_is_mergeable(&LEFT, owner, newext)) state |= RMAP_LEFT_CONTIG; } /* * Increment the cursor to see if we have a right-adjacent record to our * insertion point. This will give us the record for end block * contiguity tests. */ error = xfs_btree_increment(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_increment(cur, 0, &i); if (error) goto done; if (i) { state |= RMAP_RIGHT_VALID; error = xfs_rmap_get_rec(cur, &RIGHT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock, done); trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, cur->bc_private.a.agno, RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_flags); if (bno + len == RIGHT.rm_startblock && offset + len == RIGHT.rm_offset && xfs_rmap_is_mergeable(&RIGHT, owner, newext)) state |= RMAP_RIGHT_CONTIG; } /* check that left + prev + right is not too long */ if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) == (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) && (unsigned long)LEFT.rm_blockcount + len + RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX) state &= ~RMAP_RIGHT_CONTIG; trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state, _RET_IP_); /* reset the cursor back to PREV */ error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* * Switch out based on the FILLING and CONTIG state bits. */ switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) { case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left and right neighbors are both contiguous with new. */ error = xfs_btree_increment(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_flags); error = xfs_btree_delete(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_owner, PREV.rm_offset, PREV.rm_flags); error = xfs_btree_delete(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW = LEFT; NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left neighbor is contiguous, the right is not. */ trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_owner, PREV.rm_offset, PREV.rm_flags); error = xfs_btree_delete(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW = LEFT; NEW.rm_blockcount += PREV.rm_blockcount; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The right neighbor is contiguous, the left is not. */ error = xfs_btree_increment(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_flags); error = xfs_btree_delete(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW = PREV; NEW.rm_blockcount = len + RIGHT.rm_blockcount; NEW.rm_flags = newext; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING: /* * Setting all of a previous oldext extent to newext. * Neither the left nor right neighbors are contiguous with * the new one. */ NEW = PREV; NEW.rm_flags = newext; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is contiguous. */ NEW = PREV; NEW.rm_offset += len; NEW.rm_startblock += len; NEW.rm_blockcount -= len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; error = xfs_btree_decrement(cur, 0, &i); if (error) goto done; NEW = LEFT; NEW.rm_blockcount += len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is not contiguous. */ NEW = PREV; NEW.rm_startblock += len; NEW.rm_offset += len; NEW.rm_blockcount -= len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; NEW.rm_startblock = bno; NEW.rm_owner = owner; NEW.rm_offset = offset; NEW.rm_blockcount = len; NEW.rm_flags = newext; cur->bc_rec.r = NEW; trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len, owner, offset, newext); error = xfs_btree_insert(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); break; case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is contiguous with the new allocation. */ NEW = PREV; NEW.rm_blockcount -= len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; error = xfs_btree_increment(cur, 0, &i); if (error) goto done; NEW = RIGHT; NEW.rm_offset = offset; NEW.rm_startblock = bno; NEW.rm_blockcount += len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_RIGHT_FILLING: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is not contiguous. */ NEW = PREV; NEW.rm_blockcount -= len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset, oldext, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); NEW.rm_startblock = bno; NEW.rm_owner = owner; NEW.rm_offset = offset; NEW.rm_blockcount = len; NEW.rm_flags = newext; cur->bc_rec.r = NEW; trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len, owner, offset, newext); error = xfs_btree_insert(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); break; case 0: /* * Setting the middle part of a previous oldext extent to * newext. Contiguity is impossible here. * One extent becomes three extents. */ /* new right extent - oldext */ NEW.rm_startblock = bno + len; NEW.rm_owner = owner; NEW.rm_offset = new_endoff; NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount - new_endoff; NEW.rm_flags = PREV.rm_flags; error = xfs_rmap_update(cur, &NEW); if (error) goto done; /* new left extent - oldext */ NEW = PREV; NEW.rm_blockcount = offset - PREV.rm_offset; cur->bc_rec.r = NEW; trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); error = xfs_btree_insert(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* * Reset the cursor to the position of the new extent * we are about to insert as we can't trust it after * the previous insert. */ error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset, oldext, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); /* new middle extent - newext */ cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN; cur->bc_rec.r.rm_flags |= newext; trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len, owner, offset, newext); error = xfs_btree_insert(cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); break; case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG: case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: case RMAP_LEFT_CONTIG: case RMAP_RIGHT_CONTIG: /* * These cases are all impossible. */ ASSERT(0); } trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); done: if (error) trace_xfs_rmap_convert_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Convert an unwritten extent to a real extent or vice versa. If there is no * possibility of overlapping extents, delegate to the simpler convert * function. */ STATIC int xfs_rmap_convert_shared( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool unwritten, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = cur->bc_mp; struct xfs_rmap_irec r[4]; /* neighbor extent entries */ /* left is 0, right is 1, */ /* prev is 2, new is 3 */ uint64_t owner; uint64_t offset; uint64_t new_endoff; unsigned int oldext; unsigned int newext; unsigned int flags = 0; int i; int state = 0; int error; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) || (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)))); oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0; new_endoff = offset + len; trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); /* * For the initial lookup, look for and exact match or the left-adjacent * record for our insertion point. This will also give us the record for * start block contiguity tests. */ error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags, &PREV, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); ASSERT(PREV.rm_offset <= offset); ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff); ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext); newext = ~oldext & XFS_RMAP_UNWRITTEN; /* * Set flags determining what part of the previous oldext allocation * extent is being replaced by a newext allocation. */ if (PREV.rm_offset == offset) state |= RMAP_LEFT_FILLING; if (PREV.rm_offset + PREV.rm_blockcount == new_endoff) state |= RMAP_RIGHT_FILLING; /* Is there a left record that abuts our range? */ error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext, &LEFT, &i); if (error) goto done; if (i) { state |= RMAP_LEFT_VALID; XFS_WANT_CORRUPTED_GOTO(mp, LEFT.rm_startblock + LEFT.rm_blockcount <= bno, done); if (xfs_rmap_is_mergeable(&LEFT, owner, newext)) state |= RMAP_LEFT_CONTIG; } /* Is there a right record that abuts our range? */ error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len, newext, &i); if (error) goto done; if (i) { state |= RMAP_RIGHT_VALID; error = xfs_rmap_get_rec(cur, &RIGHT, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock, done); trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, cur->bc_private.a.agno, RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_flags); if (xfs_rmap_is_mergeable(&RIGHT, owner, newext)) state |= RMAP_RIGHT_CONTIG; } /* check that left + prev + right is not too long */ if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) == (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) && (unsigned long)LEFT.rm_blockcount + len + RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX) state &= ~RMAP_RIGHT_CONTIG; trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state, _RET_IP_); /* * Switch out based on the FILLING and CONTIG state bits. */ switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) { case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left and right neighbors are both contiguous with new. */ error = xfs_rmap_delete(cur, RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_flags); if (error) goto done; error = xfs_rmap_delete(cur, PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_owner, PREV.rm_offset, PREV.rm_flags); if (error) goto done; NEW = LEFT; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left neighbor is contiguous, the right is not. */ error = xfs_rmap_delete(cur, PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_owner, PREV.rm_offset, PREV.rm_flags); if (error) goto done; NEW = LEFT; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount += PREV.rm_blockcount; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The right neighbor is contiguous, the left is not. */ error = xfs_rmap_delete(cur, RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_flags); if (error) goto done; NEW = PREV; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount += RIGHT.rm_blockcount; NEW.rm_flags = RIGHT.rm_flags; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING: /* * Setting all of a previous oldext extent to newext. * Neither the left nor right neighbors are contiguous with * the new one. */ NEW = PREV; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_flags = newext; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is contiguous. */ NEW = PREV; error = xfs_rmap_delete(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; NEW.rm_offset += len; NEW.rm_startblock += len; NEW.rm_blockcount -= len; error = xfs_rmap_insert(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; NEW = LEFT; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount += len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; break; case RMAP_LEFT_FILLING: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is not contiguous. */ NEW = PREV; error = xfs_rmap_delete(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; NEW.rm_offset += len; NEW.rm_startblock += len; NEW.rm_blockcount -= len; error = xfs_rmap_insert(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; error = xfs_rmap_insert(cur, bno, len, owner, offset, newext); if (error) goto done; break; case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is contiguous with the new allocation. */ NEW = PREV; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount = offset - NEW.rm_offset; error = xfs_rmap_update(cur, &NEW); if (error) goto done; NEW = RIGHT; error = xfs_rmap_delete(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; NEW.rm_offset = offset; NEW.rm_startblock = bno; NEW.rm_blockcount += len; error = xfs_rmap_insert(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; break; case RMAP_RIGHT_FILLING: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is not contiguous. */ NEW = PREV; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount -= len; error = xfs_rmap_update(cur, &NEW); if (error) goto done; error = xfs_rmap_insert(cur, bno, len, owner, offset, newext); if (error) goto done; break; case 0: /* * Setting the middle part of a previous oldext extent to * newext. Contiguity is impossible here. * One extent becomes three extents. */ /* new right extent - oldext */ NEW.rm_startblock = bno + len; NEW.rm_owner = owner; NEW.rm_offset = new_endoff; NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount - new_endoff; NEW.rm_flags = PREV.rm_flags; error = xfs_rmap_insert(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; /* new left extent - oldext */ NEW = PREV; error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); NEW.rm_blockcount = offset - NEW.rm_offset; error = xfs_rmap_update(cur, &NEW); if (error) goto done; /* new middle extent - newext */ NEW.rm_startblock = bno; NEW.rm_blockcount = len; NEW.rm_owner = owner; NEW.rm_offset = offset; NEW.rm_flags = newext; error = xfs_rmap_insert(cur, NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, NEW.rm_flags); if (error) goto done; break; case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG: case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: case RMAP_LEFT_CONTIG: case RMAP_RIGHT_CONTIG: /* * These cases are all impossible. */ ASSERT(0); } trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); done: if (error) trace_xfs_rmap_convert_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } #undef NEW #undef LEFT #undef RIGHT #undef PREV /* * Find an extent in the rmap btree and unmap it. For rmap extent types that * can overlap (data fork rmaps on reflink filesystems) we must be careful * that the prev/next records in the btree might belong to another owner. * Therefore we must use delete+insert to alter any of the key fields. * * For every other situation there can only be one owner for a given extent, * so we can call the regular _free function. */ STATIC int xfs_rmap_unmap_shared( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool unwritten, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = cur->bc_mp; struct xfs_rmap_irec ltrec; uint64_t ltoff; int error = 0; int i; uint64_t owner; uint64_t offset; unsigned int flags; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); if (unwritten) flags |= XFS_RMAP_UNWRITTEN; trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); /* * We should always have a left record because there's a static record * for the AG headers at rm_startblock == 0 created by mkfs/growfs that * will not ever be removed from the tree. */ error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags, <rec, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); ltoff = ltrec.rm_offset; /* Make sure the extent we found covers the entire freeing range. */ XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && ltrec.rm_startblock + ltrec.rm_blockcount >= bno + len, out_error); /* Make sure the owner matches what we expect to find in the tree. */ XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner, out_error); /* Make sure the unwritten flag matches. */ XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error); /* Check the offset. */ XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_offset <= offset, out_error); XFS_WANT_CORRUPTED_GOTO(mp, offset <= ltoff + ltrec.rm_blockcount, out_error); if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { /* Exact match, simply remove the record from rmap tree. */ error = xfs_rmap_delete(cur, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags); if (error) goto out_error; } else if (ltrec.rm_startblock == bno) { /* * Overlap left hand side of extent: move the start, trim the * length and update the current record. * * ltbno ltlen * Orig: |oooooooooooooooooooo| * Freeing: |fffffffff| * Result: |rrrrrrrrrr| * bno len */ /* Delete prev rmap. */ error = xfs_rmap_delete(cur, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags); if (error) goto out_error; /* Add an rmap at the new offset. */ ltrec.rm_startblock += len; ltrec.rm_blockcount -= len; ltrec.rm_offset += len; error = xfs_rmap_insert(cur, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags); if (error) goto out_error; } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) { /* * Overlap right hand side of extent: trim the length and * update the current record. * * ltbno ltlen * Orig: |oooooooooooooooooooo| * Freeing: |fffffffff| * Result: |rrrrrrrrrr| * bno len */ error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); ltrec.rm_blockcount -= len; error = xfs_rmap_update(cur, <rec); if (error) goto out_error; } else { /* * Overlap middle of extent: trim the length of the existing * record to the length of the new left-extent size, increment * the insertion position so we can insert a new record * containing the remaining right-extent space. * * ltbno ltlen * Orig: |oooooooooooooooooooo| * Freeing: |fffffffff| * Result: |rrrrr| |rrrr| * bno len */ xfs_extlen_t orig_len = ltrec.rm_blockcount; /* Shrink the left side of the rmap */ error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); ltrec.rm_blockcount = bno - ltrec.rm_startblock; error = xfs_rmap_update(cur, <rec); if (error) goto out_error; /* Add an rmap at the new offset */ error = xfs_rmap_insert(cur, bno + len, orig_len - len - ltrec.rm_blockcount, ltrec.rm_owner, offset + len, ltrec.rm_flags); if (error) goto out_error; } trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); out_error: if (error) trace_xfs_rmap_unmap_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* * Find an extent in the rmap btree and map it. For rmap extent types that * can overlap (data fork rmaps on reflink filesystems) we must be careful * that the prev/next records in the btree might belong to another owner. * Therefore we must use delete+insert to alter any of the key fields. * * For every other situation there can only be one owner for a given extent, * so we can call the regular _alloc function. */ STATIC int xfs_rmap_map_shared( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool unwritten, const struct xfs_owner_info *oinfo) { struct xfs_mount *mp = cur->bc_mp; struct xfs_rmap_irec ltrec; struct xfs_rmap_irec gtrec; int have_gt; int have_lt; int error = 0; int i; uint64_t owner; uint64_t offset; unsigned int flags = 0; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); if (unwritten) flags |= XFS_RMAP_UNWRITTEN; trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); /* Is there a left record that abuts our range? */ error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags, <rec, &have_lt); if (error) goto out_error; if (have_lt && !xfs_rmap_is_mergeable(<rec, owner, flags)) have_lt = 0; /* Is there a right record that abuts our range? */ error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len, flags, &have_gt); if (error) goto out_error; if (have_gt) { error = xfs_rmap_get_rec(cur, >rec, &have_gt); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error); trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, cur->bc_private.a.agno, gtrec.rm_startblock, gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_offset, gtrec.rm_flags); if (!xfs_rmap_is_mergeable(>rec, owner, flags)) have_gt = 0; } if (have_lt && ltrec.rm_startblock + ltrec.rm_blockcount == bno && ltrec.rm_offset + ltrec.rm_blockcount == offset) { /* * Left edge contiguous, merge into left record. * * ltbno ltlen * orig: |ooooooooo| * adding: |aaaaaaaaa| * result: |rrrrrrrrrrrrrrrrrrr| * bno len */ ltrec.rm_blockcount += len; if (have_gt && bno + len == gtrec.rm_startblock && offset + len == gtrec.rm_offset) { /* * Right edge also contiguous, delete right record * and merge into left record. * * ltbno ltlen gtbno gtlen * orig: |ooooooooo| |ooooooooo| * adding: |aaaaaaaaa| * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr| */ ltrec.rm_blockcount += gtrec.rm_blockcount; error = xfs_rmap_delete(cur, gtrec.rm_startblock, gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_offset, gtrec.rm_flags); if (error) goto out_error; } /* Point the cursor back to the left record and update. */ error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_flags, &i); if (error) goto out_error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); error = xfs_rmap_update(cur, <rec); if (error) goto out_error; } else if (have_gt && bno + len == gtrec.rm_startblock && offset + len == gtrec.rm_offset) { /* * Right edge contiguous, merge into right record. * * gtbno gtlen * Orig: |ooooooooo| * adding: |aaaaaaaaa| * Result: |rrrrrrrrrrrrrrrrrrr| * bno len */ /* Delete the old record. */ error = xfs_rmap_delete(cur, gtrec.rm_startblock, gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_offset, gtrec.rm_flags); if (error) goto out_error; /* Move the start and re-add it. */ gtrec.rm_startblock = bno; gtrec.rm_blockcount += len; gtrec.rm_offset = offset; error = xfs_rmap_insert(cur, gtrec.rm_startblock, gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_offset, gtrec.rm_flags); if (error) goto out_error; } else { /* * No contiguous edge with identical owner, insert * new record at current cursor position. */ error = xfs_rmap_insert(cur, bno, len, owner, offset, flags); if (error) goto out_error; } trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len, unwritten, oinfo); out_error: if (error) trace_xfs_rmap_map_error(cur->bc_mp, cur->bc_private.a.agno, error, _RET_IP_); return error; } /* Insert a raw rmap into the rmapbt. */ int xfs_rmap_map_raw( struct xfs_btree_cur *cur, struct xfs_rmap_irec *rmap) { struct xfs_owner_info oinfo; oinfo.oi_owner = rmap->rm_owner; oinfo.oi_offset = rmap->rm_offset; oinfo.oi_flags = 0; if (rmap->rm_flags & XFS_RMAP_ATTR_FORK) oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK; if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK) oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK; if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner)) return xfs_rmap_map(cur, rmap->rm_startblock, rmap->rm_blockcount, rmap->rm_flags & XFS_RMAP_UNWRITTEN, &oinfo); return xfs_rmap_map_shared(cur, rmap->rm_startblock, rmap->rm_blockcount, rmap->rm_flags & XFS_RMAP_UNWRITTEN, &oinfo); } struct xfs_rmap_query_range_info { xfs_rmap_query_range_fn fn; void *priv; }; /* Format btree record and pass to our callback. */ STATIC int xfs_rmap_query_range_helper( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, void *priv) { struct xfs_rmap_query_range_info *query = priv; struct xfs_rmap_irec irec; int error; error = xfs_rmap_btrec_to_irec(rec, &irec); if (error) return error; return query->fn(cur, &irec, query->priv); } /* Find all rmaps between two keys. */ int xfs_rmap_query_range( struct xfs_btree_cur *cur, struct xfs_rmap_irec *low_rec, struct xfs_rmap_irec *high_rec, xfs_rmap_query_range_fn fn, void *priv) { union xfs_btree_irec low_brec; union xfs_btree_irec high_brec; struct xfs_rmap_query_range_info query; low_brec.r = *low_rec; high_brec.r = *high_rec; query.priv = priv; query.fn = fn; return xfs_btree_query_range(cur, &low_brec, &high_brec, xfs_rmap_query_range_helper, &query); } /* Find all rmaps. */ int xfs_rmap_query_all( struct xfs_btree_cur *cur, xfs_rmap_query_range_fn fn, void *priv) { struct xfs_rmap_query_range_info query; query.priv = priv; query.fn = fn; return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query); } /* Clean up after calling xfs_rmap_finish_one. */ void xfs_rmap_finish_one_cleanup( struct xfs_trans *tp, struct xfs_btree_cur *rcur, int error) { struct xfs_buf *agbp; if (rcur == NULL) return; agbp = rcur->bc_private.a.agbp; xfs_btree_del_cursor(rcur, error); if (error) xfs_trans_brelse(tp, agbp); } /* * Process one of the deferred rmap operations. We pass back the * btree cursor to maintain our lock on the rmapbt between calls. * This saves time and eliminates a buffer deadlock between the * superblock and the AGF because we'll always grab them in the same * order. */ int xfs_rmap_finish_one( struct xfs_trans *tp, enum xfs_rmap_intent_type type, uint64_t owner, int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock, xfs_filblks_t blockcount, xfs_exntst_t state, struct xfs_btree_cur **pcur) { struct xfs_mount *mp = tp->t_mountp; struct xfs_btree_cur *rcur; struct xfs_buf *agbp = NULL; int error = 0; xfs_agnumber_t agno; struct xfs_owner_info oinfo; xfs_agblock_t bno; bool unwritten; agno = XFS_FSB_TO_AGNO(mp, startblock); ASSERT(agno != NULLAGNUMBER); bno = XFS_FSB_TO_AGBNO(mp, startblock); trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork, startoff, blockcount, state); if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE)) return -EIO; /* * If we haven't gotten a cursor or the cursor AG doesn't match * the startblock, get one now. */ rcur = *pcur; if (rcur != NULL && rcur->bc_private.a.agno != agno) { xfs_rmap_finish_one_cleanup(tp, rcur, 0); rcur = NULL; *pcur = NULL; } if (rcur == NULL) { /* * Refresh the freelist before we start changing the * rmapbt, because a shape change could cause us to * allocate blocks. */ error = xfs_free_extent_fix_freelist(tp, agno, &agbp); if (error) return error; if (!agbp) return -EFSCORRUPTED; rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); if (!rcur) { error = -ENOMEM; goto out_cur; } } *pcur = rcur; xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff); unwritten = state == XFS_EXT_UNWRITTEN; bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock); switch (type) { case XFS_RMAP_ALLOC: case XFS_RMAP_MAP: error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo); break; case XFS_RMAP_MAP_SHARED: error = xfs_rmap_map_shared(rcur, bno, blockcount, unwritten, &oinfo); break; case XFS_RMAP_FREE: case XFS_RMAP_UNMAP: error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten, &oinfo); break; case XFS_RMAP_UNMAP_SHARED: error = xfs_rmap_unmap_shared(rcur, bno, blockcount, unwritten, &oinfo); break; case XFS_RMAP_CONVERT: error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten, &oinfo); break; case XFS_RMAP_CONVERT_SHARED: error = xfs_rmap_convert_shared(rcur, bno, blockcount, !unwritten, &oinfo); break; default: ASSERT(0); error = -EFSCORRUPTED; } return error; out_cur: xfs_trans_brelse(tp, agbp); return error; } /* * Don't defer an rmap if we aren't an rmap filesystem. */ static bool xfs_rmap_update_is_needed( struct xfs_mount *mp, int whichfork) { return xfs_sb_version_hasrmapbt(&mp->m_sb) && whichfork != XFS_COW_FORK; } /* * Record a rmap intent; the list is kept sorted first by AG and then by * increasing age. */ static int __xfs_rmap_add( struct xfs_trans *tp, enum xfs_rmap_intent_type type, uint64_t owner, int whichfork, struct xfs_bmbt_irec *bmap) { struct xfs_rmap_intent *ri; trace_xfs_rmap_defer(tp->t_mountp, XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock), type, XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock), owner, whichfork, bmap->br_startoff, bmap->br_blockcount, bmap->br_state); ri = kmem_alloc(sizeof(struct xfs_rmap_intent), KM_SLEEP | KM_NOFS); INIT_LIST_HEAD(&ri->ri_list); ri->ri_type = type; ri->ri_owner = owner; ri->ri_whichfork = whichfork; ri->ri_bmap = *bmap; xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list); return 0; } /* Map an extent into a file. */ int xfs_rmap_map_extent( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *PREV) { if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork)) return 0; return __xfs_rmap_add(tp, xfs_is_reflink_inode(ip) ? XFS_RMAP_MAP_SHARED : XFS_RMAP_MAP, ip->i_ino, whichfork, PREV); } /* Unmap an extent out of a file. */ int xfs_rmap_unmap_extent( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *PREV) { if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork)) return 0; return __xfs_rmap_add(tp, xfs_is_reflink_inode(ip) ? XFS_RMAP_UNMAP_SHARED : XFS_RMAP_UNMAP, ip->i_ino, whichfork, PREV); } /* * Convert a data fork extent from unwritten to real or vice versa. * * Note that tp can be NULL here as no transaction is used for COW fork * unwritten conversion. */ int xfs_rmap_convert_extent( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *PREV) { if (!xfs_rmap_update_is_needed(mp, whichfork)) return 0; return __xfs_rmap_add(tp, xfs_is_reflink_inode(ip) ? XFS_RMAP_CONVERT_SHARED : XFS_RMAP_CONVERT, ip->i_ino, whichfork, PREV); } /* Schedule the creation of an rmap for non-file data. */ int xfs_rmap_alloc_extent( struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner) { struct xfs_bmbt_irec bmap; if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK)) return 0; bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno); bmap.br_blockcount = len; bmap.br_startoff = 0; bmap.br_state = XFS_EXT_NORM; return __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap); } /* Schedule the deletion of an rmap for non-file data. */ int xfs_rmap_free_extent( struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner) { struct xfs_bmbt_irec bmap; if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK)) return 0; bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno); bmap.br_blockcount = len; bmap.br_startoff = 0; bmap.br_state = XFS_EXT_NORM; return __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap); } /* Compare rmap records. Returns -1 if a < b, 1 if a > b, and 0 if equal. */ int xfs_rmap_compare( const struct xfs_rmap_irec *a, const struct xfs_rmap_irec *b) { __u64 oa; __u64 ob; oa = xfs_rmap_irec_offset_pack(a); ob = xfs_rmap_irec_offset_pack(b); if (a->rm_startblock < b->rm_startblock) return -1; else if (a->rm_startblock > b->rm_startblock) return 1; else if (a->rm_owner < b->rm_owner) return -1; else if (a->rm_owner > b->rm_owner) return 1; else if (oa < ob) return -1; else if (oa > ob) return 1; else return 0; } /* Is there a record covering a given extent? */ int xfs_rmap_has_record( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists) { union xfs_btree_irec low; union xfs_btree_irec high; memset(&low, 0, sizeof(low)); low.r.rm_startblock = bno; memset(&high, 0xFF, sizeof(high)); high.r.rm_startblock = bno + len - 1; return xfs_btree_has_record(cur, &low, &high, exists); } /* * Is there a record for this owner completely covering a given physical * extent? If so, *has_rmap will be set to true. If there is no record * or the record only covers part of the range, we set *has_rmap to false. * This function doesn't perform range lookups or offset checks, so it is * not suitable for checking data fork blocks. */ int xfs_rmap_record_exists( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, bool *has_rmap) { uint64_t owner; uint64_t offset; unsigned int flags; int has_record; struct xfs_rmap_irec irec; int error; xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); ASSERT(XFS_RMAP_NON_INODE_OWNER(owner) || (flags & XFS_RMAP_BMBT_BLOCK)); error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &has_record); if (error) return error; if (!has_record) { *has_rmap = false; return 0; } error = xfs_rmap_get_rec(cur, &irec, &has_record); if (error) return error; if (!has_record) { *has_rmap = false; return 0; } *has_rmap = (irec.rm_owner == owner && irec.rm_startblock <= bno && irec.rm_startblock + irec.rm_blockcount >= bno + len); return 0; } struct xfs_rmap_key_state { uint64_t owner; uint64_t offset; unsigned int flags; bool has_rmap; }; /* For each rmap given, figure out if it doesn't match the key we want. */ STATIC int xfs_rmap_has_other_keys_helper( struct xfs_btree_cur *cur, struct xfs_rmap_irec *rec, void *priv) { struct xfs_rmap_key_state *rks = priv; if (rks->owner == rec->rm_owner && rks->offset == rec->rm_offset && ((rks->flags & rec->rm_flags) & XFS_RMAP_KEY_FLAGS) == rks->flags) return 0; rks->has_rmap = true; return XFS_BTREE_QUERY_RANGE_ABORT; } /* * Given an extent and some owner info, can we find records overlapping * the extent whose owner info does not match the given owner? */ int xfs_rmap_has_other_keys( struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, bool *has_rmap) { struct xfs_rmap_irec low = {0}; struct xfs_rmap_irec high; struct xfs_rmap_key_state rks; int error; xfs_owner_info_unpack(oinfo, &rks.owner, &rks.offset, &rks.flags); rks.has_rmap = false; low.rm_startblock = bno; memset(&high, 0xFF, sizeof(high)); high.rm_startblock = bno + len - 1; error = xfs_rmap_query_range(cur, &low, &high, xfs_rmap_has_other_keys_helper, &rks); *has_rmap = rks.has_rmap; return error; } const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = { .oi_owner = XFS_RMAP_OWN_NULL, }; const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER = { .oi_owner = XFS_RMAP_OWN_UNKNOWN, }; const struct xfs_owner_info XFS_RMAP_OINFO_FS = { .oi_owner = XFS_RMAP_OWN_FS, }; const struct xfs_owner_info XFS_RMAP_OINFO_LOG = { .oi_owner = XFS_RMAP_OWN_LOG, }; const struct xfs_owner_info XFS_RMAP_OINFO_AG = { .oi_owner = XFS_RMAP_OWN_AG, }; const struct xfs_owner_info XFS_RMAP_OINFO_INOBT = { .oi_owner = XFS_RMAP_OWN_INOBT, }; const struct xfs_owner_info XFS_RMAP_OINFO_INODES = { .oi_owner = XFS_RMAP_OWN_INODES, }; const struct xfs_owner_info XFS_RMAP_OINFO_REFC = { .oi_owner = XFS_RMAP_OWN_REFC, }; const struct xfs_owner_info XFS_RMAP_OINFO_COW = { .oi_owner = XFS_RMAP_OWN_COW, }; xfsprogs-5.3.0/libxfs/xfs_rmap.h0000644000175000017500000001514213466663244016544 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_RMAP_H__ #define __XFS_RMAP_H__ static inline void xfs_rmap_ino_bmbt_owner( struct xfs_owner_info *oi, xfs_ino_t ino, int whichfork) { oi->oi_owner = ino; oi->oi_offset = 0; oi->oi_flags = XFS_OWNER_INFO_BMBT_BLOCK; if (whichfork == XFS_ATTR_FORK) oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; } static inline void xfs_rmap_ino_owner( struct xfs_owner_info *oi, xfs_ino_t ino, int whichfork, xfs_fileoff_t offset) { oi->oi_owner = ino; oi->oi_offset = offset; oi->oi_flags = 0; if (whichfork == XFS_ATTR_FORK) oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; } static inline bool xfs_rmap_should_skip_owner_update( const struct xfs_owner_info *oi) { return oi->oi_owner == XFS_RMAP_OWN_NULL; } /* Reverse mapping functions. */ struct xfs_buf; static inline __u64 xfs_rmap_irec_offset_pack( const struct xfs_rmap_irec *irec) { __u64 x; x = XFS_RMAP_OFF(irec->rm_offset); if (irec->rm_flags & XFS_RMAP_ATTR_FORK) x |= XFS_RMAP_OFF_ATTR_FORK; if (irec->rm_flags & XFS_RMAP_BMBT_BLOCK) x |= XFS_RMAP_OFF_BMBT_BLOCK; if (irec->rm_flags & XFS_RMAP_UNWRITTEN) x |= XFS_RMAP_OFF_UNWRITTEN; return x; } static inline int xfs_rmap_irec_offset_unpack( __u64 offset, struct xfs_rmap_irec *irec) { if (offset & ~(XFS_RMAP_OFF_MASK | XFS_RMAP_OFF_FLAGS)) return -EFSCORRUPTED; irec->rm_offset = XFS_RMAP_OFF(offset); if (offset & XFS_RMAP_OFF_ATTR_FORK) irec->rm_flags |= XFS_RMAP_ATTR_FORK; if (offset & XFS_RMAP_OFF_BMBT_BLOCK) irec->rm_flags |= XFS_RMAP_BMBT_BLOCK; if (offset & XFS_RMAP_OFF_UNWRITTEN) irec->rm_flags |= XFS_RMAP_UNWRITTEN; return 0; } static inline void xfs_owner_info_unpack( const struct xfs_owner_info *oinfo, uint64_t *owner, uint64_t *offset, unsigned int *flags) { unsigned int r = 0; *owner = oinfo->oi_owner; *offset = oinfo->oi_offset; if (oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK) r |= XFS_RMAP_ATTR_FORK; if (oinfo->oi_flags & XFS_OWNER_INFO_BMBT_BLOCK) r |= XFS_RMAP_BMBT_BLOCK; *flags = r; } static inline void xfs_owner_info_pack( struct xfs_owner_info *oinfo, uint64_t owner, uint64_t offset, unsigned int flags) { oinfo->oi_owner = owner; oinfo->oi_offset = XFS_RMAP_OFF(offset); oinfo->oi_flags = 0; if (flags & XFS_RMAP_ATTR_FORK) oinfo->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; if (flags & XFS_RMAP_BMBT_BLOCK) oinfo->oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK; } int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo); int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo); int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags, int *stat); int xfs_rmap_lookup_eq(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags, int *stat); int xfs_rmap_insert(struct xfs_btree_cur *rcur, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags); int xfs_rmap_get_rec(struct xfs_btree_cur *cur, struct xfs_rmap_irec *irec, int *stat); typedef int (*xfs_rmap_query_range_fn)( struct xfs_btree_cur *cur, struct xfs_rmap_irec *rec, void *priv); int xfs_rmap_query_range(struct xfs_btree_cur *cur, struct xfs_rmap_irec *low_rec, struct xfs_rmap_irec *high_rec, xfs_rmap_query_range_fn fn, void *priv); int xfs_rmap_query_all(struct xfs_btree_cur *cur, xfs_rmap_query_range_fn fn, void *priv); enum xfs_rmap_intent_type { XFS_RMAP_MAP, XFS_RMAP_MAP_SHARED, XFS_RMAP_UNMAP, XFS_RMAP_UNMAP_SHARED, XFS_RMAP_CONVERT, XFS_RMAP_CONVERT_SHARED, XFS_RMAP_ALLOC, XFS_RMAP_FREE, }; struct xfs_rmap_intent { struct list_head ri_list; enum xfs_rmap_intent_type ri_type; uint64_t ri_owner; int ri_whichfork; struct xfs_bmbt_irec ri_bmap; }; /* functions for updating the rmapbt based on bmbt map/unmap operations */ int xfs_rmap_map_extent(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *imap); int xfs_rmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *imap); int xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *imap); int xfs_rmap_alloc_extent(struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner); int xfs_rmap_free_extent(struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner); void xfs_rmap_finish_one_cleanup(struct xfs_trans *tp, struct xfs_btree_cur *rcur, int error); int xfs_rmap_finish_one(struct xfs_trans *tp, enum xfs_rmap_intent_type type, uint64_t owner, int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock, xfs_filblks_t blockcount, xfs_exntst_t state, struct xfs_btree_cur **pcur); int xfs_rmap_find_left_neighbor(struct xfs_btree_cur *cur, xfs_agblock_t bno, uint64_t owner, uint64_t offset, unsigned int flags, struct xfs_rmap_irec *irec, int *stat); int xfs_rmap_lookup_le_range(struct xfs_btree_cur *cur, xfs_agblock_t bno, uint64_t owner, uint64_t offset, unsigned int flags, struct xfs_rmap_irec *irec, int *stat); int xfs_rmap_compare(const struct xfs_rmap_irec *a, const struct xfs_rmap_irec *b); union xfs_btree_rec; int xfs_rmap_btrec_to_irec(union xfs_btree_rec *rec, struct xfs_rmap_irec *irec); int xfs_rmap_has_record(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, bool *exists); int xfs_rmap_record_exists(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, bool *has_rmap); int xfs_rmap_has_other_keys(struct xfs_btree_cur *cur, xfs_agblock_t bno, xfs_extlen_t len, const struct xfs_owner_info *oinfo, bool *has_rmap); int xfs_rmap_map_raw(struct xfs_btree_cur *cur, struct xfs_rmap_irec *rmap); extern const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE; extern const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER; extern const struct xfs_owner_info XFS_RMAP_OINFO_FS; extern const struct xfs_owner_info XFS_RMAP_OINFO_LOG; extern const struct xfs_owner_info XFS_RMAP_OINFO_AG; extern const struct xfs_owner_info XFS_RMAP_OINFO_INOBT; extern const struct xfs_owner_info XFS_RMAP_OINFO_INODES; extern const struct xfs_owner_info XFS_RMAP_OINFO_REFC; extern const struct xfs_owner_info XFS_RMAP_OINFO_COW; #endif /* __XFS_RMAP_H__ */ xfsprogs-5.3.0/libxfs/xfs_rmap_btree.c0000644000175000017500000003575413570057155017725 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_btree.h" #include "xfs_rmap.h" #include "xfs_rmap_btree.h" #include "xfs_trace.h" #include "xfs_ag_resv.h" /* * Reverse map btree. * * This is a per-ag tree used to track the owner(s) of a given extent. With * reflink it is possible for there to be multiple owners, which is a departure * from classic XFS. Owner records for data extents are inserted when the * extent is mapped and removed when an extent is unmapped. Owner records for * all other block types (i.e. metadata) are inserted when an extent is * allocated and removed when an extent is freed. There can only be one owner * of a metadata extent, usually an inode or some other metadata structure like * an AG btree. * * The rmap btree is part of the free space management, so blocks for the tree * are sourced from the agfl. Hence we need transaction reservation support for * this tree so that the freelist is always large enough. This also impacts on * the minimum space we need to leave free in the AG. * * The tree is ordered by [ag block, owner, offset]. This is a large key size, * but it is the only way to enforce unique keys when a block can be owned by * multiple files at any offset. There's no need to order/search by extent * size for online updating/management of the tree. It is intended that most * reverse lookups will be to find the owner(s) of a particular block, or to * try to recover tree and file data from corrupt primary metadata. */ static struct xfs_btree_cur * xfs_rmapbt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agbp, cur->bc_private.a.agno); } STATIC void xfs_rmapbt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int inc) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int btnum = cur->bc_btnum; struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); ASSERT(ptr->s != 0); agf->agf_roots[btnum] = ptr->s; be32_add_cpu(&agf->agf_levels[btnum], inc); pag->pagf_levels[btnum] += inc; xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); } STATIC int xfs_rmapbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); int error; xfs_agblock_t bno; /* Allocate the new block from the freelist. If we can't, give up. */ error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, &bno, 1); if (error) return error; trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno, bno, 1); if (bno == NULLAGBLOCK) { *stat = 0; return 0; } xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false); xfs_trans_agbtree_delta(cur->bc_tp, 1); new->s = cpu_to_be32(bno); be32_add_cpu(&agf->agf_rmap_blocks, 1); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_private.a.agno); *stat = 1; return 0; } STATIC int xfs_rmapbt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agblock_t bno; int error; bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_private.a.agno, bno, 1); be32_add_cpu(&agf->agf_rmap_blocks, -1); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); if (error) return error; xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, XFS_EXTENT_BUSY_SKIP_DISCARD); xfs_trans_agbtree_delta(cur->bc_tp, -1); xfs_ag_resv_rmapbt_free(cur->bc_mp, cur->bc_private.a.agno); return 0; } STATIC int xfs_rmapbt_get_minrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_rmap_mnr[level != 0]; } STATIC int xfs_rmapbt_get_maxrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_rmap_mxr[level != 0]; } STATIC void xfs_rmapbt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->rmap.rm_startblock = rec->rmap.rm_startblock; key->rmap.rm_owner = rec->rmap.rm_owner; key->rmap.rm_offset = rec->rmap.rm_offset; } /* * The high key for a reverse mapping record can be computed by shifting * the startblock and offset to the highest value that would still map * to that record. In practice this means that we add blockcount-1 to * the startblock for all records, and if the record is for a data/attr * fork mapping, we add blockcount-1 to the offset too. */ STATIC void xfs_rmapbt_init_high_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { uint64_t off; int adj; adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1; key->rmap.rm_startblock = rec->rmap.rm_startblock; be32_add_cpu(&key->rmap.rm_startblock, adj); key->rmap.rm_owner = rec->rmap.rm_owner; key->rmap.rm_offset = rec->rmap.rm_offset; if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) || XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset))) return; off = be64_to_cpu(key->rmap.rm_offset); off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK); key->rmap.rm_offset = cpu_to_be64(off); } STATIC void xfs_rmapbt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock); rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount); rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner); rec->rmap.rm_offset = cpu_to_be64( xfs_rmap_irec_offset_pack(&cur->bc_rec.r)); } STATIC void xfs_rmapbt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); ptr->s = agf->agf_roots[cur->bc_btnum]; } STATIC int64_t xfs_rmapbt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { struct xfs_rmap_irec *rec = &cur->bc_rec.r; struct xfs_rmap_key *kp = &key->rmap; __u64 x, y; int64_t d; d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock; if (d) return d; x = be64_to_cpu(kp->rm_owner); y = rec->rm_owner; if (x > y) return 1; else if (y > x) return -1; x = XFS_RMAP_OFF(be64_to_cpu(kp->rm_offset)); y = rec->rm_offset; if (x > y) return 1; else if (y > x) return -1; return 0; } STATIC int64_t xfs_rmapbt_diff_two_keys( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { struct xfs_rmap_key *kp1 = &k1->rmap; struct xfs_rmap_key *kp2 = &k2->rmap; int64_t d; __u64 x, y; d = (int64_t)be32_to_cpu(kp1->rm_startblock) - be32_to_cpu(kp2->rm_startblock); if (d) return d; x = be64_to_cpu(kp1->rm_owner); y = be64_to_cpu(kp2->rm_owner); if (x > y) return 1; else if (y > x) return -1; x = XFS_RMAP_OFF(be64_to_cpu(kp1->rm_offset)); y = XFS_RMAP_OFF(be64_to_cpu(kp2->rm_offset)); if (x > y) return 1; else if (y > x) return -1; return 0; } static xfs_failaddr_t xfs_rmapbt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_perag *pag = bp->b_pag; xfs_failaddr_t fa; unsigned int level; /* * magic number and level verification * * During growfs operations, we can't verify the exact level or owner as * the perag is not fully initialised and hence not attached to the * buffer. In this case, check against the maximum tree depth. * * Similarly, during log recovery we will have a perag structure * attached, but the agf information will not yet have been initialised * from the on disk AGF. Again, we can only check against maximum limits * in this case. */ if (!xfs_verify_magic(bp, block->bb_magic)) return __this_address; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return __this_address; fa = xfs_btree_sblock_v5hdr_verify(bp); if (fa) return fa; level = be16_to_cpu(block->bb_level); if (pag && pag->pagf_init) { if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi]) return __this_address; } else if (level >= mp->m_rmap_maxlevels) return __this_address; return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]); } static void xfs_rmapbt_read_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; if (!xfs_btree_sblock_verify_crc(bp)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_rmapbt_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } if (bp->b_error) trace_xfs_btree_corrupt(bp, _RET_IP_); } static void xfs_rmapbt_write_verify( struct xfs_buf *bp) { xfs_failaddr_t fa; fa = xfs_rmapbt_verify(bp); if (fa) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } xfs_btree_sblock_calc_crc(bp); } const struct xfs_buf_ops xfs_rmapbt_buf_ops = { .name = "xfs_rmapbt", .magic = { 0, cpu_to_be32(XFS_RMAP_CRC_MAGIC) }, .verify_read = xfs_rmapbt_read_verify, .verify_write = xfs_rmapbt_write_verify, .verify_struct = xfs_rmapbt_verify, }; STATIC int xfs_rmapbt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { uint32_t x; uint32_t y; uint64_t a; uint64_t b; x = be32_to_cpu(k1->rmap.rm_startblock); y = be32_to_cpu(k2->rmap.rm_startblock); if (x < y) return 1; else if (x > y) return 0; a = be64_to_cpu(k1->rmap.rm_owner); b = be64_to_cpu(k2->rmap.rm_owner); if (a < b) return 1; else if (a > b) return 0; a = XFS_RMAP_OFF(be64_to_cpu(k1->rmap.rm_offset)); b = XFS_RMAP_OFF(be64_to_cpu(k2->rmap.rm_offset)); if (a <= b) return 1; return 0; } STATIC int xfs_rmapbt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { uint32_t x; uint32_t y; uint64_t a; uint64_t b; x = be32_to_cpu(r1->rmap.rm_startblock); y = be32_to_cpu(r2->rmap.rm_startblock); if (x < y) return 1; else if (x > y) return 0; a = be64_to_cpu(r1->rmap.rm_owner); b = be64_to_cpu(r2->rmap.rm_owner); if (a < b) return 1; else if (a > b) return 0; a = XFS_RMAP_OFF(be64_to_cpu(r1->rmap.rm_offset)); b = XFS_RMAP_OFF(be64_to_cpu(r2->rmap.rm_offset)); if (a <= b) return 1; return 0; } static const struct xfs_btree_ops xfs_rmapbt_ops = { .rec_len = sizeof(struct xfs_rmap_rec), .key_len = 2 * sizeof(struct xfs_rmap_key), .dup_cursor = xfs_rmapbt_dup_cursor, .set_root = xfs_rmapbt_set_root, .alloc_block = xfs_rmapbt_alloc_block, .free_block = xfs_rmapbt_free_block, .get_minrecs = xfs_rmapbt_get_minrecs, .get_maxrecs = xfs_rmapbt_get_maxrecs, .init_key_from_rec = xfs_rmapbt_init_key_from_rec, .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec, .init_rec_from_cur = xfs_rmapbt_init_rec_from_cur, .init_ptr_from_cur = xfs_rmapbt_init_ptr_from_cur, .key_diff = xfs_rmapbt_key_diff, .buf_ops = &xfs_rmapbt_buf_ops, .diff_two_keys = xfs_rmapbt_diff_two_keys, .keys_inorder = xfs_rmapbt_keys_inorder, .recs_inorder = xfs_rmapbt_recs_inorder, }; /* * Allocate a new allocation btree cursor. */ struct xfs_btree_cur * xfs_rmapbt_init_cursor( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno) { struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); struct xfs_btree_cur *cur; cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); cur->bc_tp = tp; cur->bc_mp = mp; /* Overlapping btree; 2 keys per pointer. */ cur->bc_btnum = XFS_BTNUM_RMAP; cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING; cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_ops = &xfs_rmapbt_ops; cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2); cur->bc_private.a.agbp = agbp; cur->bc_private.a.agno = agno; return cur; } /* * Calculate number of records in an rmap btree block. */ int xfs_rmapbt_maxrecs( int blocklen, int leaf) { blocklen -= XFS_RMAP_BLOCK_LEN; if (leaf) return blocklen / sizeof(struct xfs_rmap_rec); return blocklen / (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t)); } /* Compute the maximum height of an rmap btree. */ void xfs_rmapbt_compute_maxlevels( struct xfs_mount *mp) { /* * On a non-reflink filesystem, the maximum number of rmap * records is the number of blocks in the AG, hence the max * rmapbt height is log_$maxrecs($agblocks). However, with * reflink each AG block can have up to 2^32 (per the refcount * record format) owners, which means that theoretically we * could face up to 2^64 rmap records. * * That effectively means that the max rmapbt height must be * XFS_BTREE_MAXLEVELS. "Fortunately" we'll run out of AG * blocks to feed the rmapbt long before the rmapbt reaches * maximum height. The reflink code uses ag_resv_critical to * disallow reflinking when less than 10% of the per-AG metadata * block reservation since the fallback is a regular file copy. */ if (xfs_sb_version_hasreflink(&mp->m_sb)) mp->m_rmap_maxlevels = XFS_BTREE_MAXLEVELS; else mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels( mp->m_rmap_mnr, mp->m_sb.sb_agblocks); } /* Calculate the refcount btree size for some records. */ xfs_extlen_t xfs_rmapbt_calc_size( struct xfs_mount *mp, unsigned long long len) { return xfs_btree_calc_size(mp->m_rmap_mnr, len); } /* * Calculate the maximum refcount btree size. */ xfs_extlen_t xfs_rmapbt_max_size( struct xfs_mount *mp, xfs_agblock_t agblocks) { /* Bail out if we're uninitialized, which can happen in mkfs. */ if (mp->m_rmap_mxr[0] == 0) return 0; return xfs_rmapbt_calc_size(mp, agblocks); } /* * Figure out how many blocks to reserve and how many are used by this btree. */ int xfs_rmapbt_calc_reserves( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used) { struct xfs_buf *agbp; struct xfs_agf *agf; xfs_agblock_t agblocks; xfs_extlen_t tree_len; int error; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 0; error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); if (error) return error; agf = XFS_BUF_TO_AGF(agbp); agblocks = be32_to_cpu(agf->agf_length); tree_len = be32_to_cpu(agf->agf_rmap_blocks); xfs_trans_brelse(tp, agbp); /* * The log is permanently allocated, so the space it occupies will * never be available for the kinds of things that would require btree * expansion. We therefore can pretend the space isn't there. */ if (mp->m_sb.sb_logstart && XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno) agblocks -= mp->m_sb.sb_logblocks; /* Reserve 1% of the AG or enough for 1 block per record. */ *ask += max(agblocks / 100, xfs_rmapbt_max_size(mp, agblocks)); *used += tree_len; return error; } xfsprogs-5.3.0/libxfs/xfs_rmap_btree.h0000644000175000017500000000345613435336036017722 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_RMAP_BTREE_H__ #define __XFS_RMAP_BTREE_H__ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; /* rmaps only exist on crc enabled filesystems */ #define XFS_RMAP_BLOCK_LEN XFS_BTREE_SBLOCK_CRC_LEN /* * Record, key, and pointer address macros for btree blocks. * * (note that some of these may appear unused, but they are used in userspace) */ #define XFS_RMAP_REC_ADDR(block, index) \ ((struct xfs_rmap_rec *) \ ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ (((index) - 1) * sizeof(struct xfs_rmap_rec)))) #define XFS_RMAP_KEY_ADDR(block, index) \ ((struct xfs_rmap_key *) \ ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ ((index) - 1) * 2 * sizeof(struct xfs_rmap_key))) #define XFS_RMAP_HIGH_KEY_ADDR(block, index) \ ((struct xfs_rmap_key *) \ ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ sizeof(struct xfs_rmap_key) + \ ((index) - 1) * 2 * sizeof(struct xfs_rmap_key))) #define XFS_RMAP_PTR_ADDR(block, index, maxrecs) \ ((xfs_rmap_ptr_t *) \ ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ (maxrecs) * 2 * sizeof(struct xfs_rmap_key) + \ ((index) - 1) * sizeof(xfs_rmap_ptr_t))) struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *bp, xfs_agnumber_t agno); int xfs_rmapbt_maxrecs(int blocklen, int leaf); extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp); extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp, unsigned long long len); extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp, xfs_agblock_t agblocks); extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); #endif /* __XFS_RMAP_BTREE_H__ */ xfsprogs-5.3.0/libxfs/xfs_rtbitmap.c0000644000175000017500000006540113570057155017417 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_bmap.h" #include "xfs_trans.h" /* * Realtime allocator bitmap functions shared with userspace. */ /* * Real time buffers need verifiers to avoid runtime warnings during IO. * We don't have anything to verify, however, so these are just dummy * operations. */ static void xfs_rtbuf_verify_read( struct xfs_buf *bp) { return; } static void xfs_rtbuf_verify_write( struct xfs_buf *bp) { return; } const struct xfs_buf_ops xfs_rtbuf_ops = { .name = "rtbuf", .verify_read = xfs_rtbuf_verify_read, .verify_write = xfs_rtbuf_verify_write, }; /* * Get a buffer for the bitmap or summary file block specified. * The buffer is returned read and locked. */ int xfs_rtbuf_get( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t block, /* block number in bitmap or summary */ int issum, /* is summary not bitmap */ xfs_buf_t **bpp) /* output: buffer for the block */ { xfs_buf_t *bp; /* block buffer, result */ xfs_inode_t *ip; /* bitmap or summary inode */ xfs_bmbt_irec_t map; int nmap = 1; int error; /* error value */ ip = issum ? mp->m_rsumip : mp->m_rbmip; error = xfs_bmapi_read(ip, block, 1, &map, &nmap, XFS_DATA_FORK); if (error) return error; if (nmap == 0 || !xfs_bmap_is_real_extent(&map)) return -EFSCORRUPTED; ASSERT(map.br_startblock != NULLFSBLOCK); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, map.br_startblock), mp->m_bsize, 0, &bp, &xfs_rtbuf_ops); if (error) return error; xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF : XFS_BLFT_RTBITMAP_BUF); *bpp = bp; return 0; } /* * Searching backward from start to limit, find the first block whose * allocated/free state is different from start's. */ int xfs_rtfind_back( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to look at */ xfs_rtblock_t limit, /* last block to look at */ xfs_rtblock_t *rtblock) /* out: start block found */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t firstbit; /* first useful bit in the word */ xfs_rtblock_t i; /* current bit number rel. to start */ xfs_rtblock_t len; /* length of inspected area */ xfs_rtword_t mask; /* mask of relevant bits for value */ xfs_rtword_t want; /* mask for "good" values */ xfs_rtword_t wdiff; /* difference from wanted value */ int word; /* word number in the buffer */ /* * Compute and read in starting bitmap block for starting block. */ block = XFS_BITTOBLOCK(mp, start); error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Get the first word's index & point to it. */ word = XFS_BITTOWORD(mp, start); b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); len = start - limit + 1; /* * Compute match value, based on the bit at start: if 1 (free) * then all-ones, else all-zeroes. */ want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; /* * If the starting position is not word-aligned, deal with the * partial word. */ if (bit < XFS_NBWORD - 1) { /* * Calculate first (leftmost) bit number to look at, * and mask for all the relevant bits in this word. */ firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << firstbit; /* * Calculate the difference between the value there * and what we're looking for. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different. Mark where we are and return. */ xfs_trans_brelse(tp, bp); i = bit - XFS_RTHIBIT(wdiff); *rtblock = start - i + 1; return 0; } i = bit - firstbit + 1; /* * Go on to previous block if that's where the previous word is * and we need the previous word. */ if (--word == -1 && i < len) { /* * If done with this block, get the previous one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; word = XFS_BLOCKWMASK(mp); b = &bufp[word]; } else { /* * Go on to the previous word in the buffer. */ b--; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the previous one. */ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value. */ if ((wdiff = *b ^ want)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); *rtblock = start - i + 1; return 0; } i += XFS_NBWORD; /* * Go on to previous block if that's where the previous word is * and we need the previous word. */ if (--word == -1 && i < len) { /* * If done with this block, get the previous one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; word = XFS_BLOCKWMASK(mp); b = &bufp[word]; } else { /* * Go on to the previous word in the buffer. */ b--; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if (len - i) { /* * Calculate first (leftmost) bit number to look at, * and mask for all the relevant bits in this word. */ firstbit = XFS_NBWORD - (len - i); mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); *rtblock = start - i + 1; return 0; } else i = len; } /* * No match, return that we scanned the whole area. */ xfs_trans_brelse(tp, bp); *rtblock = start - i + 1; return 0; } /* * Searching forward from start to limit, find the first block whose * allocated/free state is different from start's. */ int xfs_rtfind_forw( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to look at */ xfs_rtblock_t limit, /* last block to look at */ xfs_rtblock_t *rtblock) /* out: start block found */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t i; /* current bit number rel. to start */ xfs_rtblock_t lastbit; /* last useful bit in the word */ xfs_rtblock_t len; /* length of inspected area */ xfs_rtword_t mask; /* mask of relevant bits for value */ xfs_rtword_t want; /* mask for "good" values */ xfs_rtword_t wdiff; /* difference from wanted value */ int word; /* word number in the buffer */ /* * Compute and read in starting bitmap block for starting block. */ block = XFS_BITTOBLOCK(mp, start); error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Get the first word's index & point to it. */ word = XFS_BITTOWORD(mp, start); b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); len = limit - start + 1; /* * Compute match value, based on the bit at start: if 1 (free) * then all-ones, else all-zeroes. */ want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; /* * If the starting position is not word-aligned, deal with the * partial word. */ if (bit) { /* * Calculate last (rightmost) bit number to look at, * and mask for all the relevant bits in this word. */ lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Calculate the difference between the value there * and what we're looking for. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different. Mark where we are and return. */ xfs_trans_brelse(tp, bp); i = XFS_RTLOBIT(wdiff) - bit; *rtblock = start + i - 1; return 0; } i = lastbit - bit; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the previous one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the previous word in the buffer. */ b++; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one. */ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value. */ if ((wdiff = *b ^ want)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *rtblock = start + i - 1; return 0; } i += XFS_NBWORD; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the next one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer. */ b++; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if ((lastbit = len - i)) { /* * Calculate mask for all the relevant bits in this word. */ mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *rtblock = start + i - 1; return 0; } else i = len; } /* * No match, return that we scanned the whole area. */ xfs_trans_brelse(tp, bp); *rtblock = start + i - 1; return 0; } /* * Read and/or modify the summary information for a given extent size, * bitmap block combination. * Keeps track of a current summary block, so we don't keep reading * it from the buffer cache. * * Summary information is returned in *sum if specified. * If no delta is specified, returns summary only. */ int xfs_rtmodify_summary_int( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ int delta, /* change to make to summary info */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_suminfo_t *sum) /* out: summary info for this block */ { xfs_buf_t *bp; /* buffer for the summary block */ int error; /* error value */ xfs_fsblock_t sb; /* summary fsblock */ int so; /* index into the summary file */ xfs_suminfo_t *sp; /* pointer to returned data */ /* * Compute entry number in the summary file. */ so = XFS_SUMOFFS(mp, log, bbno); /* * Compute the block number in the summary file. */ sb = XFS_SUMOFFSTOBLOCK(mp, so); /* * If we have an old buffer, and the block number matches, use that. */ if (*rbpp && *rsb == sb) bp = *rbpp; /* * Otherwise we have to get the buffer. */ else { /* * If there was an old one, get rid of it first. */ if (*rbpp) xfs_trans_brelse(tp, *rbpp); error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); if (error) { return error; } /* * Remember this buffer and block for the next call. */ *rbpp = bp; *rsb = sb; } /* * Point to the summary information, modify/log it, and/or copy it out. */ sp = XFS_SUMPTR(mp, bp, so); if (delta) { uint first = (uint)((char *)sp - (char *)bp->b_addr); *sp += delta; if (mp->m_rsum_cache) { if (*sp == 0 && log == mp->m_rsum_cache[bbno]) mp->m_rsum_cache[bbno]++; if (*sp != 0 && log < mp->m_rsum_cache[bbno]) mp->m_rsum_cache[bbno] = log; } xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1); } if (sum) *sum = *sp; return 0; } int xfs_rtmodify_summary( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ int delta, /* change to make to summary info */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { return xfs_rtmodify_summary_int(mp, tp, log, bbno, delta, rbpp, rsb, NULL); } /* * Set the given range of bitmap bits to the given value. * Do whatever I/O and logging is required. */ int xfs_rtmodify_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to modify */ xfs_extlen_t len, /* length of extent to modify */ int val) /* 1 for free, 0 for allocated */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtword_t *first; /* first used word in the buffer */ int i; /* current bit number rel. to start */ int lastbit; /* last useful bit in word */ xfs_rtword_t mask; /* mask o frelevant bits for value */ int word; /* word number in the buffer */ /* * Compute starting bitmap block number. */ block = XFS_BITTOBLOCK(mp, start); /* * Read the bitmap block, and point to its data. */ error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Compute the starting word's address, and starting bit. */ word = XFS_BITTOWORD(mp, start); first = b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); /* * 0 (allocated) => all zeroes; 1 (free) => all ones. */ val = -val; /* * If not starting on a word boundary, deal with the first * (partial) word. */ if (bit) { /* * Compute first bit not changed and mask of relevant bits. */ lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Set/clear the active bits. */ if (val) *b |= mask; else *b &= ~mask; i = lastbit - bit; /* * Go on to the next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * Log the changed part of this block. * Get the next one. */ xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), (uint)((char *)b - (char *)bufp)); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } first = b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer */ b++; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one. */ while (len - i >= XFS_NBWORD) { /* * Set the word value correctly. */ *b = val; i += XFS_NBWORD; /* * Go on to the next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * Log the changed part of this block. * Get the next one. */ xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), (uint)((char *)b - (char *)bufp)); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } first = b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer */ b++; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if ((lastbit = len - i)) { /* * Compute a mask of relevant bits. */ mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Set/clear the active bits. */ if (val) *b |= mask; else *b &= ~mask; b++; } /* * Log any remaining changed bytes. */ if (b > first) xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), (uint)((char *)b - (char *)bufp - 1)); return 0; } /* * Mark an extent specified by start and len freed. * Updates all the summary information as well as the bitmap. */ int xfs_rtfree_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to free */ xfs_extlen_t len, /* length to free */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { xfs_rtblock_t end; /* end of the freed extent */ int error; /* error value */ xfs_rtblock_t postblock; /* first block freed > end */ xfs_rtblock_t preblock; /* first block freed < start */ end = start + len - 1; /* * Modify the bitmap to mark this extent freed. */ error = xfs_rtmodify_range(mp, tp, start, len, 1); if (error) { return error; } /* * Assume we're freeing out of the middle of an allocated extent. * We need to find the beginning and end of the extent so we can * properly update the summary. */ error = xfs_rtfind_back(mp, tp, start, 0, &preblock); if (error) { return error; } /* * Find the next allocated block (end of allocated extent). */ error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, &postblock); if (error) return error; /* * If there are blocks not being freed at the front of the * old extent, add summary data for them to be allocated. */ if (preblock < start) { error = xfs_rtmodify_summary(mp, tp, XFS_RTBLOCKLOG(start - preblock), XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); if (error) { return error; } } /* * If there are blocks not being freed at the end of the * old extent, add summary data for them to be allocated. */ if (postblock > end) { error = xfs_rtmodify_summary(mp, tp, XFS_RTBLOCKLOG(postblock - end), XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); if (error) { return error; } } /* * Increment the summary information corresponding to the entire * (new) free extent. */ error = xfs_rtmodify_summary(mp, tp, XFS_RTBLOCKLOG(postblock + 1 - preblock), XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); return error; } /* * Check that the given range is either all allocated (val = 0) or * all free (val = 1). */ int xfs_rtcheck_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block number of extent */ xfs_extlen_t len, /* length of extent */ int val, /* 1 for free, 0 for allocated */ xfs_rtblock_t *new, /* out: first block not matching */ int *stat) /* out: 1 for matches, 0 for not */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t i; /* current bit number rel. to start */ xfs_rtblock_t lastbit; /* last useful bit in word */ xfs_rtword_t mask; /* mask of relevant bits for value */ xfs_rtword_t wdiff; /* difference from wanted value */ int word; /* word number in the buffer */ /* * Compute starting bitmap block number */ block = XFS_BITTOBLOCK(mp, start); /* * Read the bitmap block. */ error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Compute the starting word's address, and starting bit. */ word = XFS_BITTOWORD(mp, start); b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); /* * 0 (allocated) => all zero's; 1 (free) => all one's. */ val = -val; /* * If not starting on a word boundary, deal with the first * (partial) word. */ if (bit) { /* * Compute first bit not examined. */ lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); /* * Mask of relevant bits. */ mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ val) & mask)) { /* * Different, compute first wrong bit and return. */ xfs_trans_brelse(tp, bp); i = XFS_RTLOBIT(wdiff) - bit; *new = start + i; *stat = 0; return 0; } i = lastbit - bit; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the next one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer. */ b++; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one. */ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value. */ if ((wdiff = *b ^ val)) { /* * Different, compute first wrong bit and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *new = start + i; *stat = 0; return 0; } i += XFS_NBWORD; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the next one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer. */ b++; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if ((lastbit = len - i)) { /* * Mask of relevant bits. */ mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ val) & mask)) { /* * Different, compute first wrong bit and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *new = start + i; *stat = 0; return 0; } else i = len; } /* * Successful, return. */ xfs_trans_brelse(tp, bp); *new = start + i; *stat = 1; return 0; } #ifdef DEBUG /* * Check that the given extent (block range) is allocated already. */ STATIC int /* error */ xfs_rtcheck_alloc_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number of extent */ xfs_extlen_t len) /* length of extent */ { xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ int stat; int error; error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat); if (error) return error; ASSERT(stat); return 0; } #else #define xfs_rtcheck_alloc_range(m,t,b,l) (0) #endif /* * Free an extent in the realtime subvolume. Length is expressed in * realtime extents, as is the block number. */ int /* error */ xfs_rtfree_extent( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number to free */ xfs_extlen_t len) /* length of extent freed */ { int error; /* error value */ xfs_mount_t *mp; /* file system mount structure */ xfs_fsblock_t sb; /* summary file block number */ xfs_buf_t *sumbp = NULL; /* summary file block buffer */ mp = tp->t_mountp; ASSERT(mp->m_rbmip->i_itemp != NULL); ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL)); error = xfs_rtcheck_alloc_range(mp, tp, bno, len); if (error) return error; /* * Free the range of realtime blocks. */ error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); if (error) { return error; } /* * Mark more blocks free in the superblock. */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); /* * If we've now freed all the blocks, reset the file sequence * number to 0. */ if (tp->t_frextents_delta + mp->m_sb.sb_frextents == mp->m_sb.sb_rextents) { if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; *(uint64_t *)&VFS_I(mp->m_rbmip)->i_atime = 0; xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); } return 0; } /* Find all the free records within a given range. */ int xfs_rtalloc_query_range( struct xfs_trans *tp, struct xfs_rtalloc_rec *low_rec, struct xfs_rtalloc_rec *high_rec, xfs_rtalloc_query_range_fn fn, void *priv) { struct xfs_rtalloc_rec rec; struct xfs_mount *mp = tp->t_mountp; xfs_rtblock_t rtstart; xfs_rtblock_t rtend; xfs_rtblock_t rem; int is_free; int error = 0; if (low_rec->ar_startext > high_rec->ar_startext) return -EINVAL; if (low_rec->ar_startext >= mp->m_sb.sb_rextents || low_rec->ar_startext == high_rec->ar_startext) return 0; if (high_rec->ar_startext > mp->m_sb.sb_rextents) high_rec->ar_startext = mp->m_sb.sb_rextents; /* Iterate the bitmap, looking for discrepancies. */ rtstart = low_rec->ar_startext; rem = high_rec->ar_startext - rtstart; while (rem) { /* Is the first block free? */ error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend, &is_free); if (error) break; /* How long does the extent go for? */ error = xfs_rtfind_forw(mp, tp, rtstart, high_rec->ar_startext - 1, &rtend); if (error) break; if (is_free) { rec.ar_startext = rtstart; rec.ar_extcount = rtend - rtstart + 1; error = fn(tp, &rec, priv); if (error) break; } rem -= rtend - rtstart + 1; rtstart = rtend + 1; } return error; } /* Find all the free records. */ int xfs_rtalloc_query_all( struct xfs_trans *tp, xfs_rtalloc_query_range_fn fn, void *priv) { struct xfs_rtalloc_rec keys[2]; keys[0].ar_startext = 0; keys[1].ar_startext = tp->t_mountp->m_sb.sb_rextents - 1; keys[0].ar_extcount = keys[1].ar_extcount = 0; return xfs_rtalloc_query_range(tp, &keys[0], &keys[1], fn, priv); } /* Is the given extent all free? */ int xfs_rtalloc_extent_is_free( struct xfs_mount *mp, struct xfs_trans *tp, xfs_rtblock_t start, xfs_extlen_t len, bool *is_free) { xfs_rtblock_t end; int matches; int error; error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches); if (error) return error; *is_free = matches; return 0; } xfsprogs-5.3.0/libxfs/xfs_sb.c0000644000175000017500000010571613570057155016205 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_ialloc.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_bmap_btree.h" #include "xfs_alloc_btree.h" #include "xfs_rmap_btree.h" #include "xfs_refcount_btree.h" #include "xfs_da_format.h" #include "xfs_health.h" /* * Physical superblock buffer manipulations. Shared with libxfs in userspace. */ /* * Reference counting access wrappers to the perag structures. * Because we never free per-ag structures, the only thing we * have to protect against changes is the tree structure itself. */ struct xfs_perag * xfs_perag_get( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_perag *pag; int ref = 0; rcu_read_lock(); pag = radix_tree_lookup(&mp->m_perag_tree, agno); if (pag) { ASSERT(atomic_read(&pag->pag_ref) >= 0); ref = atomic_inc_return(&pag->pag_ref); } rcu_read_unlock(); trace_xfs_perag_get(mp, agno, ref, _RET_IP_); return pag; } /* * search from @first to find the next perag with the given tag set. */ struct xfs_perag * xfs_perag_get_tag( struct xfs_mount *mp, xfs_agnumber_t first, int tag) { struct xfs_perag *pag; int found; int ref; rcu_read_lock(); found = radix_tree_gang_lookup_tag(&mp->m_perag_tree, (void **)&pag, first, 1, tag); if (found <= 0) { rcu_read_unlock(); return NULL; } ref = atomic_inc_return(&pag->pag_ref); rcu_read_unlock(); trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_); return pag; } void xfs_perag_put( struct xfs_perag *pag) { int ref; ASSERT(atomic_read(&pag->pag_ref) > 0); ref = atomic_dec_return(&pag->pag_ref); trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_); } /* Check all the superblock fields we care about when reading one in. */ STATIC int xfs_validate_sb_read( struct xfs_mount *mp, struct xfs_sb *sbp) { if (XFS_SB_VERSION_NUM(sbp) != XFS_SB_VERSION_5) return 0; /* * Version 5 superblock feature mask validation. Reject combinations * the kernel cannot support up front before checking anything else. */ if (xfs_sb_has_compat_feature(sbp, XFS_SB_FEAT_COMPAT_UNKNOWN)) { xfs_warn(mp, "Superblock has unknown compatible features (0x%x) enabled.", (sbp->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN)); xfs_warn(mp, "Using a more recent kernel is recommended."); } if (xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { xfs_alert(mp, "Superblock has unknown read-only compatible features (0x%x) enabled.", (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { xfs_warn(mp, "Attempted to mount read-only compatible filesystem read-write."); xfs_warn(mp, "Filesystem can only be safely mounted read only."); return -EINVAL; } } if (xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { xfs_warn(mp, "Superblock has unknown incompatible features (0x%x) enabled.", (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN)); xfs_warn(mp, "Filesystem cannot be safely mounted by this kernel."); return -EINVAL; } return 0; } /* Check all the superblock fields we care about when writing one out. */ STATIC int xfs_validate_sb_write( struct xfs_mount *mp, struct xfs_buf *bp, struct xfs_sb *sbp) { /* * Carry out additional sb summary counter sanity checks when we write * the superblock. We skip this in the read validator because there * could be newer superblocks in the log and if the values are garbage * even after replay we'll recalculate them at the end of log mount. * * mkfs has traditionally written zeroed counters to inprogress and * secondary superblocks, so allow this usage to continue because * we never read counters from such superblocks. */ if (XFS_BUF_ADDR(bp) == XFS_SB_DADDR && !sbp->sb_inprogress && (sbp->sb_fdblocks > sbp->sb_dblocks || !xfs_verify_icount(mp, sbp->sb_icount) || sbp->sb_ifree > sbp->sb_icount)) { xfs_warn(mp, "SB summary counter sanity check failed"); return -EFSCORRUPTED; } if (XFS_SB_VERSION_NUM(sbp) != XFS_SB_VERSION_5) return 0; /* * Version 5 superblock feature mask validation. Reject combinations * the kernel cannot support since we checked for unsupported bits in * the read verifier, which means that memory is corrupt. */ if (xfs_sb_has_compat_feature(sbp, XFS_SB_FEAT_COMPAT_UNKNOWN)) { xfs_warn(mp, "Corruption detected in superblock compatible features (0x%x)!", (sbp->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN)); return -EFSCORRUPTED; } if (xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { xfs_alert(mp, "Corruption detected in superblock read-only compatible features (0x%x)!", (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); return -EFSCORRUPTED; } if (xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { xfs_warn(mp, "Corruption detected in superblock incompatible features (0x%x)!", (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN)); return -EFSCORRUPTED; } if (xfs_sb_has_incompat_log_feature(sbp, XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) { xfs_warn(mp, "Corruption detected in superblock incompatible log features (0x%x)!", (sbp->sb_features_log_incompat & XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)); return -EFSCORRUPTED; } /* * We can't read verify the sb LSN because the read verifier is called * before the log is allocated and processed. We know the log is set up * before write verifier calls, so check it here. */ if (!xfs_log_check_lsn(mp, sbp->sb_lsn)) return -EFSCORRUPTED; return 0; } /* Check the validity of the SB. */ STATIC int xfs_validate_sb_common( struct xfs_mount *mp, struct xfs_buf *bp, struct xfs_sb *sbp) { struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); uint32_t agcount = 0; uint32_t rem; if (!xfs_verify_magic(bp, dsb->sb_magicnum)) { xfs_warn(mp, "bad magic number"); return -EWRONGFS; } if (!xfs_sb_good_version(sbp)) { xfs_warn(mp, "bad version"); return -EWRONGFS; } if (xfs_sb_version_has_pquotino(sbp)) { if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) { xfs_notice(mp, "Version 5 of Super block has XFS_OQUOTA bits."); return -EFSCORRUPTED; } } else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) { xfs_notice(mp, "Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits."); return -EFSCORRUPTED; } /* * Full inode chunks must be aligned to inode chunk size when * sparse inodes are enabled to support the sparse chunk * allocation algorithm and prevent overlapping inode records. */ if (xfs_sb_version_hassparseinodes(sbp)) { uint32_t align; align = XFS_INODES_PER_CHUNK * sbp->sb_inodesize >> sbp->sb_blocklog; if (sbp->sb_inoalignmt != align) { xfs_warn(mp, "Inode block alignment (%u) must match chunk size (%u) for sparse inodes.", sbp->sb_inoalignmt, align); return -EINVAL; } } if (unlikely( sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { xfs_warn(mp, "filesystem is marked as having an external log; " "specify logdev on the mount command line."); return -EINVAL; } if (unlikely( sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { xfs_warn(mp, "filesystem is marked as having an internal log; " "do not specify logdev on the mount command line."); return -EINVAL; } /* Compute agcount for this number of dblocks and agblocks */ if (sbp->sb_agblocks) { agcount = div_u64_rem(sbp->sb_dblocks, sbp->sb_agblocks, &rem); if (rem) agcount++; } /* * More sanity checking. Most of these were stolen directly from * xfs_repair. */ if (unlikely( sbp->sb_agcount <= 0 || sbp->sb_sectsize < XFS_MIN_SECTORSIZE || sbp->sb_sectsize > XFS_MAX_SECTORSIZE || sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || sbp->sb_sectsize != (1 << sbp->sb_sectlog) || sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || sbp->sb_blocksize != (1 << sbp->sb_blocklog) || sbp->sb_dirblklog + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || sbp->sb_inodelog < XFS_DINODE_MIN_LOG || sbp->sb_inodelog > XFS_DINODE_MAX_LOG || sbp->sb_inodesize != (1 << sbp->sb_inodelog) || sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE || sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) || XFS_FSB_TO_B(mp, sbp->sb_agblocks) < XFS_MIN_AG_BYTES || XFS_FSB_TO_B(mp, sbp->sb_agblocks) > XFS_MAX_AG_BYTES || sbp->sb_agblklog != xfs_highbit32(sbp->sb_agblocks - 1) + 1 || agcount == 0 || agcount != sbp->sb_agcount || (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) || sbp->sb_dblocks == 0 || sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp) || sbp->sb_shared_vn != 0)) { xfs_notice(mp, "SB sanity check failed"); return -EFSCORRUPTED; } if (sbp->sb_unit) { if (!xfs_sb_version_hasdalign(sbp) || sbp->sb_unit > sbp->sb_width || (sbp->sb_width % sbp->sb_unit) != 0) { xfs_notice(mp, "SB stripe unit sanity check failed"); return -EFSCORRUPTED; } } else if (xfs_sb_version_hasdalign(sbp)) { xfs_notice(mp, "SB stripe alignment sanity check failed"); return -EFSCORRUPTED; } else if (sbp->sb_width) { xfs_notice(mp, "SB stripe width sanity check failed"); return -EFSCORRUPTED; } if (xfs_sb_version_hascrc(&mp->m_sb) && sbp->sb_blocksize < XFS_MIN_CRC_BLOCKSIZE) { xfs_notice(mp, "v5 SB sanity check failed"); return -EFSCORRUPTED; } /* * Currently only very few inode sizes are supported. */ switch (sbp->sb_inodesize) { case 256: case 512: case 1024: case 2048: break; default: xfs_warn(mp, "inode size of %d bytes not supported", sbp->sb_inodesize); return -ENOSYS; } if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { xfs_warn(mp, "file system too large to be mounted on this system."); return -EFBIG; } return 0; } void xfs_sb_quota_from_disk(struct xfs_sb *sbp) { /* * older mkfs doesn't initialize quota inodes to NULLFSINO. This * leads to in-core values having two different values for a quota * inode to be invalid: 0 and NULLFSINO. Change it to a single value * NULLFSINO. * * Note that this change affect only the in-core values. These * values are not written back to disk unless any quota information * is written to the disk. Even in that case, sb_pquotino field is * not written to disk unless the superblock supports pquotino. */ if (sbp->sb_uquotino == 0) sbp->sb_uquotino = NULLFSINO; if (sbp->sb_gquotino == 0) sbp->sb_gquotino = NULLFSINO; if (sbp->sb_pquotino == 0) sbp->sb_pquotino = NULLFSINO; /* * We need to do these manipilations only if we are working * with an older version of on-disk superblock. */ if (xfs_sb_version_has_pquotino(sbp)) return; if (sbp->sb_qflags & XFS_OQUOTA_ENFD) sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ? XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD; if (sbp->sb_qflags & XFS_OQUOTA_CHKD) sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ? XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD; sbp->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD); if (sbp->sb_qflags & XFS_PQUOTA_ACCT && sbp->sb_gquotino != NULLFSINO) { /* * In older version of superblock, on-disk superblock only * has sb_gquotino, and in-core superblock has both sb_gquotino * and sb_pquotino. But, only one of them is supported at any * point of time. So, if PQUOTA is set in disk superblock, * copy over sb_gquotino to sb_pquotino. The NULLFSINO test * above is to make sure we don't do this twice and wipe them * both out! */ sbp->sb_pquotino = sbp->sb_gquotino; sbp->sb_gquotino = NULLFSINO; } } static void __xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from, bool convert_xquota) { to->sb_magicnum = be32_to_cpu(from->sb_magicnum); to->sb_blocksize = be32_to_cpu(from->sb_blocksize); to->sb_dblocks = be64_to_cpu(from->sb_dblocks); to->sb_rblocks = be64_to_cpu(from->sb_rblocks); to->sb_rextents = be64_to_cpu(from->sb_rextents); memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); to->sb_logstart = be64_to_cpu(from->sb_logstart); to->sb_rootino = be64_to_cpu(from->sb_rootino); to->sb_rbmino = be64_to_cpu(from->sb_rbmino); to->sb_rsumino = be64_to_cpu(from->sb_rsumino); to->sb_rextsize = be32_to_cpu(from->sb_rextsize); to->sb_agblocks = be32_to_cpu(from->sb_agblocks); to->sb_agcount = be32_to_cpu(from->sb_agcount); to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); to->sb_logblocks = be32_to_cpu(from->sb_logblocks); to->sb_versionnum = be16_to_cpu(from->sb_versionnum); to->sb_sectsize = be16_to_cpu(from->sb_sectsize); to->sb_inodesize = be16_to_cpu(from->sb_inodesize); to->sb_inopblock = be16_to_cpu(from->sb_inopblock); memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); to->sb_blocklog = from->sb_blocklog; to->sb_sectlog = from->sb_sectlog; to->sb_inodelog = from->sb_inodelog; to->sb_inopblog = from->sb_inopblog; to->sb_agblklog = from->sb_agblklog; to->sb_rextslog = from->sb_rextslog; to->sb_inprogress = from->sb_inprogress; to->sb_imax_pct = from->sb_imax_pct; to->sb_icount = be64_to_cpu(from->sb_icount); to->sb_ifree = be64_to_cpu(from->sb_ifree); to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); to->sb_frextents = be64_to_cpu(from->sb_frextents); to->sb_uquotino = be64_to_cpu(from->sb_uquotino); to->sb_gquotino = be64_to_cpu(from->sb_gquotino); to->sb_qflags = be16_to_cpu(from->sb_qflags); to->sb_flags = from->sb_flags; to->sb_shared_vn = from->sb_shared_vn; to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt); to->sb_unit = be32_to_cpu(from->sb_unit); to->sb_width = be32_to_cpu(from->sb_width); to->sb_dirblklog = from->sb_dirblklog; to->sb_logsectlog = from->sb_logsectlog; to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); to->sb_logsunit = be32_to_cpu(from->sb_logsunit); to->sb_features2 = be32_to_cpu(from->sb_features2); to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2); to->sb_features_compat = be32_to_cpu(from->sb_features_compat); to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat); to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat); to->sb_features_log_incompat = be32_to_cpu(from->sb_features_log_incompat); /* crc is only used on disk, not in memory; just init to 0 here. */ to->sb_crc = 0; to->sb_spino_align = be32_to_cpu(from->sb_spino_align); to->sb_pquotino = be64_to_cpu(from->sb_pquotino); to->sb_lsn = be64_to_cpu(from->sb_lsn); /* * sb_meta_uuid is only on disk if it differs from sb_uuid and the * feature flag is set; if not set we keep it only in memory. */ if (xfs_sb_version_hasmetauuid(to)) uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); else uuid_copy(&to->sb_meta_uuid, &from->sb_uuid); /* Convert on-disk flags to in-memory flags? */ if (convert_xquota) xfs_sb_quota_from_disk(to); } void xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from) { __xfs_sb_from_disk(to, from, true); } static void xfs_sb_quota_to_disk( struct xfs_dsb *to, struct xfs_sb *from) { uint16_t qflags = from->sb_qflags; to->sb_uquotino = cpu_to_be64(from->sb_uquotino); if (xfs_sb_version_has_pquotino(from)) { to->sb_qflags = cpu_to_be16(from->sb_qflags); to->sb_gquotino = cpu_to_be64(from->sb_gquotino); to->sb_pquotino = cpu_to_be64(from->sb_pquotino); return; } /* * The in-core version of sb_qflags do not have XFS_OQUOTA_* * flags, whereas the on-disk version does. So, convert incore * XFS_{PG}QUOTA_* flags to on-disk XFS_OQUOTA_* flags. */ qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD | XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD); if (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD)) qflags |= XFS_OQUOTA_ENFD; if (from->sb_qflags & (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) qflags |= XFS_OQUOTA_CHKD; to->sb_qflags = cpu_to_be16(qflags); /* * GQUOTINO and PQUOTINO cannot be used together in versions * of superblock that do not have pquotino. from->sb_flags * tells us which quota is active and should be copied to * disk. If neither are active, we should NULL the inode. * * In all cases, the separate pquotino must remain 0 because it * it beyond the "end" of the valid non-pquotino superblock. */ if (from->sb_qflags & XFS_GQUOTA_ACCT) to->sb_gquotino = cpu_to_be64(from->sb_gquotino); else if (from->sb_qflags & XFS_PQUOTA_ACCT) to->sb_gquotino = cpu_to_be64(from->sb_pquotino); else { /* * We can't rely on just the fields being logged to tell us * that it is safe to write NULLFSINO - we should only do that * if quotas are not actually enabled. Hence only write * NULLFSINO if both in-core quota inodes are NULL. */ if (from->sb_gquotino == NULLFSINO && from->sb_pquotino == NULLFSINO) to->sb_gquotino = cpu_to_be64(NULLFSINO); } to->sb_pquotino = 0; } void xfs_sb_to_disk( struct xfs_dsb *to, struct xfs_sb *from) { xfs_sb_quota_to_disk(to, from); to->sb_magicnum = cpu_to_be32(from->sb_magicnum); to->sb_blocksize = cpu_to_be32(from->sb_blocksize); to->sb_dblocks = cpu_to_be64(from->sb_dblocks); to->sb_rblocks = cpu_to_be64(from->sb_rblocks); to->sb_rextents = cpu_to_be64(from->sb_rextents); memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); to->sb_logstart = cpu_to_be64(from->sb_logstart); to->sb_rootino = cpu_to_be64(from->sb_rootino); to->sb_rbmino = cpu_to_be64(from->sb_rbmino); to->sb_rsumino = cpu_to_be64(from->sb_rsumino); to->sb_rextsize = cpu_to_be32(from->sb_rextsize); to->sb_agblocks = cpu_to_be32(from->sb_agblocks); to->sb_agcount = cpu_to_be32(from->sb_agcount); to->sb_rbmblocks = cpu_to_be32(from->sb_rbmblocks); to->sb_logblocks = cpu_to_be32(from->sb_logblocks); to->sb_versionnum = cpu_to_be16(from->sb_versionnum); to->sb_sectsize = cpu_to_be16(from->sb_sectsize); to->sb_inodesize = cpu_to_be16(from->sb_inodesize); to->sb_inopblock = cpu_to_be16(from->sb_inopblock); memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); to->sb_blocklog = from->sb_blocklog; to->sb_sectlog = from->sb_sectlog; to->sb_inodelog = from->sb_inodelog; to->sb_inopblog = from->sb_inopblog; to->sb_agblklog = from->sb_agblklog; to->sb_rextslog = from->sb_rextslog; to->sb_inprogress = from->sb_inprogress; to->sb_imax_pct = from->sb_imax_pct; to->sb_icount = cpu_to_be64(from->sb_icount); to->sb_ifree = cpu_to_be64(from->sb_ifree); to->sb_fdblocks = cpu_to_be64(from->sb_fdblocks); to->sb_frextents = cpu_to_be64(from->sb_frextents); to->sb_flags = from->sb_flags; to->sb_shared_vn = from->sb_shared_vn; to->sb_inoalignmt = cpu_to_be32(from->sb_inoalignmt); to->sb_unit = cpu_to_be32(from->sb_unit); to->sb_width = cpu_to_be32(from->sb_width); to->sb_dirblklog = from->sb_dirblklog; to->sb_logsectlog = from->sb_logsectlog; to->sb_logsectsize = cpu_to_be16(from->sb_logsectsize); to->sb_logsunit = cpu_to_be32(from->sb_logsunit); /* * We need to ensure that bad_features2 always matches features2. * Hence we enforce that here rather than having to remember to do it * everywhere else that updates features2. */ from->sb_bad_features2 = from->sb_features2; to->sb_features2 = cpu_to_be32(from->sb_features2); to->sb_bad_features2 = cpu_to_be32(from->sb_bad_features2); if (xfs_sb_version_hascrc(from)) { to->sb_features_compat = cpu_to_be32(from->sb_features_compat); to->sb_features_ro_compat = cpu_to_be32(from->sb_features_ro_compat); to->sb_features_incompat = cpu_to_be32(from->sb_features_incompat); to->sb_features_log_incompat = cpu_to_be32(from->sb_features_log_incompat); to->sb_spino_align = cpu_to_be32(from->sb_spino_align); to->sb_lsn = cpu_to_be64(from->sb_lsn); if (xfs_sb_version_hasmetauuid(from)) uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); } } /* * If the superblock has the CRC feature bit set or the CRC field is non-null, * check that the CRC is valid. We check the CRC field is non-null because a * single bit error could clear the feature bit and unused parts of the * superblock are supposed to be zero. Hence a non-null crc field indicates that * we've potentially lost a feature bit and we should check it anyway. * * However, past bugs (i.e. in growfs) left non-zeroed regions beyond the * last field in V4 secondary superblocks. So for secondary superblocks, * we are more forgiving, and ignore CRC failures if the primary doesn't * indicate that the fs version is V5. */ static void xfs_sb_read_verify( struct xfs_buf *bp) { struct xfs_sb sb; struct xfs_mount *mp = bp->b_mount; struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); int error; /* * open code the version check to avoid needing to convert the entire * superblock from disk order just to check the version number */ if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) && (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) == XFS_SB_VERSION_5) || dsb->sb_crc != 0)) { if (!xfs_buf_verify_cksum(bp, XFS_SB_CRC_OFF)) { /* Only fail bad secondaries on a known V5 filesystem */ if (bp->b_bn == XFS_SB_DADDR || xfs_sb_version_hascrc(&mp->m_sb)) { error = -EFSBADCRC; goto out_error; } } } /* * Check all the superblock fields. Don't byteswap the xquota flags * because _verify_common checks the on-disk values. */ __xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false); error = xfs_validate_sb_common(mp, bp, &sb); if (error) goto out_error; error = xfs_validate_sb_read(mp, &sb); out_error: if (error == -EFSCORRUPTED || error == -EFSBADCRC) xfs_verifier_error(bp, error, __this_address); else if (error) xfs_buf_ioerror(bp, error); } /* * We may be probed for a filesystem match, so we may not want to emit * messages when the superblock buffer is not actually an XFS superblock. * If we find an XFS superblock, then run a normal, noisy mount because we are * really going to mount it and want to know about errors. */ static void xfs_sb_quiet_read_verify( struct xfs_buf *bp) { struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) { /* XFS filesystem, verify noisily! */ xfs_sb_read_verify(bp); return; } /* quietly fail */ xfs_buf_ioerror(bp, -EWRONGFS); } static void xfs_sb_write_verify( struct xfs_buf *bp) { struct xfs_sb sb; struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; int error; /* * Check all the superblock fields. Don't byteswap the xquota flags * because _verify_common checks the on-disk values. */ __xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false); error = xfs_validate_sb_common(mp, bp, &sb); if (error) goto out_error; error = xfs_validate_sb_write(mp, bp, &sb); if (error) goto out_error; if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_SB_CRC_OFF); return; out_error: xfs_verifier_error(bp, error, __this_address); } const struct xfs_buf_ops xfs_sb_buf_ops = { .name = "xfs_sb", .magic = { cpu_to_be32(XFS_SB_MAGIC), cpu_to_be32(XFS_SB_MAGIC) }, .verify_read = xfs_sb_read_verify, .verify_write = xfs_sb_write_verify, }; const struct xfs_buf_ops xfs_sb_quiet_buf_ops = { .name = "xfs_sb_quiet", .magic = { cpu_to_be32(XFS_SB_MAGIC), cpu_to_be32(XFS_SB_MAGIC) }, .verify_read = xfs_sb_quiet_read_verify, .verify_write = xfs_sb_write_verify, }; /* * xfs_mount_common * * Mount initialization code establishing various mount * fields from the superblock associated with the given * mount structure. * * Inode geometry are calculated in xfs_ialloc_setup_geometry. */ void xfs_sb_mount_common( struct xfs_mount *mp, struct xfs_sb *sbp) { mp->m_agfrotor = mp->m_agirotor = 0; mp->m_maxagi = mp->m_sb.sb_agcount; mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; mp->m_blockmask = sbp->sb_blocksize - 1; mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; mp->m_blockwmask = mp->m_blockwsize - 1; mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1); mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0); mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2; mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2; mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1); mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0); mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2; mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2; mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(sbp->sb_blocksize, 1); mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(sbp->sb_blocksize, 0); mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2; mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2; mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(sbp->sb_blocksize, true); mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(sbp->sb_blocksize, false); mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2; mp->m_refc_mnr[1] = mp->m_refc_mxr[1] / 2; mp->m_bsize = XFS_FSB_TO_BB(mp, 1); mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp); } /* * xfs_initialize_perag_data * * Read in each per-ag structure so we can count up the number of * allocated inodes, free inodes and used filesystem blocks as this * information is no longer persistent in the superblock. Once we have * this information, write it into the in-core superblock structure. */ int xfs_initialize_perag_data( struct xfs_mount *mp, xfs_agnumber_t agcount) { xfs_agnumber_t index; xfs_perag_t *pag; xfs_sb_t *sbp = &mp->m_sb; uint64_t ifree = 0; uint64_t ialloc = 0; uint64_t bfree = 0; uint64_t bfreelst = 0; uint64_t btree = 0; uint64_t fdblocks; int error = 0; for (index = 0; index < agcount; index++) { /* * read the agf, then the agi. This gets us * all the information we need and populates the * per-ag structures for us. */ error = xfs_alloc_pagf_init(mp, NULL, index, 0); if (error) return error; error = xfs_ialloc_pagi_init(mp, NULL, index); if (error) return error; pag = xfs_perag_get(mp, index); ifree += pag->pagi_freecount; ialloc += pag->pagi_count; bfree += pag->pagf_freeblks; bfreelst += pag->pagf_flcount; btree += pag->pagf_btreeblks; xfs_perag_put(pag); } fdblocks = bfree + bfreelst + btree; /* * If the new summary counts are obviously incorrect, fail the * mount operation because that implies the AGFs are also corrupt. * Clear FS_COUNTERS so that we don't unmount with a dirty log, which * will prevent xfs_repair from fixing anything. */ if (fdblocks > sbp->sb_dblocks || ifree > ialloc) { xfs_alert(mp, "AGF corruption. Please run xfs_repair."); error = -EFSCORRUPTED; goto out; } /* Overwrite incore superblock counters with just-read data */ spin_lock(&mp->m_sb_lock); sbp->sb_ifree = ifree; sbp->sb_icount = ialloc; sbp->sb_fdblocks = fdblocks; spin_unlock(&mp->m_sb_lock); xfs_reinit_percpu_counters(mp); out: xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS); return error; } /* * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock * into the superblock buffer to be logged. It does not provide the higher * level of locking that is needed to protect the in-core superblock from * concurrent access. */ void xfs_log_sb( struct xfs_trans *tp) { struct xfs_mount *mp = tp->t_mountp; struct xfs_buf *bp = xfs_trans_getsb(tp, mp); mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree); mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsb)); } /* * xfs_sync_sb * * Sync the superblock to disk. * * Note that the caller is responsible for checking the frozen state of the * filesystem. This procedure uses the non-blocking transaction allocator and * thus will allow modifications to a frozen fs. This is required because this * code can be called during the process of freezing where use of the high-level * allocator would deadlock. */ int xfs_sync_sb( struct xfs_mount *mp, bool wait) { struct xfs_trans *tp; int error; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, XFS_TRANS_NO_WRITECOUNT, &tp); if (error) return error; xfs_log_sb(tp); if (wait) xfs_trans_set_sync(tp); return xfs_trans_commit(tp); } /* * Update all the secondary superblocks to match the new state of the primary. * Because we are completely overwriting all the existing fields in the * secondary superblock buffers, there is no need to read them in from disk. * Just get a new buffer, stamp it and write it. * * The sb buffers need to be cached here so that we serialise against other * operations that access the secondary superblocks, but we don't want to keep * them in memory once it is written so we mark it as a one-shot buffer. */ int xfs_update_secondary_sbs( struct xfs_mount *mp) { xfs_agnumber_t agno; int saved_error = 0; int error = 0; LIST_HEAD (buffer_list); /* update secondary superblocks. */ for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) { struct xfs_buf *bp; bp = xfs_buf_get(mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1)); /* * If we get an error reading or writing alternate superblocks, * continue. xfs_repair chooses the "best" superblock based * on most matches; if we break early, we'll leave more * superblocks un-updated than updated, and xfs_repair may * pick them over the properly-updated primary. */ if (!bp) { xfs_warn(mp, "error allocating secondary superblock for ag %d", agno); if (!saved_error) saved_error = -ENOMEM; continue; } bp->b_ops = &xfs_sb_buf_ops; xfs_buf_oneshot(bp); xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); xfs_buf_delwri_queue(bp, &buffer_list); xfs_buf_relse(bp); /* don't hold too many buffers at once */ if (agno % 16) continue; error = xfs_buf_delwri_submit(&buffer_list); if (error) { xfs_warn(mp, "write error %d updating a secondary superblock near ag %d", error, agno); if (!saved_error) saved_error = error; continue; } } error = xfs_buf_delwri_submit(&buffer_list); if (error) { xfs_warn(mp, "write error %d updating a secondary superblock near ag %d", error, agno); } return saved_error ? saved_error : error; } /* * Same behavior as xfs_sync_sb, except that it is always synchronous and it * also writes the superblock buffer to disk sector 0 immediately. */ int xfs_sync_sb_buf( struct xfs_mount *mp) { struct xfs_trans *tp; struct xfs_buf *bp; int error; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, 0, &tp); if (error) return error; bp = xfs_trans_getsb(tp, mp); xfs_log_sb(tp); xfs_trans_bhold(tp, bp); xfs_trans_set_sync(tp); error = xfs_trans_commit(tp); if (error) goto out; /* * write out the sb buffer to get the changes to disk */ error = xfs_bwrite(bp); out: xfs_buf_relse(bp); return error; } void xfs_fs_geometry( struct xfs_sb *sbp, struct xfs_fsop_geom *geo, int struct_version) { memset(geo, 0, sizeof(struct xfs_fsop_geom)); geo->blocksize = sbp->sb_blocksize; geo->rtextsize = sbp->sb_rextsize; geo->agblocks = sbp->sb_agblocks; geo->agcount = sbp->sb_agcount; geo->logblocks = sbp->sb_logblocks; geo->sectsize = sbp->sb_sectsize; geo->inodesize = sbp->sb_inodesize; geo->imaxpct = sbp->sb_imax_pct; geo->datablocks = sbp->sb_dblocks; geo->rtblocks = sbp->sb_rblocks; geo->rtextents = sbp->sb_rextents; geo->logstart = sbp->sb_logstart; BUILD_BUG_ON(sizeof(geo->uuid) != sizeof(sbp->sb_uuid)); memcpy(geo->uuid, &sbp->sb_uuid, sizeof(sbp->sb_uuid)); if (struct_version < 2) return; geo->sunit = sbp->sb_unit; geo->swidth = sbp->sb_width; if (struct_version < 3) return; geo->version = XFS_FSOP_GEOM_VERSION; geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK | XFS_FSOP_GEOM_FLAGS_DIRV2 | XFS_FSOP_GEOM_FLAGS_EXTFLG; if (xfs_sb_version_hasattr(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_ATTR; if (xfs_sb_version_hasquota(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_QUOTA; if (xfs_sb_version_hasalign(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_IALIGN; if (xfs_sb_version_hasdalign(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_DALIGN; if (xfs_sb_version_hassector(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_SECTOR; if (xfs_sb_version_hasasciici(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_DIRV2CI; if (xfs_sb_version_haslazysbcount(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_LAZYSB; if (xfs_sb_version_hasattr2(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_ATTR2; if (xfs_sb_version_hasprojid32bit(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_PROJID32; if (xfs_sb_version_hascrc(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_V5SB; if (xfs_sb_version_hasftype(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_FTYPE; if (xfs_sb_version_hasfinobt(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_FINOBT; if (xfs_sb_version_hassparseinodes(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_SPINODES; if (xfs_sb_version_hasrmapbt(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT; if (xfs_sb_version_hasreflink(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK; if (xfs_sb_version_hassector(sbp)) geo->logsectsize = sbp->sb_logsectsize; else geo->logsectsize = BBSIZE; geo->rtsectsize = sbp->sb_blocksize; geo->dirblocksize = xfs_dir2_dirblock_bytes(sbp); if (struct_version < 4) return; if (xfs_sb_version_haslogv2(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_LOGV2; geo->logsunit = sbp->sb_logsunit; if (struct_version < 5) return; geo->version = XFS_FSOP_GEOM_VERSION_V5; } /* Read a secondary superblock. */ int xfs_sb_read_secondary( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp) { struct xfs_buf *bp; int error; ASSERT(agno != 0 && agno != NULLAGNUMBER); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_SB_BLOCK(mp)), XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_sb_buf_ops); if (error) return error; xfs_buf_set_ref(bp, XFS_SSB_REF); *bpp = bp; return 0; } /* Get an uninitialised secondary superblock buffer. */ int xfs_sb_get_secondary( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp) { struct xfs_buf *bp; ASSERT(agno != 0 && agno != NULLAGNUMBER); bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_SB_BLOCK(mp)), XFS_FSS_TO_BB(mp, 1), 0); if (!bp) return -ENOMEM; bp->b_ops = &xfs_sb_buf_ops; xfs_buf_oneshot(bp); *bpp = bp; return 0; } xfsprogs-5.3.0/libxfs/xfs_sb.h0000644000175000017500000000276413570057155016211 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_SB_H__ #define __XFS_SB_H__ struct xfs_mount; struct xfs_sb; struct xfs_dsb; struct xfs_trans; struct xfs_fsop_geom; struct xfs_perag; /* * perag get/put wrappers for ref counting */ extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t); extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t, int tag); extern void xfs_perag_put(struct xfs_perag *pag); extern int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t); extern void xfs_log_sb(struct xfs_trans *tp); extern int xfs_sync_sb(struct xfs_mount *mp, bool wait); extern int xfs_sync_sb_buf(struct xfs_mount *mp); extern void xfs_sb_mount_common(struct xfs_mount *mp, struct xfs_sb *sbp); extern void xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from); extern void xfs_sb_to_disk(struct xfs_dsb *to, struct xfs_sb *from); extern void xfs_sb_quota_from_disk(struct xfs_sb *sbp); extern int xfs_update_secondary_sbs(struct xfs_mount *mp); #define XFS_FS_GEOM_MAX_STRUCT_VER (4) extern void xfs_fs_geometry(struct xfs_sb *sbp, struct xfs_fsop_geom *geo, int struct_version); extern int xfs_sb_read_secondary(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp); extern int xfs_sb_get_secondary(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp); #endif /* __XFS_SB_H__ */ xfsprogs-5.3.0/libxfs/xfs_shared.h0000644000175000017500000001511413570057155017044 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. */ #ifndef __XFS_SHARED_H__ #define __XFS_SHARED_H__ /* * Definitions shared between kernel and userspace that don't fit into any other * header file that is shared with userspace. */ struct xfs_ifork; struct xfs_buf; struct xfs_buf_ops; struct xfs_mount; struct xfs_trans; struct xfs_inode; /* * Buffer verifier operations are widely used, including userspace tools */ extern const struct xfs_buf_ops xfs_agf_buf_ops; extern const struct xfs_buf_ops xfs_agi_buf_ops; extern const struct xfs_buf_ops xfs_agf_buf_ops; extern const struct xfs_buf_ops xfs_agfl_buf_ops; extern const struct xfs_buf_ops xfs_bnobt_buf_ops; extern const struct xfs_buf_ops xfs_cntbt_buf_ops; extern const struct xfs_buf_ops xfs_rmapbt_buf_ops; extern const struct xfs_buf_ops xfs_refcountbt_buf_ops; extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops; extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops; extern const struct xfs_buf_ops xfs_bmbt_buf_ops; extern const struct xfs_buf_ops xfs_da3_node_buf_ops; extern const struct xfs_buf_ops xfs_dquot_buf_ops; extern const struct xfs_buf_ops xfs_symlink_buf_ops; extern const struct xfs_buf_ops xfs_agi_buf_ops; extern const struct xfs_buf_ops xfs_inobt_buf_ops; extern const struct xfs_buf_ops xfs_finobt_buf_ops; extern const struct xfs_buf_ops xfs_inode_buf_ops; extern const struct xfs_buf_ops xfs_inode_buf_ra_ops; extern const struct xfs_buf_ops xfs_dquot_buf_ops; extern const struct xfs_buf_ops xfs_dquot_buf_ra_ops; extern const struct xfs_buf_ops xfs_sb_buf_ops; extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops; extern const struct xfs_buf_ops xfs_symlink_buf_ops; extern const struct xfs_buf_ops xfs_rtbuf_ops; /* log size calculation functions */ int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes); int xfs_log_calc_minimum_size(struct xfs_mount *); struct xfs_trans_res; void xfs_log_get_max_trans_res(struct xfs_mount *mp, struct xfs_trans_res *max_resp); /* * Values for t_flags. */ #define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ #define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ #define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ #define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ #define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ #define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ #define XFS_TRANS_NO_WRITECOUNT 0x40 /* do not elevate SB writecount */ /* * LOWMODE is used by the allocator to activate the lowspace algorithm - when * free space is running low the extent allocator may choose to allocate an * extent from an AG without leaving sufficient space for a btree split when * inserting the new extent. In this case the allocator will enable the * lowspace algorithm which is supposed to allow further allocations (such as * btree splits and newroots) to allocate from sequential AGs. In order to * avoid locking AGs out of order the lowspace algorithm will start searching * for free space from AG 0. If the correct transaction reservations have been * made then this algorithm will eventually find all the space it needs. */ #define XFS_TRANS_LOWMODE 0x100 /* allocate in low space mode */ /* * Field values for xfs_trans_mod_sb. */ #define XFS_TRANS_SB_ICOUNT 0x00000001 #define XFS_TRANS_SB_IFREE 0x00000002 #define XFS_TRANS_SB_FDBLOCKS 0x00000004 #define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 #define XFS_TRANS_SB_FREXTENTS 0x00000010 #define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 #define XFS_TRANS_SB_DBLOCKS 0x00000040 #define XFS_TRANS_SB_AGCOUNT 0x00000080 #define XFS_TRANS_SB_IMAXPCT 0x00000100 #define XFS_TRANS_SB_REXTSIZE 0x00000200 #define XFS_TRANS_SB_RBMBLOCKS 0x00000400 #define XFS_TRANS_SB_RBLOCKS 0x00000800 #define XFS_TRANS_SB_REXTENTS 0x00001000 #define XFS_TRANS_SB_REXTSLOG 0x00002000 /* * Here we centralize the specification of XFS meta-data buffer reference count * values. This determines how hard the buffer cache tries to hold onto the * buffer. */ #define XFS_AGF_REF 4 #define XFS_AGI_REF 4 #define XFS_AGFL_REF 3 #define XFS_INO_BTREE_REF 3 #define XFS_ALLOC_BTREE_REF 2 #define XFS_BMAP_BTREE_REF 2 #define XFS_RMAP_BTREE_REF 2 #define XFS_DIR_BTREE_REF 2 #define XFS_INO_REF 2 #define XFS_ATTR_BTREE_REF 1 #define XFS_DQUOT_REF 1 #define XFS_REFC_BTREE_REF 1 #define XFS_SSB_REF 0 /* * Flags for xfs_trans_ichgtime(). */ #define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ #define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */ #define XFS_ICHGTIME_CREATE 0x4 /* inode create timestamp */ /* * Symlink decoding/encoding functions */ int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp); xfs_failaddr_t xfs_symlink_shortform_verify(struct xfs_inode *ip); /* Computed inode geometry for the filesystem. */ struct xfs_ino_geometry { /* Maximum inode count in this filesystem. */ uint64_t maxicount; /* Actual inode cluster buffer size, in bytes. */ unsigned int inode_cluster_size; /* * Desired inode cluster buffer size, in bytes. This value is not * rounded up to at least one filesystem block, which is necessary for * the sole purpose of validating sb_spino_align. Runtime code must * only ever use inode_cluster_size. */ unsigned int inode_cluster_size_raw; /* Inode cluster sizes, adjusted to be at least 1 fsb. */ unsigned int inodes_per_cluster; unsigned int blocks_per_cluster; /* Inode cluster alignment. */ unsigned int cluster_align; unsigned int cluster_align_inodes; unsigned int inoalign_mask; /* mask sb_inoalignmt if used */ unsigned int inobt_mxr[2]; /* max inobt btree records */ unsigned int inobt_mnr[2]; /* min inobt btree records */ unsigned int inobt_maxlevels; /* max inobt btree levels. */ /* Size of inode allocations under normal operation. */ unsigned int ialloc_inos; unsigned int ialloc_blks; /* Minimum inode blocks for a sparse allocation. */ unsigned int ialloc_min_blks; /* stripe unit inode alignment */ unsigned int ialloc_align; unsigned int agino_log; /* #bits for agino in inum */ }; /* Keep iterating the data structure. */ #define XFS_ITER_CONTINUE (0) /* Stop iterating the data structure. */ #define XFS_ITER_ABORT (1) #endif /* __XFS_SHARED_H__ */ xfsprogs-5.3.0/libxfs/xfs_symlink_remote.c0000644000175000017500000001254713570057155020641 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * Copyright (c) 2012-2013 Red Hat, Inc. * All rights reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_shared.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" /* * Each contiguous block has a header, so it is not just a simple pathlen * to FSB conversion. */ int xfs_symlink_blocks( struct xfs_mount *mp, int pathlen) { int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); return (pathlen + buflen - 1) / buflen; } int xfs_symlink_hdr_set( struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp) { struct xfs_dsymlink_hdr *dsl = bp->b_addr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return 0; memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr)); dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); dsl->sl_offset = cpu_to_be32(offset); dsl->sl_bytes = cpu_to_be32(size); uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid); dsl->sl_owner = cpu_to_be64(ino); dsl->sl_blkno = cpu_to_be64(bp->b_bn); bp->b_ops = &xfs_symlink_buf_ops; return sizeof(struct xfs_dsymlink_hdr); } /* * Checking of the symlink header is split into two parts. the verifier does * CRC, location and bounds checking, the unpacking function checks the path * parameters and owner. */ bool xfs_symlink_hdr_ok( xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp) { struct xfs_dsymlink_hdr *dsl = bp->b_addr; if (offset != be32_to_cpu(dsl->sl_offset)) return false; if (size != be32_to_cpu(dsl->sl_bytes)) return false; if (ino != be64_to_cpu(dsl->sl_owner)) return false; /* ok */ return true; } static xfs_failaddr_t xfs_symlink_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_dsymlink_hdr *dsl = bp->b_addr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return __this_address; if (!xfs_verify_magic(bp, dsl->sl_magic)) return __this_address; if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (bp->b_bn != be64_to_cpu(dsl->sl_blkno)) return __this_address; if (be32_to_cpu(dsl->sl_offset) + be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN) return __this_address; if (dsl->sl_owner == 0) return __this_address; if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn))) return __this_address; return NULL; } static void xfs_symlink_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; xfs_failaddr_t fa; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF)) xfs_verifier_error(bp, -EFSBADCRC, __this_address); else { fa = xfs_symlink_verify(bp); if (fa) xfs_verifier_error(bp, -EFSCORRUPTED, fa); } } static void xfs_symlink_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; xfs_failaddr_t fa; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; fa = xfs_symlink_verify(bp); if (fa) { xfs_verifier_error(bp, -EFSCORRUPTED, fa); return; } if (bip) { struct xfs_dsymlink_hdr *dsl = bp->b_addr; dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn); } xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF); } const struct xfs_buf_ops xfs_symlink_buf_ops = { .name = "xfs_symlink", .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) }, .verify_read = xfs_symlink_read_verify, .verify_write = xfs_symlink_write_verify, .verify_struct = xfs_symlink_verify, }; void xfs_symlink_local_to_remote( struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp) { struct xfs_mount *mp = ip->i_mount; char *buf; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF); if (!xfs_sb_version_hascrc(&mp->m_sb)) { bp->b_ops = NULL; memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); return; } /* * As this symlink fits in an inode literal area, it must also fit in * the smallest buffer the filesystem supports. */ ASSERT(BBTOB(bp->b_length) >= ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr)); bp->b_ops = &xfs_symlink_buf_ops; buf = bp->b_addr; buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) + ifp->if_bytes - 1); } /* * Verify the in-memory consistency of an inline symlink data fork. This * does not do on-disk format checks. */ xfs_failaddr_t xfs_symlink_shortform_verify( struct xfs_inode *ip) { char *sfp; char *endp; struct xfs_ifork *ifp; int size; ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL); ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); sfp = (char *)ifp->if_u1.if_data; size = ifp->if_bytes; endp = sfp + size; /* * Zero length symlinks should never occur in memory as they are * never alllowed to exist on disk. */ if (!size) return __this_address; /* No negative sizes or overly long symlink targets. */ if (size < 0 || size > XFS_SYMLINK_MAXLEN) return __this_address; /* No NULLs in the target either. */ if (memchr(sfp, 0, size - 1)) return __this_address; /* We /did/ null-terminate the buffer, right? */ if (*endp != 0) return __this_address; return NULL; } xfsprogs-5.3.0/libxfs/xfs_trans_inode.c0000644000175000017500000001025613570057155020100 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_inode.h" #include "xfs_trans.h" /* * Add a locked inode to the transaction. * * The inode must be locked, and it cannot be associated with any transaction. * If lock_flags is non-zero the inode will be unlocked on transaction commit. */ void xfs_trans_ijoin( struct xfs_trans *tp, struct xfs_inode *ip, uint lock_flags) { xfs_inode_log_item_t *iip; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); if (ip->i_itemp == NULL) xfs_inode_item_init(ip, ip->i_mount); iip = ip->i_itemp; ASSERT(iip->ili_lock_flags == 0); iip->ili_lock_flags = lock_flags; /* * Get a log_item_desc to point at the new item. */ xfs_trans_add_item(tp, &iip->ili_item); } /* * Transactional inode timestamp update. Requires the inode to be locked and * joined to the transaction supplied. Relies on the transaction subsystem to * track dirty state and update/writeback the inode accordingly. */ void xfs_trans_ichgtime( struct xfs_trans *tp, struct xfs_inode *ip, int flags) { struct inode *inode = VFS_I(ip); struct timespec64 tv; ASSERT(tp); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); tv = current_time(inode); if (flags & XFS_ICHGTIME_MOD) inode->i_mtime = tv; if (flags & XFS_ICHGTIME_CHG) inode->i_ctime = tv; if (flags & XFS_ICHGTIME_CREATE) { ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec; ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec; } } /* * This is called to mark the fields indicated in fieldmask as needing * to be logged when the transaction is committed. The inode must * already be associated with the given transaction. * * The values for fieldmask are defined in xfs_inode_item.h. We always * log all of the core inode if any of it has changed, and we always log * all of the inline data/extents/b-tree root if any of them has changed. */ void xfs_trans_log_inode( xfs_trans_t *tp, xfs_inode_t *ip, uint flags) { struct inode *inode = VFS_I(ip); ASSERT(ip->i_itemp != NULL); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); /* * Don't bother with i_lock for the I_DIRTY_TIME check here, as races * don't matter - we either will need an extra transaction in 24 hours * to log the timestamps, or will clear already cleared fields in the * worst case. */ if (inode->i_state & (I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED)) { spin_lock(&inode->i_lock); inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED); spin_unlock(&inode->i_lock); } /* * Record the specific change for fdatasync optimisation. This * allows fdatasync to skip log forces for inodes that are only * timestamp dirty. We do this before the change count so that * the core being logged in this case does not impact on fdatasync * behaviour. */ ip->i_itemp->ili_fsync_fields |= flags; /* * First time we log the inode in a transaction, bump the inode change * counter if it is configured for this to occur. While we have the * inode locked exclusively for metadata modification, we can usually * avoid setting XFS_ILOG_CORE if no one has queried the value since * the last time it was incremented. If we have XFS_ILOG_CORE already * set however, then go ahead and bump the i_version counter * unconditionally. */ if (!test_and_set_bit(XFS_LI_DIRTY, &ip->i_itemp->ili_item.li_flags) && IS_I_VERSION(VFS_I(ip))) { if (inode_maybe_inc_iversion(VFS_I(ip), flags & XFS_ILOG_CORE)) flags |= XFS_ILOG_CORE; } tp->t_flags |= XFS_TRANS_DIRTY; /* * Always OR in the bits from the ili_last_fields field. * This is to coordinate with the xfs_iflush() and xfs_iflush_done() * routines in the eventual clearing of the ili_fields bits. * See the big comment in xfs_iflush() for an explanation of * this coordination mechanism. */ flags |= ip->i_itemp->ili_last_fields; ip->i_itemp->ili_fields |= flags; } int xfs_trans_roll_inode( struct xfs_trans **tpp, struct xfs_inode *ip) { int error; xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); error = xfs_trans_roll(tpp); if (!error) xfs_trans_ijoin(*tpp, ip, 0); return error; } xfsprogs-5.3.0/libxfs/xfs_trans_resv.c0000644000175000017500000007116213570057155017764 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (C) 2010 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_bmap_btree.h" #include "xfs_trans.h" #include "xfs_trans_space.h" #include "xfs_quota_defs.h" #define _ALLOC true #define _FREE false /* * A buffer has a format structure overhead in the log in addition * to the data, so we need to take this into account when reserving * space in a transaction for a buffer. Round the space required up * to a multiple of 128 bytes so that we don't change the historical * reservation that has been used for this overhead. */ STATIC uint xfs_buf_log_overhead(void) { return round_up(sizeof(struct xlog_op_header) + sizeof(struct xfs_buf_log_format), 128); } /* * Calculate out transaction log reservation per item in bytes. * * The nbufs argument is used to indicate the number of items that * will be changed in a transaction. size is used to tell how many * bytes should be reserved per item. */ STATIC uint xfs_calc_buf_res( uint nbufs, uint size) { return nbufs * (size + xfs_buf_log_overhead()); } /* * Per-extent log reservation for the btree changes involved in freeing or * allocating an extent. In classic XFS there were two trees that will be * modified (bnobt + cntbt). With rmap enabled, there are three trees * (rmapbt). With reflink, there are four trees (refcountbt). The number of * blocks reserved is based on the formula: * * num trees * ((2 blocks/level * max depth) - 1) * * Keep in mind that max depth is calculated separately for each type of tree. */ uint xfs_allocfree_log_count( struct xfs_mount *mp, uint num_ops) { uint blocks; blocks = num_ops * 2 * (2 * mp->m_ag_maxlevels - 1); if (xfs_sb_version_hasrmapbt(&mp->m_sb)) blocks += num_ops * (2 * mp->m_rmap_maxlevels - 1); if (xfs_sb_version_hasreflink(&mp->m_sb)) blocks += num_ops * (2 * mp->m_refc_maxlevels - 1); return blocks; } /* * Logging inodes is really tricksy. They are logged in memory format, * which means that what we write into the log doesn't directly translate into * the amount of space they use on disk. * * Case in point - btree format forks in memory format use more space than the * on-disk format. In memory, the buffer contains a normal btree block header so * the btree code can treat it as though it is just another generic buffer. * However, when we write it to the inode fork, we don't write all of this * header as it isn't needed. e.g. the root is only ever in the inode, so * there's no need for sibling pointers which would waste 16 bytes of space. * * Hence when we have an inode with a maximally sized btree format fork, then * amount of information we actually log is greater than the size of the inode * on disk. Hence we need an inode reservation function that calculates all this * correctly. So, we log: * * - 4 log op headers for object * - for the ilf, the inode core and 2 forks * - inode log format object * - the inode core * - two inode forks containing bmap btree root blocks. * - the btree data contained by both forks will fit into the inode size, * hence when combined with the inode core above, we have a total of the * actual inode size. * - the BMBT headers need to be accounted separately, as they are * additional to the records and pointers that fit inside the inode * forks. */ STATIC uint xfs_calc_inode_res( struct xfs_mount *mp, uint ninodes) { return ninodes * (4 * sizeof(struct xlog_op_header) + sizeof(struct xfs_inode_log_format) + mp->m_sb.sb_inodesize + 2 * XFS_BMBT_BLOCK_LEN(mp)); } /* * Inode btree record insertion/removal modifies the inode btree and free space * btrees (since the inobt does not use the agfl). This requires the following * reservation: * * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size * * The caller must account for SB and AG header modifications, etc. */ STATIC uint xfs_calc_inobt_res( struct xfs_mount *mp) { return xfs_calc_buf_res(M_IGEO(mp)->inobt_maxlevels, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * The free inode btree is a conditional feature. The behavior differs slightly * from that of the traditional inode btree in that the finobt tracks records * for inode chunks with at least one free inode. A record can be removed from * the tree during individual inode allocation. Therefore the finobt * reservation is unconditional for both the inode chunk allocation and * individual inode allocation (modify) cases. * * Behavior aside, the reservation for finobt modification is equivalent to the * traditional inobt: cover a full finobt shape change plus block allocation. */ STATIC uint xfs_calc_finobt_res( struct xfs_mount *mp) { if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return 0; return xfs_calc_inobt_res(mp); } /* * Calculate the reservation required to allocate or free an inode chunk. This * includes: * * the allocation btrees: 2 trees * (max depth - 1) * block size * the inode chunk: m_ino_geo.ialloc_blks * N * * The size N of the inode chunk reservation depends on whether it is for * allocation or free and which type of create transaction is in use. An inode * chunk free always invalidates the buffers and only requires reservation for * headers (N == 0). An inode chunk allocation requires a chunk sized * reservation on v4 and older superblocks to initialize the chunk. No chunk * reservation is required for allocation on v5 supers, which use ordered * buffers to initialize. */ STATIC uint xfs_calc_inode_chunk_res( struct xfs_mount *mp, bool alloc) { uint res, size = 0; res = xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), XFS_FSB_TO_B(mp, 1)); if (alloc) { /* icreate tx uses ordered buffers */ if (xfs_sb_version_hascrc(&mp->m_sb)) return res; size = XFS_FSB_TO_B(mp, 1); } res += xfs_calc_buf_res(M_IGEO(mp)->ialloc_blks, size); return res; } /* * Various log reservation values. * * These are based on the size of the file system block because that is what * most transactions manipulate. Each adds in an additional 128 bytes per * item logged to try to account for the overhead of the transaction mechanism. * * Note: Most of the reservations underestimate the number of allocation * groups into which they could free extents in the xfs_defer_finish() call. * This is because the number in the worst case is quite high and quite * unusual. In order to fix this we need to change xfs_defer_finish() to free * extents in only a single AG at a time. This will require changes to the * EFI code as well, however, so that the EFI for the extents not freed is * logged again in each transaction. See SGI PV #261917. * * Reservation functions here avoid a huge stack in xfs_trans_init due to * register overflow from temporaries in the calculations. */ /* * In a write transaction we can allocate a maximum of 2 * extents. This gives: * the inode getting the new extents: inode size * the inode's bmap btree: max depth * block size * the agfs of the ags from which the extents are allocated: 2 * sector * the superblock free block counter: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size * And the bmap_finish transaction can free bmap blocks in a join: * the agfs of the ags containing the blocks: 2 * sector size * the agfls of the ags containing the blocks: 2 * sector size * the super block free block counter: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_write_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), XFS_FSB_TO_B(mp, 1)))); } /* * In truncating a file we free up to two extents at once. We can modify: * the inode being truncated: inode size * the inode's bmap btree: (max depth + 1) * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_itruncate_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1, XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4), XFS_FSB_TO_B(mp, 1)))); } /* * In renaming a files we can modify: * the four inodes involved: 4 * inode size * the two directory btrees: 2 * (max depth + v2) * dir block size * the two directory bmap btrees: 2 * max depth * block size * And the bmap_finish transaction can free dir and bmap blocks (two sets * of bmap blocks) giving: * the agf for the ags in which the blocks live: 3 * sector size * the agfl for the ags in which the blocks live: 3 * sector size * the superblock for the free block count: sector size * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_rename_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + max((xfs_calc_inode_res(mp, 4) + xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 3), XFS_FSB_TO_B(mp, 1)))); } /* * For removing an inode from unlinked list at first, we can modify: * the agi hash list and counters: sector size * the on disk inode before ours in the agi hash list: inode cluster size * the on disk inode in the agi hash list: inode cluster size */ STATIC uint xfs_calc_iunlink_remove_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + 2 * M_IGEO(mp)->inode_cluster_size; } /* * For creating a link to an inode: * the parent directory inode: inode size * the linked inode: inode size * the directory btree could split: (max depth + v2) * dir block size * the directory bmap btree could join or split: (max depth + v2) * blocksize * And the bmap_finish transaction can free some bmap blocks giving: * the agf for the ag in which the blocks live: sector size * the agfl for the ag in which the blocks live: sector size * the superblock for the free block count: sector size * the allocation btrees: 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_link_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_iunlink_remove_reservation(mp) + max((xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), XFS_FSB_TO_B(mp, 1)))); } /* * For adding an inode to unlinked list we can modify: * the agi hash list: sector size * the on disk inode: inode cluster size */ STATIC uint xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + M_IGEO(mp)->inode_cluster_size; } /* * For removing a directory entry we can modify: * the parent directory inode: inode size * the removed inode: inode size * the directory btree could join: (max depth + v2) * dir block size * the directory bmap btree could join or split: (max depth + v2) * blocksize * And the bmap_finish transaction can free the dir and bmap blocks giving: * the agf for the ag in which the blocks live: 2 * sector size * the agfl for the ag in which the blocks live: 2 * sector size * the superblock for the free block count: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_remove_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_iunlink_add_reservation(mp) + max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), XFS_FSB_TO_B(mp, 1)))); } /* * For create, break it in to the two cases that the transaction * covers. We start with the modify case - allocation done by modification * of the state of existing inodes - and the allocation case. */ /* * For create we can modify: * the parent directory inode: inode size * the new inode: inode size * the inode btree entry: block size * the superblock for the nlink flag: sector size * the directory btree: (max depth + v2) * dir block size * the directory inode's bmap btree: (max depth + v2) * block size * the finobt (record modification and allocation btrees) */ STATIC uint xfs_calc_create_resv_modify( struct xfs_mount *mp) { return xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + (uint)XFS_FSB_TO_B(mp, 1) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) + xfs_calc_finobt_res(mp); } /* * For icreate we can allocate some inodes giving: * the agi and agf of the ag getting the new inodes: 2 * sectorsize * the superblock for the nlink flag: sector size * the inode chunk (allocation, optional init) * the inobt (record insertion) * the finobt (optional, record insertion) */ STATIC uint xfs_calc_icreate_resv_alloc( struct xfs_mount *mp) { return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + mp->m_sb.sb_sectsize + xfs_calc_inode_chunk_res(mp, _ALLOC) + xfs_calc_inobt_res(mp) + xfs_calc_finobt_res(mp); } STATIC uint xfs_calc_icreate_reservation(xfs_mount_t *mp) { return XFS_DQUOT_LOGRES(mp) + max(xfs_calc_icreate_resv_alloc(mp), xfs_calc_create_resv_modify(mp)); } STATIC uint xfs_calc_create_tmpfile_reservation( struct xfs_mount *mp) { uint res = XFS_DQUOT_LOGRES(mp); res += xfs_calc_icreate_resv_alloc(mp); return res + xfs_calc_iunlink_add_reservation(mp); } /* * Making a new directory is the same as creating a new file. */ STATIC uint xfs_calc_mkdir_reservation( struct xfs_mount *mp) { return xfs_calc_icreate_reservation(mp); } /* * Making a new symplink is the same as creating a new file, but * with the added blocks for remote symlink data which can be up to 1kB in * length (XFS_SYMLINK_MAXLEN). */ STATIC uint xfs_calc_symlink_reservation( struct xfs_mount *mp) { return xfs_calc_icreate_reservation(mp) + xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN); } /* * In freeing an inode we can modify: * the inode being freed: inode size * the super block free inode counter, AGF and AGFL: sector size * the on disk inode (agi unlinked list removal) * the inode chunk (invalidated, headers only) * the inode btree * the finobt (record insertion, removal or modification) * * Note that the inode chunk res. includes an allocfree res. for freeing of the * inode chunk. This is technically extraneous because the inode chunk free is * deferred (it occurs after a transaction roll). Include the extra reservation * anyways since we've had reports of ifree transaction overruns due to too many * agfl fixups during inode chunk frees. */ STATIC uint xfs_calc_ifree_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_iunlink_remove_reservation(mp) + xfs_calc_inode_chunk_res(mp, _FREE) + xfs_calc_inobt_res(mp) + xfs_calc_finobt_res(mp); } /* * When only changing the inode we log the inode and possibly the superblock * We also add a bit of slop for the transaction stuff. */ STATIC uint xfs_calc_ichange_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } /* * Growing the data section of the filesystem. * superblock * agi and agf * allocation btrees */ STATIC uint xfs_calc_growdata_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * Growing the rt section of the filesystem. * In the first set of transactions (ALLOC) we allocate space to the * bitmap or summary files. * superblock: sector size * agf of the ag from which the extent is allocated: sector size * bmap btree for bitmap/summary inode: max depth * blocksize * bitmap/summary inode: inode size * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize */ STATIC uint xfs_calc_growrtalloc_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), XFS_FSB_TO_B(mp, 1)) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * Growing the rt section of the filesystem. * In the second set of transactions (ZERO) we zero the new metadata blocks. * one bitmap/summary block: blocksize */ STATIC uint xfs_calc_growrtzero_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_blocksize); } /* * Growing the rt section of the filesystem. * In the third set of transactions (FREE) we update metadata without * allocating any new blocks. * superblock: sector size * bitmap inode: inode size * summary inode: inode size * one bitmap block: blocksize * summary blocks: new summary size */ STATIC uint xfs_calc_growrtfree_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) + xfs_calc_buf_res(1, mp->m_rsumsize); } /* * Logging the inode modification timestamp on a synchronous write. * inode */ STATIC uint xfs_calc_swrite_reservation( struct xfs_mount *mp) { return xfs_calc_inode_res(mp, 1); } /* * Logging the inode mode bits when writing a setuid/setgid file * inode */ STATIC uint xfs_calc_writeid_reservation( struct xfs_mount *mp) { return xfs_calc_inode_res(mp, 1); } /* * Converting the inode from non-attributed to attributed. * the inode being converted: inode size * agf block and superblock (for block allocation) * the new block (directory sized) * bmap blocks for the new directory block * allocation btrees */ STATIC uint xfs_calc_addafork_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(1, mp->m_dir_geo->blksize) + xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * Removing the attribute fork of a file * the inode being truncated: inode size * the inode's bmap btree: max depth * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrinval_reservation( struct xfs_mount *mp) { return max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4), XFS_FSB_TO_B(mp, 1)))); } /* * Setting an attribute at mount time. * the inode getting the attribute * the superblock for allocations * the agfs extents are allocated from * the attribute btree * max depth * the inode allocation btree * Since attribute transaction space is dependent on the size of the attribute, * the calculation is done partially at mount time and partially at runtime(see * below). */ STATIC uint xfs_calc_attrsetm_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1)); } /* * Setting an attribute at runtime, transaction space unit per block. * the superblock for allocations: sector size * the inode bmap btree could join or split: max depth * block size * Since the runtime attribute transaction space is dependent on the total * blocks needed for the 1st bmap, here we calculate out the space unit for * one block so that the caller could figure out the total space according * to the attibute extent length in blocks by: * ext * M_RES(mp)->tr_attrsetrt.tr_logres */ STATIC uint xfs_calc_attrsetrt_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1)); } /* * Removing an attribute. * the inode: inode size * the attribute btree could join: max depth * block size * the inode bmap btree could join or split: max depth * block size * And the bmap_finish transaction can free the attr blocks freed giving: * the agf for the ag in which the blocks live: 2 * sector size * the agfl for the ag in which the blocks live: 2 * sector size * the superblock for the free block count: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrrm_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1)) + (uint)XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)), (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), XFS_FSB_TO_B(mp, 1)))); } /* * Clearing a bad agino number in an agi hash bucket. */ STATIC uint xfs_calc_clear_agi_bucket_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } /* * Adjusting quota limits. * the xfs_disk_dquot_t: sizeof(struct xfs_disk_dquot) */ STATIC uint xfs_calc_qm_setqlim_reservation(void) { return xfs_calc_buf_res(1, sizeof(struct xfs_disk_dquot)); } /* * Allocating quota on disk if needed. * the write transaction log space for quota file extent allocation * the unit of quota allocation: one system block size */ STATIC uint xfs_calc_qm_dqalloc_reservation( struct xfs_mount *mp) { return xfs_calc_write_reservation(mp) + xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1); } /* * Turning off quotas. * the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2 * the superblock for the quota flags: sector size */ STATIC uint xfs_calc_qm_quotaoff_reservation( struct xfs_mount *mp) { return sizeof(struct xfs_qoff_logitem) * 2 + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } /* * End of turning off quotas. * the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2 */ STATIC uint xfs_calc_qm_quotaoff_end_reservation(void) { return sizeof(struct xfs_qoff_logitem) * 2; } /* * Syncing the incore super block changes to disk. * the super block to reflect the changes: sector size */ STATIC uint xfs_calc_sb_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } void xfs_trans_resv_calc( struct xfs_mount *mp, struct xfs_trans_resv *resp) { /* * The following transactions are logged in physical format and * require a permanent reservation on space. */ resp->tr_write.tr_logres = xfs_calc_write_reservation(mp); if (xfs_sb_version_hasreflink(&mp->m_sb)) resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK; else resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT; resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp); if (xfs_sb_version_hasreflink(&mp->m_sb)) resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT_REFLINK; else resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT; resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT; resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT; resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT; resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp); resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_create_tmpfile.tr_logres = xfs_calc_create_tmpfile_reservation(mp); resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp); resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT; resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_addafork.tr_logres = xfs_calc_addafork_reservation(mp); resp->tr_addafork.tr_logcount = XFS_ADDAFORK_LOG_COUNT; resp->tr_addafork.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_attrinval.tr_logres = xfs_calc_attrinval_reservation(mp); resp->tr_attrinval.tr_logcount = XFS_ATTRINVAL_LOG_COUNT; resp->tr_attrinval.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_attrsetm.tr_logres = xfs_calc_attrsetm_reservation(mp); resp->tr_attrsetm.tr_logcount = XFS_ATTRSET_LOG_COUNT; resp->tr_attrsetm.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_attrrm.tr_logres = xfs_calc_attrrm_reservation(mp); resp->tr_attrrm.tr_logcount = XFS_ATTRRM_LOG_COUNT; resp->tr_attrrm.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_growrtalloc.tr_logres = xfs_calc_growrtalloc_reservation(mp); resp->tr_growrtalloc.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT; resp->tr_growrtalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_qm_dqalloc.tr_logres = xfs_calc_qm_dqalloc_reservation(mp); if (xfs_sb_version_hasreflink(&mp->m_sb)) resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK; else resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; /* * The following transactions are logged in logical format with * a default log count. */ resp->tr_qm_setqlim.tr_logres = xfs_calc_qm_setqlim_reservation(); resp->tr_qm_setqlim.tr_logcount = XFS_DEFAULT_LOG_COUNT; resp->tr_qm_quotaoff.tr_logres = xfs_calc_qm_quotaoff_reservation(mp); resp->tr_qm_quotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT; resp->tr_qm_equotaoff.tr_logres = xfs_calc_qm_quotaoff_end_reservation(); resp->tr_qm_equotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT; resp->tr_sb.tr_logres = xfs_calc_sb_reservation(mp); resp->tr_sb.tr_logcount = XFS_DEFAULT_LOG_COUNT; /* growdata requires permanent res; it can free space to the last AG */ resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp); resp->tr_growdata.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT; resp->tr_growdata.tr_logflags |= XFS_TRANS_PERM_LOG_RES; /* The following transaction are logged in logical format */ resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp); resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp); resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp); resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp); resp->tr_clearagi.tr_logres = xfs_calc_clear_agi_bucket_reservation(mp); resp->tr_growrtzero.tr_logres = xfs_calc_growrtzero_reservation(mp); resp->tr_growrtfree.tr_logres = xfs_calc_growrtfree_reservation(mp); } xfsprogs-5.3.0/libxfs/xfs_trans_resv.h0000644000175000017500000000743413435336036017770 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_TRANS_RESV_H__ #define __XFS_TRANS_RESV_H__ struct xfs_mount; /* * structure for maintaining pre-calculated transaction reservations. */ struct xfs_trans_res { uint tr_logres; /* log space unit in bytes per log ticket */ int tr_logcount; /* number of log operations per log ticket */ int tr_logflags; /* log flags, currently only used for indicating * a reservation request is permanent or not */ }; struct xfs_trans_resv { struct xfs_trans_res tr_write; /* extent alloc trans */ struct xfs_trans_res tr_itruncate; /* truncate trans */ struct xfs_trans_res tr_rename; /* rename trans */ struct xfs_trans_res tr_link; /* link trans */ struct xfs_trans_res tr_remove; /* unlink trans */ struct xfs_trans_res tr_symlink; /* symlink trans */ struct xfs_trans_res tr_create; /* create trans */ struct xfs_trans_res tr_create_tmpfile; /* create O_TMPFILE trans */ struct xfs_trans_res tr_mkdir; /* mkdir trans */ struct xfs_trans_res tr_ifree; /* inode free trans */ struct xfs_trans_res tr_ichange; /* inode update trans */ struct xfs_trans_res tr_growdata; /* fs data section grow trans */ struct xfs_trans_res tr_addafork; /* add inode attr fork trans */ struct xfs_trans_res tr_writeid; /* write setuid/setgid file */ struct xfs_trans_res tr_attrinval; /* attr fork buffer * invalidation */ struct xfs_trans_res tr_attrsetm; /* set/create an attribute at * mount time */ struct xfs_trans_res tr_attrsetrt; /* set/create an attribute at * runtime */ struct xfs_trans_res tr_attrrm; /* remove an attribute */ struct xfs_trans_res tr_clearagi; /* clear agi unlinked bucket */ struct xfs_trans_res tr_growrtalloc; /* grow realtime allocations */ struct xfs_trans_res tr_growrtzero; /* grow realtime zeroing */ struct xfs_trans_res tr_growrtfree; /* grow realtime freeing */ struct xfs_trans_res tr_qm_setqlim; /* adjust quota limits */ struct xfs_trans_res tr_qm_dqalloc; /* allocate quota on disk */ struct xfs_trans_res tr_qm_quotaoff; /* turn quota off */ struct xfs_trans_res tr_qm_equotaoff;/* end of turn quota off */ struct xfs_trans_res tr_sb; /* modify superblock */ struct xfs_trans_res tr_fsyncts; /* update timestamps on fsync */ }; /* shorthand way of accessing reservation structure */ #define M_RES(mp) (&(mp)->m_resv) /* * Per-directory log reservation for any directory change. * dir blocks: (1 btree block per level + data block + free block) * dblock size * bmap btree: (levels + 2) * max depth * block size * v2 directory blocks can be fragmented below the dirblksize down to the fsb * size, so account for that in the DAENTER macros. */ #define XFS_DIROP_LOG_RES(mp) \ (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) #define XFS_DIROP_LOG_COUNT(mp) \ (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) /* * Various log count values. */ #define XFS_DEFAULT_LOG_COUNT 1 #define XFS_DEFAULT_PERM_LOG_COUNT 2 #define XFS_ITRUNCATE_LOG_COUNT 2 #define XFS_ITRUNCATE_LOG_COUNT_REFLINK 8 #define XFS_INACTIVE_LOG_COUNT 2 #define XFS_CREATE_LOG_COUNT 2 #define XFS_CREATE_TMPFILE_LOG_COUNT 2 #define XFS_MKDIR_LOG_COUNT 3 #define XFS_SYMLINK_LOG_COUNT 3 #define XFS_REMOVE_LOG_COUNT 2 #define XFS_LINK_LOG_COUNT 2 #define XFS_RENAME_LOG_COUNT 2 #define XFS_WRITE_LOG_COUNT 2 #define XFS_WRITE_LOG_COUNT_REFLINK 8 #define XFS_ADDAFORK_LOG_COUNT 2 #define XFS_ATTRINVAL_LOG_COUNT 1 #define XFS_ATTRSET_LOG_COUNT 3 #define XFS_ATTRRM_LOG_COUNT 3 void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp); uint xfs_allocfree_log_count(struct xfs_mount *mp, uint num_ops); #endif /* __XFS_TRANS_RESV_H__ */ xfsprogs-5.3.0/libxfs/xfs_trans_space.h0000644000175000017500000000732413570057155020104 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_TRANS_SPACE_H__ #define __XFS_TRANS_SPACE_H__ /* * Components of space reservations. */ /* Worst case number of rmaps that can be held in a block. */ #define XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) \ (((mp)->m_rmap_mxr[0]) - ((mp)->m_rmap_mnr[0])) /* Adding one rmap could split every level up to the top of the tree. */ #define XFS_RMAPADD_SPACE_RES(mp) ((mp)->m_rmap_maxlevels) /* Blocks we might need to add "b" rmaps to a tree. */ #define XFS_NRMAPADD_SPACE_RES(mp, b)\ (((b + XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) - 1) / \ XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)) * \ XFS_RMAPADD_SPACE_RES(mp)) #define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) \ (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0])) #define XFS_EXTENTADD_SPACE_RES(mp,w) (XFS_BM_MAXLEVELS(mp,w) - 1) #define XFS_NEXTENTADD_SPACE_RES(mp,b,w)\ (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ XFS_EXTENTADD_SPACE_RES(mp,w)) /* Blocks we might need to add "b" mappings & rmappings to a file. */ #define XFS_SWAP_RMAP_SPACE_RES(mp,b,w)\ (XFS_NEXTENTADD_SPACE_RES((mp), (b), (w)) + \ XFS_NRMAPADD_SPACE_RES((mp), (b))) #define XFS_DAENTER_1B(mp,w) \ ((w) == XFS_DATA_FORK ? (mp)->m_dir_geo->fsbcount : 1) #define XFS_DAENTER_DBS(mp,w) \ (XFS_DA_NODE_MAXDEPTH + (((w) == XFS_DATA_FORK) ? 2 : 0)) #define XFS_DAENTER_BLOCKS(mp,w) \ (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) #define XFS_DAENTER_BMAP1B(mp,w) \ XFS_NEXTENTADD_SPACE_RES(mp, XFS_DAENTER_1B(mp, w), w) #define XFS_DAENTER_BMAPS(mp,w) \ (XFS_DAENTER_DBS(mp,w) * XFS_DAENTER_BMAP1B(mp,w)) #define XFS_DAENTER_SPACE_RES(mp,w) \ (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) #define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) #define XFS_DIRENTER_MAX_SPLIT(mp,nl) 1 #define XFS_DIRENTER_SPACE_RES(mp,nl) \ (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ XFS_DIRENTER_MAX_SPLIT(mp,nl)) #define XFS_DIRREMOVE_SPACE_RES(mp) \ XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) #define XFS_IALLOC_SPACE_RES(mp) \ (M_IGEO(mp)->ialloc_blks + \ (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \ (M_IGEO(mp)->inobt_maxlevels - 1))) /* * Space reservation values for various transactions. */ #define XFS_ADDAFORK_SPACE_RES(mp) \ ((mp)->m_dir_geo->fsbcount + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK)) #define XFS_ATTRRM_SPACE_RES(mp) \ XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) /* This macro is not used - see inline code in xfs_attr_set */ #define XFS_ATTRSET_SPACE_RES(mp, v) \ (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) #define XFS_CREATE_SPACE_RES(mp,nl) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_DIOSTRAT_SPACE_RES(mp, v) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) #define XFS_GROWFS_SPACE_RES(mp) \ (2 * (mp)->m_ag_maxlevels) #define XFS_GROWFSRT_SPACE_RES(mp,b) \ ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) #define XFS_LINK_SPACE_RES(mp,nl) \ XFS_DIRENTER_SPACE_RES(mp,nl) #define XFS_MKDIR_SPACE_RES(mp,nl) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) #define XFS_REMOVE_SPACE_RES(mp) \ XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_sb_version_hasfinobt(&mp->m_sb) ? \ M_IGEO(mp)->inobt_maxlevels : 0) #endif /* __XFS_TRANS_SPACE_H__ */ xfsprogs-5.3.0/libxfs/xfs_types.c0000644000175000017500000001124313570057155016734 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * Copyright (C) 2017 Oracle. * All Rights Reserved. */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_shared.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" /* Find the size of the AG, in blocks. */ xfs_agblock_t xfs_ag_block_count( struct xfs_mount *mp, xfs_agnumber_t agno) { ASSERT(agno < mp->m_sb.sb_agcount); if (agno < mp->m_sb.sb_agcount - 1) return mp->m_sb.sb_agblocks; return mp->m_sb.sb_dblocks - (agno * mp->m_sb.sb_agblocks); } /* * Verify that an AG block number pointer neither points outside the AG * nor points at static metadata. */ bool xfs_verify_agbno( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) { xfs_agblock_t eoag; eoag = xfs_ag_block_count(mp, agno); if (agbno >= eoag) return false; if (agbno <= XFS_AGFL_BLOCK(mp)) return false; return true; } /* * Verify that an FS block number pointer neither points outside the * filesystem nor points at static AG metadata. */ bool xfs_verify_fsbno( struct xfs_mount *mp, xfs_fsblock_t fsbno) { xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); if (agno >= mp->m_sb.sb_agcount) return false; return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno)); } /* Calculate the first and last possible inode number in an AG. */ void xfs_agino_range( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t *first, xfs_agino_t *last) { xfs_agblock_t bno; xfs_agblock_t eoag; eoag = xfs_ag_block_count(mp, agno); /* * Calculate the first inode, which will be in the first * cluster-aligned block after the AGFL. */ bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align); *first = XFS_AGB_TO_AGINO(mp, bno); /* * Calculate the last inode, which will be at the end of the * last (aligned) cluster that can be allocated in the AG. */ bno = round_down(eoag, M_IGEO(mp)->cluster_align); *last = XFS_AGB_TO_AGINO(mp, bno) - 1; } /* * Verify that an AG inode number pointer neither points outside the AG * nor points at static metadata. */ bool xfs_verify_agino( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino) { xfs_agino_t first; xfs_agino_t last; xfs_agino_range(mp, agno, &first, &last); return agino >= first && agino <= last; } /* * Verify that an AG inode number pointer neither points outside the AG * nor points at static metadata, or is NULLAGINO. */ bool xfs_verify_agino_or_null( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino) { return agino == NULLAGINO || xfs_verify_agino(mp, agno, agino); } /* * Verify that an FS inode number pointer neither points outside the * filesystem nor points at static AG metadata. */ bool xfs_verify_ino( struct xfs_mount *mp, xfs_ino_t ino) { xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ino); xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino); if (agno >= mp->m_sb.sb_agcount) return false; if (XFS_AGINO_TO_INO(mp, agno, agino) != ino) return false; return xfs_verify_agino(mp, agno, agino); } /* Is this an internal inode number? */ bool xfs_internal_inum( struct xfs_mount *mp, xfs_ino_t ino) { return ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || (xfs_sb_version_hasquota(&mp->m_sb) && xfs_is_quota_inode(&mp->m_sb, ino)); } /* * Verify that a directory entry's inode number doesn't point at an internal * inode, empty space, or static AG metadata. */ bool xfs_verify_dir_ino( struct xfs_mount *mp, xfs_ino_t ino) { if (xfs_internal_inum(mp, ino)) return false; return xfs_verify_ino(mp, ino); } /* * Verify that an realtime block number pointer doesn't point off the * end of the realtime device. */ bool xfs_verify_rtbno( struct xfs_mount *mp, xfs_rtblock_t rtbno) { return rtbno < mp->m_sb.sb_rblocks; } /* Calculate the range of valid icount values. */ void xfs_icount_range( struct xfs_mount *mp, unsigned long long *min, unsigned long long *max) { unsigned long long nr_inos = 0; xfs_agnumber_t agno; /* root, rtbitmap, rtsum all live in the first chunk */ *min = XFS_INODES_PER_CHUNK; for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { xfs_agino_t first, last; xfs_agino_range(mp, agno, &first, &last); nr_inos += last - first + 1; } *max = nr_inos; } /* Sanity-checking of inode counts. */ bool xfs_verify_icount( struct xfs_mount *mp, unsigned long long icount) { unsigned long long min, max; xfs_icount_range(mp, &min, &max); return icount >= min && icount <= max; } /* Sanity-checking of dir/attr block offsets. */ bool xfs_verify_dablk( struct xfs_mount *mp, xfs_fileoff_t dabno) { xfs_dablk_t max_dablk = -1U; return dabno <= max_dablk; } xfsprogs-5.3.0/libxfs/xfs_types.h0000644000175000017500000001425313570057155016745 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __XFS_TYPES_H__ #define __XFS_TYPES_H__ typedef uint32_t prid_t; /* project ID */ typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */ typedef uint32_t xfs_agino_t; /* inode # within allocation grp */ typedef uint32_t xfs_extlen_t; /* extent length in blocks */ typedef uint32_t xfs_agnumber_t; /* allocation group number */ typedef int32_t xfs_extnum_t; /* # of extents in a file */ typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */ typedef int64_t xfs_fsize_t; /* bytes in a file */ typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */ typedef uint32_t xfs_rtword_t; /* word type for bitmap manipulations */ typedef int64_t xfs_lsn_t; /* log sequence number */ typedef int32_t xfs_tid_t; /* transaction identifier */ typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ typedef uint32_t xfs_dahash_t; /* dir/attr hash value */ typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ typedef uint64_t xfs_fileoff_t; /* block number in a file */ typedef uint64_t xfs_filblks_t; /* number of blocks in a file */ typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ typedef int64_t xfs_sfiloff_t; /* signed block number in a file */ /* * New verifiers will return the instruction address of the failing check. * NULL means everything is ok. */ typedef void * xfs_failaddr_t; /* * Null values for the types. */ #define NULLFSBLOCK ((xfs_fsblock_t)-1) #define NULLRFSBLOCK ((xfs_rfsblock_t)-1) #define NULLRTBLOCK ((xfs_rtblock_t)-1) #define NULLFILEOFF ((xfs_fileoff_t)-1) #define NULLAGBLOCK ((xfs_agblock_t)-1) #define NULLAGNUMBER ((xfs_agnumber_t)-1) #define NULLCOMMITLSN ((xfs_lsn_t)-1) #define NULLFSINO ((xfs_ino_t)-1) #define NULLAGINO ((xfs_agino_t)-1) /* * Max values for extlen, extnum, aextnum. */ #define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ #define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ #define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ /* * Minimum and maximum blocksize and sectorsize. * The blocksize upper limit is pretty much arbitrary. * The sectorsize upper limit is due to sizeof(sb_sectsize). * CRC enable filesystems use 512 byte inodes, meaning 512 byte block sizes * cannot be used. */ #define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ #define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ #define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) #define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) #define XFS_MIN_CRC_BLOCKSIZE (1 << (XFS_MIN_BLOCKSIZE_LOG + 1)) #define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ #define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ #define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) #define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) /* * Inode fork identifiers. */ #define XFS_DATA_FORK 0 #define XFS_ATTR_FORK 1 #define XFS_COW_FORK 2 /* * Min numbers of data/attr fork btree root pointers. */ #define MINDBTPTRS 3 #define MINABTPTRS 2 /* * MAXNAMELEN is the length (including the terminating null) of * the longest permissible file (component) name. */ #define MAXNAMELEN 256 /* * This enum is used in string mapping in xfs_trace.h; please keep the * TRACE_DEFINE_ENUMs for it up to date. */ typedef enum { XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi } xfs_lookup_t; #define XFS_AG_BTREE_CMP_FORMAT_STR \ { XFS_LOOKUP_EQi, "eq" }, \ { XFS_LOOKUP_LEi, "le" }, \ { XFS_LOOKUP_GEi, "ge" } /* * This enum is used in string mapping in xfs_trace.h and scrub/trace.h; * please keep the TRACE_DEFINE_ENUMs for it up to date. */ typedef enum { XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_RMAPi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, XFS_BTNUM_FINOi, XFS_BTNUM_REFCi, XFS_BTNUM_MAX } xfs_btnum_t; #define XFS_BTNUM_STRINGS \ { XFS_BTNUM_BNOi, "bnobt" }, \ { XFS_BTNUM_CNTi, "cntbt" }, \ { XFS_BTNUM_RMAPi, "rmapbt" }, \ { XFS_BTNUM_BMAPi, "bmbt" }, \ { XFS_BTNUM_INOi, "inobt" }, \ { XFS_BTNUM_FINOi, "finobt" }, \ { XFS_BTNUM_REFCi, "refcbt" } struct xfs_name { const unsigned char *name; int len; int type; }; /* * uid_t and gid_t are hard-coded to 32 bits in the inode. * Hence, an 'id' in a dquot is 32 bits.. */ typedef uint32_t xfs_dqid_t; /* * Constants for bit manipulations. */ #define XFS_NBBYLOG 3 /* log2(NBBY) */ #define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ #define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) #define XFS_NBWORD (1 << XFS_NBWORDLOG) #define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) struct xfs_iext_cursor { struct xfs_iext_leaf *leaf; int pos; }; typedef enum { XFS_EXT_NORM, XFS_EXT_UNWRITTEN, } xfs_exntst_t; typedef struct xfs_bmbt_irec { xfs_fileoff_t br_startoff; /* starting file offset */ xfs_fsblock_t br_startblock; /* starting block number */ xfs_filblks_t br_blockcount; /* number of blocks */ xfs_exntst_t br_state; /* extent state */ } xfs_bmbt_irec_t; /* * Type verifier functions */ struct xfs_mount; xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno); bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t *first, xfs_agino_t *last); bool xfs_verify_agino(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino); bool xfs_verify_agino_or_null(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino); bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno); bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount); bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off); void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min, unsigned long long *max); #endif /* __XFS_TYPES_H__ */ xfsprogs-5.3.0/libxlog/Makefile0000644000175000017500000000066013435336036016354 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTLIBRARY = libxlog.la LT_CURRENT = 0 LT_REVISION = 0 LT_AGE = 0 CFILES = xfs_log_recover.c util.c # don't want to link xfs_repair with a debug libxlog. DEBUG = -DNDEBUG default: ltdepend $(LTLIBRARY) include $(BUILDRULES) install install-dev: default -include .ltdep xfsprogs-5.3.0/libxlog/util.c0000644000175000017500000000756713435336037016053 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" int print_exit; int print_skip_uuid; int print_record_header; libxfs_init_t x; /* * Return 1 for dirty, 0 for clean, -1 for errors */ int xlog_is_dirty( struct xfs_mount *mp, struct xlog *log, libxfs_init_t *x, int verbose) { int error; xfs_daddr_t head_blk, tail_blk; memset(log, 0, sizeof(*log)); /* We (re-)init members of libxfs_init_t here? really? */ x->logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); x->logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); x->lbsize = BBSIZE; if (xfs_sb_version_hassector(&mp->m_sb)) x->lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT); log->l_dev = mp->m_logdev_targp; log->l_logBBsize = x->logBBsize; log->l_logBBstart = x->logBBstart; log->l_sectBBsize = BTOBB(x->lbsize); log->l_mp = mp; if (xfs_sb_version_hassector(&mp->m_sb)) { log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; ASSERT(log->l_sectbb_log <= mp->m_sectbb_log); /* for larger sector sizes, must have v2 or external log */ ASSERT(log->l_sectbb_log == 0 || log->l_logBBstart == 0 || xfs_sb_version_haslogv2(&mp->m_sb)); ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); } log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1; error = xlog_find_tail(log, &head_blk, &tail_blk); if (error) { xlog_warn(_("%s: cannot find log head/tail " "(xlog_find_tail=%d)\n"), __func__, error); return -1; } if (verbose) xlog_warn( _("%s: head block %" PRId64 " tail block %" PRId64 "\n"), __func__, head_blk, tail_blk); if (head_blk != tail_blk) return 1; return 0; } static int header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head) { char uu_log[64], uu_sb[64]; if (print_skip_uuid) return 0; if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) return 0; platform_uuid_unparse(&mp->m_sb.sb_uuid, uu_sb); platform_uuid_unparse(&head->h_fs_uuid, uu_log); printf(_("* ERROR: mismatched uuid in log\n" "* SB : %s\n* log: %s\n"), uu_sb, uu_log); memcpy(&mp->m_sb.sb_uuid, &head->h_fs_uuid, sizeof(uuid_t)); return 0; } int xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head) { if (print_record_header) printf(_("\nLOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n"), CYCLE_LSN(be64_to_cpu(head->h_lsn)), BLOCK_LSN(be64_to_cpu(head->h_lsn)), CYCLE_LSN(be64_to_cpu(head->h_lsn)), BLOCK_LSN(be64_to_cpu(head->h_lsn))); if (be32_to_cpu(head->h_magicno) != XLOG_HEADER_MAGIC_NUM) { printf(_("* ERROR: bad magic number in log header: 0x%x\n"), be32_to_cpu(head->h_magicno)); } else if (header_check_uuid(mp, head)) { /* failed - fall through */ } else if (be32_to_cpu(head->h_fmt) != XLOG_FMT) { printf(_("* ERROR: log format incompatible (log=%d, ours=%d)\n"), be32_to_cpu(head->h_fmt), XLOG_FMT); } else { /* everything is ok */ return 0; } /* bail out now or just carry on regardless */ if (print_exit) xlog_exit(_("Bad log")); return 0; } int xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head) { if (platform_uuid_is_null(&head->h_fs_uuid)) return 0; if (header_check_uuid(mp, head)) { /* bail out now or just carry on regardless */ if (print_exit) xlog_exit(_("Bad log")); } return 0; } /* * Userspace versions of common diagnostic routines (varargs fun). */ void xlog_warn(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); } void xlog_exit(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); exit(1); } void xlog_panic(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); abort(); } xfsprogs-5.3.0/libxlog/xfs_log_recover.c0000644000175000017500000013260413435336037020253 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #define xfs_readonly_buftarg(buftarg) (0) /* avoid set-but-unused var warning. gcc is not very bright. */ #define xlog_clear_stale_blocks(log, taillsn) ({ \ (taillsn) = (taillsn); \ (0); \ }) #define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) /* * Verify the given count of basic blocks is valid number of blocks * to specify for an operation involving the given XFS log buffer. * Returns nonzero if the count is valid, 0 otherwise. */ static inline int xlog_buf_bbcount_valid( struct xlog *log, int bbcount) { return bbcount > 0 && bbcount <= log->l_logBBsize; } /* * Allocate a buffer to hold log data. The buffer needs to be able * to map to a range of nbblks basic blocks at any valid (basic * block) offset within the log. */ xfs_buf_t * xlog_get_bp( struct xlog *log, int nbblks) { if (!xlog_buf_bbcount_valid(log, nbblks)) { xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", nbblks); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); return NULL; } /* * We do log I/O in units of log sectors (a power-of-2 * multiple of the basic block size), so we round up the * requested size to accommodate the basic blocks required * for complete log sectors. * * In addition, the buffer may be used for a non-sector- * aligned block offset, in which case an I/O of the * requested size could extend beyond the end of the * buffer. If the requested size is only 1 basic block it * will never straddle a sector boundary, so this won't be * an issue. Nor will this be a problem if the log I/O is * done in basic blocks (sector size 1). But otherwise we * extend the buffer by one extra log sector to ensure * there's space to accommodate this possibility. */ if (nbblks > 1 && log->l_sectBBsize > 1) nbblks += log->l_sectBBsize; nbblks = round_up(nbblks, log->l_sectBBsize); return libxfs_getbufr(log->l_dev, (xfs_daddr_t)-1, nbblks); } void xlog_put_bp( xfs_buf_t *bp) { libxfs_putbufr(bp); } /* * Return the address of the start of the given block number's data * in a log buffer. The buffer covers a log sector-aligned region. */ STATIC char * xlog_align( struct xlog *log, xfs_daddr_t blk_no, int nbblks, struct xfs_buf *bp) { xfs_daddr_t offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1); ASSERT(offset + nbblks <= bp->b_length); return bp->b_addr + BBTOB(offset); } /* * nbblks should be uint, but oh well. Just want to catch that 32-bit length. */ int xlog_bread_noalign( struct xlog *log, xfs_daddr_t blk_no, int nbblks, struct xfs_buf *bp) { if (!xlog_buf_bbcount_valid(log, nbblks)) { xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", nbblks); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); return EFSCORRUPTED; } blk_no = round_down(blk_no, log->l_sectBBsize); nbblks = round_up(nbblks, log->l_sectBBsize); ASSERT(nbblks > 0); ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); bp->b_bcount = BBTOB(nbblks); bp->b_error = 0; return libxfs_readbufr(log->l_dev, XFS_BUF_ADDR(bp), bp, nbblks, 0); } int xlog_bread( struct xlog *log, xfs_daddr_t blk_no, int nbblks, struct xfs_buf *bp, char **offset) { int error; error = xlog_bread_noalign(log, blk_no, nbblks, bp); if (error) return error; *offset = xlog_align(log, blk_no, nbblks, bp); return 0; } /* * Read at an offset into the buffer. Returns with the buffer in it's original * state regardless of the result of the read. */ STATIC int xlog_bread_offset( struct xlog *log, xfs_daddr_t blk_no, /* block to read from */ int nbblks, /* blocks to read */ struct xfs_buf *bp, char *offset) { char *orig_offset = bp->b_addr; int orig_len = bp->b_bcount; int error, error2; error = xfs_buf_associate_memory(bp, offset, BBTOB(nbblks)); if (error) return error; error = xlog_bread_noalign(log, blk_no, nbblks, bp); /* must reset buffer pointer even on error */ error2 = xfs_buf_associate_memory(bp, orig_offset, orig_len); if (error) return error; return error2; } /* * This routine finds (to an approximation) the first block in the physical * log which contains the given cycle. It uses a binary search algorithm. * Note that the algorithm can not be perfect because the disk will not * necessarily be perfect. */ int xlog_find_cycle_start( struct xlog *log, struct xfs_buf *bp, xfs_daddr_t first_blk, xfs_daddr_t *last_blk, uint cycle) { char *offset; xfs_daddr_t mid_blk; xfs_daddr_t end_blk; uint mid_cycle; int error; end_blk = *last_blk; mid_blk = BLK_AVG(first_blk, end_blk); while (mid_blk != first_blk && mid_blk != end_blk) { error = xlog_bread(log, mid_blk, 1, bp, &offset); if (error) return error; mid_cycle = xlog_get_cycle(offset); if (mid_cycle == cycle) end_blk = mid_blk; /* last_half_cycle == mid_cycle */ else first_blk = mid_blk; /* first_half_cycle == mid_cycle */ mid_blk = BLK_AVG(first_blk, end_blk); } ASSERT((mid_blk == first_blk && mid_blk+1 == end_blk) || (mid_blk == end_blk && mid_blk-1 == first_blk)); *last_blk = end_blk; return 0; } /* * Check that a range of blocks does not contain stop_on_cycle_no. * Fill in *new_blk with the block offset where such a block is * found, or with -1 (an invalid block number) if there is no such * block in the range. The scan needs to occur from front to back * and the pointer into the region must be updated since a later * routine will need to perform another test. */ STATIC int xlog_find_verify_cycle( struct xlog *log, xfs_daddr_t start_blk, int nbblks, uint stop_on_cycle_no, xfs_daddr_t *new_blk) { xfs_daddr_t i, j; uint cycle; xfs_buf_t *bp; int bufblks; char *buf = NULL; int error = 0; /* * Greedily allocate a buffer big enough to handle the full * range of basic blocks we'll be examining. If that fails, * try a smaller size. We need to be able to read at least * a log sector, or we're out of luck. */ bufblks = 1 << ffs(nbblks); while (bufblks > log->l_logBBsize) bufblks >>= 1; while (!(bp = xlog_get_bp(log, bufblks))) { bufblks >>= 1; if (bufblks < log->l_sectBBsize) return ENOMEM; } for (i = start_blk; i < start_blk + nbblks; i += bufblks) { int bcount; bcount = min(bufblks, (start_blk + nbblks - i)); error = xlog_bread(log, i, bcount, bp, &buf); if (error) goto out; for (j = 0; j < bcount; j++) { cycle = xlog_get_cycle(buf); if (cycle == stop_on_cycle_no) { *new_blk = i+j; goto out; } buf += BBSIZE; } } *new_blk = -1; out: xlog_put_bp(bp); return error; } /* * Potentially backup over partial log record write. * * In the typical case, last_blk is the number of the block directly after * a good log record. Therefore, we subtract one to get the block number * of the last block in the given buffer. extra_bblks contains the number * of blocks we would have read on a previous read. This happens when the * last log record is split over the end of the physical log. * * extra_bblks is the number of blocks potentially verified on a previous * call to this routine. */ STATIC int xlog_find_verify_log_record( struct xlog *log, xfs_daddr_t start_blk, xfs_daddr_t *last_blk, int extra_bblks) { xfs_daddr_t i; xfs_buf_t *bp; char *offset = NULL; xlog_rec_header_t *head = NULL; int error = 0; int smallmem = 0; int num_blks = *last_blk - start_blk; int xhdrs; ASSERT(start_blk != 0 || *last_blk != start_blk); if (!(bp = xlog_get_bp(log, num_blks))) { if (!(bp = xlog_get_bp(log, 1))) return ENOMEM; smallmem = 1; } else { error = xlog_bread(log, start_blk, num_blks, bp, &offset); if (error) goto out; offset += ((num_blks - 1) << BBSHIFT); } for (i = (*last_blk) - 1; i >= 0; i--) { if (i < start_blk) { /* valid log record not found */ xfs_warn(log->l_mp, "Log inconsistent (didn't find previous header)"); ASSERT(0); error = XFS_ERROR(EIO); goto out; } if (smallmem) { error = xlog_bread(log, i, 1, bp, &offset); if (error) goto out; } head = (xlog_rec_header_t *)offset; if (head->h_magicno == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) break; if (!smallmem) offset -= BBSIZE; } /* * We hit the beginning of the physical log & still no header. Return * to caller. If caller can handle a return of -1, then this routine * will be called again for the end of the physical log. */ if (i == -1) { error = -1; goto out; } /* * We have the final block of the good log (the first block * of the log record _before_ the head. So we check the uuid. */ if ((error = xlog_header_check_mount(log->l_mp, head))) goto out; /* * We may have found a log record header before we expected one. * last_blk will be the 1st block # with a given cycle #. We may end * up reading an entire log record. In this case, we don't want to * reset last_blk. Only when last_blk points in the middle of a log * record do we update last_blk. */ if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { uint h_size = be32_to_cpu(head->h_size); xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) xhdrs++; } else { xhdrs = 1; } if (*last_blk - i + extra_bblks != BTOBB(be32_to_cpu(head->h_len)) + xhdrs) *last_blk = i; out: xlog_put_bp(bp); return error; } /* * Head is defined to be the point of the log where the next log write * write could go. This means that incomplete LR writes at the end are * eliminated when calculating the head. We aren't guaranteed that previous * LR have complete transactions. We only know that a cycle number of * current cycle number -1 won't be present in the log if we start writing * from our current block number. * * last_blk contains the block number of the first block with a given * cycle number. * * Return: zero if normal, non-zero if error. */ STATIC int xlog_find_head( struct xlog *log, xfs_daddr_t *return_head_blk) { xfs_buf_t *bp; char *offset; xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk; int num_scan_bblks; uint first_half_cycle, last_half_cycle; uint stop_on_cycle; int error, log_bbnum = log->l_logBBsize; /* Is the end of the log device zeroed? */ if ((error = xlog_find_zeroed(log, &first_blk)) == -1) { *return_head_blk = first_blk; /* Is the whole lot zeroed? */ if (!first_blk) { /* Linux XFS shouldn't generate totally zeroed logs - * mkfs etc write a dummy unmount record to a fresh * log so we can store the uuid in there */ xfs_warn(log->l_mp, "totally zeroed log"); } return 0; } else if (error) { xfs_warn(log->l_mp, "empty log check failed"); return error; } first_blk = 0; /* get cycle # of 1st block */ bp = xlog_get_bp(log, 1); if (!bp) return ENOMEM; error = xlog_bread(log, 0, 1, bp, &offset); if (error) goto bp_err; first_half_cycle = xlog_get_cycle(offset); last_blk = head_blk = log_bbnum - 1; /* get cycle # of last block */ error = xlog_bread(log, last_blk, 1, bp, &offset); if (error) goto bp_err; last_half_cycle = xlog_get_cycle(offset); ASSERT(last_half_cycle != 0); /* * If the 1st half cycle number is equal to the last half cycle number, * then the entire log is stamped with the same cycle number. In this * case, head_blk can't be set to zero (which makes sense). The below * math doesn't work out properly with head_blk equal to zero. Instead, * we set it to log_bbnum which is an invalid block number, but this * value makes the math correct. If head_blk doesn't changed through * all the tests below, *head_blk is set to zero at the very end rather * than log_bbnum. In a sense, log_bbnum and zero are the same block * in a circular file. */ if (first_half_cycle == last_half_cycle) { /* * In this case we believe that the entire log should have * cycle number last_half_cycle. We need to scan backwards * from the end verifying that there are no holes still * containing last_half_cycle - 1. If we find such a hole, * then the start of that hole will be the new head. The * simple case looks like * x | x ... | x - 1 | x * Another case that fits this picture would be * x | x + 1 | x ... | x * In this case the head really is somewhere at the end of the * log, as one of the latest writes at the beginning was * incomplete. * One more case is * x | x + 1 | x ... | x - 1 | x * This is really the combination of the above two cases, and * the head has to end up at the start of the x-1 hole at the * end of the log. * * In the 256k log case, we will read from the beginning to the * end of the log and search for cycle numbers equal to x-1. * We don't worry about the x+1 blocks that we encounter, * because we know that they cannot be the head since the log * started with x. */ head_blk = log_bbnum; stop_on_cycle = last_half_cycle - 1; } else { /* * In this case we want to find the first block with cycle * number matching last_half_cycle. We expect the log to be * some variation on * x + 1 ... | x ... | x * The first block with cycle number x (last_half_cycle) will * be where the new head belongs. First we do a binary search * for the first occurrence of last_half_cycle. The binary * search may not be totally accurate, so then we scan back * from there looking for occurrences of last_half_cycle before * us. If that backwards scan wraps around the beginning of * the log, then we look for occurrences of last_half_cycle - 1 * at the end of the log. The cases we're looking for look * like * v binary search stopped here * x + 1 ... | x | x + 1 | x ... | x * ^ but we want to locate this spot * or * <---------> less than scan distance * x + 1 ... | x ... | x - 1 | x * ^ we want to locate this spot */ stop_on_cycle = last_half_cycle; if ((error = xlog_find_cycle_start(log, bp, first_blk, &head_blk, last_half_cycle))) goto bp_err; } /* * Now validate the answer. Scan back some number of maximum possible * blocks and make sure each one has the expected cycle number. The * maximum is determined by the total possible amount of buffering * in the in-core log. The following number can be made tighter if * we actually look at the block size of the filesystem. */ num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); if (head_blk >= num_scan_bblks) { /* * We are guaranteed that the entire check can be performed * in one buffer. */ start_blk = head_blk - num_scan_bblks; if ((error = xlog_find_verify_cycle(log, start_blk, num_scan_bblks, stop_on_cycle, &new_blk))) goto bp_err; if (new_blk != -1) head_blk = new_blk; } else { /* need to read 2 parts of log */ /* * We are going to scan backwards in the log in two parts. * First we scan the physical end of the log. In this part * of the log, we are looking for blocks with cycle number * last_half_cycle - 1. * If we find one, then we know that the log starts there, as * we've found a hole that didn't get written in going around * the end of the physical log. The simple case for this is * x + 1 ... | x ... | x - 1 | x * <---------> less than scan distance * If all of the blocks at the end of the log have cycle number * last_half_cycle, then we check the blocks at the start of * the log looking for occurrences of last_half_cycle. If we * find one, then our current estimate for the location of the * first occurrence of last_half_cycle is wrong and we move * back to the hole we've found. This case looks like * x + 1 ... | x | x + 1 | x ... * ^ binary search stopped here * Another case we need to handle that only occurs in 256k * logs is * x + 1 ... | x ... | x+1 | x ... * ^ binary search stops here * In a 256k log, the scan at the end of the log will see the * x + 1 blocks. We need to skip past those since that is * certainly not the head of the log. By searching for * last_half_cycle-1 we accomplish that. */ ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks >= head_blk); start_blk = log_bbnum - (num_scan_bblks - head_blk); if ((error = xlog_find_verify_cycle(log, start_blk, num_scan_bblks - (int)head_blk, (stop_on_cycle - 1), &new_blk))) goto bp_err; if (new_blk != -1) { head_blk = new_blk; goto validate_head; } /* * Scan beginning of log now. The last part of the physical * log is good. This scan needs to verify that it doesn't find * the last_half_cycle. */ start_blk = 0; ASSERT(head_blk <= INT_MAX); if ((error = xlog_find_verify_cycle(log, start_blk, (int)head_blk, stop_on_cycle, &new_blk))) goto bp_err; if (new_blk != -1) head_blk = new_blk; } validate_head: /* * Now we need to make sure head_blk is not pointing to a block in * the middle of a log record. */ num_scan_bblks = XLOG_REC_SHIFT(log); if (head_blk >= num_scan_bblks) { start_blk = head_blk - num_scan_bblks; /* don't read head_blk */ /* start ptr at last block ptr before head_blk */ if ((error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0)) == -1) { error = XFS_ERROR(EIO); goto bp_err; } else if (error) goto bp_err; } else { start_blk = 0; ASSERT(head_blk <= INT_MAX); if ((error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0)) == -1) { /* We hit the beginning of the log during our search */ start_blk = log_bbnum - (num_scan_bblks - head_blk); new_blk = log_bbnum; ASSERT(start_blk <= INT_MAX && (xfs_daddr_t) log_bbnum-start_blk >= 0); ASSERT(head_blk <= INT_MAX); if ((error = xlog_find_verify_log_record(log, start_blk, &new_blk, (int)head_blk)) == -1) { error = XFS_ERROR(EIO); goto bp_err; } else if (error) goto bp_err; if (new_blk != log_bbnum) head_blk = new_blk; } else if (error) goto bp_err; } xlog_put_bp(bp); if (head_blk == log_bbnum) *return_head_blk = 0; else *return_head_blk = head_blk; /* * When returning here, we have a good block number. Bad block * means that during a previous crash, we didn't have a clean break * from cycle number N to cycle number N-1. In this case, we need * to find the first block with cycle number N-1. */ return 0; bp_err: xlog_put_bp(bp); if (error) xfs_warn(log->l_mp, "failed to find log head"); return error; } /* * Find the sync block number or the tail of the log. * * This will be the block number of the last record to have its * associated buffers synced to disk. Every log record header has * a sync lsn embedded in it. LSNs hold block numbers, so it is easy * to get a sync block number. The only concern is to figure out which * log record header to believe. * * The following algorithm uses the log record header with the largest * lsn. The entire log record does not need to be valid. We only care * that the header is valid. * * We could speed up search by using current head_blk buffer, but it is not * available. */ int xlog_find_tail( struct xlog *log, xfs_daddr_t *head_blk, xfs_daddr_t *tail_blk) { xlog_rec_header_t *rhead; xlog_op_header_t *op_head; char *offset = NULL; xfs_buf_t *bp; int error, i, found; xfs_daddr_t umount_data_blk; xfs_daddr_t after_umount_blk; xfs_lsn_t tail_lsn; int hblks; found = 0; /* * Find previous log record */ if ((error = xlog_find_head(log, head_blk))) return error; bp = xlog_get_bp(log, 1); if (!bp) return ENOMEM; if (*head_blk == 0) { /* special case */ error = xlog_bread(log, 0, 1, bp, &offset); if (error) goto done; if (xlog_get_cycle(offset) == 0) { *tail_blk = 0; /* leave all other log inited values alone */ goto done; } } /* * Search backwards looking for log record header block */ ASSERT(*head_blk < INT_MAX); for (i = (int)(*head_blk) - 1; i >= 0; i--) { error = xlog_bread(log, i, 1, bp, &offset); if (error) goto done; if (*(__be32 *)offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) { found = 1; break; } } /* * If we haven't found the log record header block, start looking * again from the end of the physical log. XXXmiken: There should be * a check here to make sure we didn't search more than N blocks in * the previous code. */ if (!found) { for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) { error = xlog_bread(log, i, 1, bp, &offset); if (error) goto done; if (*(__be32 *)offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) { found = 2; break; } } } if (!found) { xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__); xlog_put_bp(bp); ASSERT(0); return XFS_ERROR(EIO); } /* find blk_no of tail of log */ rhead = (xlog_rec_header_t *)offset; *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn)); /* * Reset log values according to the state of the log when we * crashed. In the case where head_blk == 0, we bump curr_cycle * one because the next write starts a new cycle rather than * continuing the cycle of the last good log record. At this * point we have guaranteed that all partial log records have been * accounted for. Therefore, we know that the last good log record * written was complete and ended exactly on the end boundary * of the physical log. */ log->l_prev_block = i; log->l_curr_block = (int)*head_blk; log->l_curr_cycle = be32_to_cpu(rhead->h_cycle); if (found == 2) log->l_curr_cycle++; atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn)); atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn)); xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle, BBTOB(log->l_curr_block)); xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle, BBTOB(log->l_curr_block)); /* * Look for unmount record. If we find it, then we know there * was a clean unmount. Since 'i' could be the last block in * the physical log, we convert to a log block before comparing * to the head_blk. * * Save the current tail lsn to use to pass to * xlog_clear_stale_blocks() below. We won't want to clear the * unmount record if there is one, so we pass the lsn of the * unmount record rather than the block after it. */ if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { int h_size = be32_to_cpu(rhead->h_size); int h_version = be32_to_cpu(rhead->h_version); if ((h_version & XLOG_VERSION_2) && (h_size > XLOG_HEADER_CYCLE_SIZE)) { hblks = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) hblks++; } else { hblks = 1; } } else { hblks = 1; } after_umount_blk = (i + hblks + (int) BTOBB(be32_to_cpu(rhead->h_len))) % log->l_logBBsize; tail_lsn = atomic64_read(&log->l_tail_lsn); if (*head_blk == after_umount_blk && be32_to_cpu(rhead->h_num_logops) == 1) { umount_data_blk = (i + hblks) % log->l_logBBsize; error = xlog_bread(log, umount_data_blk, 1, bp, &offset); if (error) goto done; op_head = (xlog_op_header_t *)offset; if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { /* * Set tail and last sync so that newly written * log records will point recovery to after the * current unmount record. */ xlog_assign_atomic_lsn(&log->l_tail_lsn, log->l_curr_cycle, after_umount_blk); xlog_assign_atomic_lsn(&log->l_last_sync_lsn, log->l_curr_cycle, after_umount_blk); *tail_blk = after_umount_blk; /* * Note that the unmount was clean. If the unmount * was not clean, we need to know this to rebuild the * superblock counters from the perag headers if we * have a filesystem using non-persistent counters. */ log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN; } } /* * Make sure that there are no blocks in front of the head * with the same cycle number as the head. This can happen * because we allow multiple outstanding log writes concurrently, * and the later writes might make it out before earlier ones. * * We use the lsn from before modifying it so that we'll never * overwrite the unmount record after a clean unmount. * * Do this only if we are going to recover the filesystem * * NOTE: This used to say "if (!readonly)" * However on Linux, we can & do recover a read-only filesystem. * We only skip recovery if NORECOVERY is specified on mount, * in which case we would not be here. * * But... if the -device- itself is readonly, just skip this. * We can't recover this device anyway, so it won't matter. */ if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) error = xlog_clear_stale_blocks(log, tail_lsn); done: xlog_put_bp(bp); if (error) xfs_warn(log->l_mp, "failed to locate log tail"); return error; } /* * Is the log zeroed at all? * * The last binary search should be changed to perform an X block read * once X becomes small enough. You can then search linearly through * the X blocks. This will cut down on the number of reads we need to do. * * If the log is partially zeroed, this routine will pass back the blkno * of the first block with cycle number 0. It won't have a complete LR * preceding it. * * Return: * 0 => the log is completely written to * -1 => use *blk_no as the first block of the log * >0 => error has occurred */ int xlog_find_zeroed( struct xlog *log, xfs_daddr_t *blk_no) { xfs_buf_t *bp; char *offset; uint first_cycle, last_cycle; xfs_daddr_t new_blk, last_blk, start_blk; xfs_daddr_t num_scan_bblks; int error, log_bbnum = log->l_logBBsize; *blk_no = 0; /* check totally zeroed log */ bp = xlog_get_bp(log, 1); if (!bp) return ENOMEM; error = xlog_bread(log, 0, 1, bp, &offset); if (error) goto bp_err; first_cycle = xlog_get_cycle(offset); if (first_cycle == 0) { /* completely zeroed log */ *blk_no = 0; xlog_put_bp(bp); return -1; } /* check partially zeroed log */ error = xlog_bread(log, log_bbnum-1, 1, bp, &offset); if (error) goto bp_err; last_cycle = xlog_get_cycle(offset); if (last_cycle != 0) { /* log completely written to */ xlog_put_bp(bp); return 0; } else if (first_cycle != 1) { /* * If the cycle of the last block is zero, the cycle of * the first block must be 1. If it's not, maybe we're * not looking at a log... Bail out. */ xfs_warn(log->l_mp, "Log inconsistent or not a log (last==0, first!=1)"); error = XFS_ERROR(EINVAL); goto bp_err; } /* we have a partially zeroed log */ last_blk = log_bbnum-1; if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0))) goto bp_err; /* * Validate the answer. Because there is no way to guarantee that * the entire log is made up of log records which are the same size, * we scan over the defined maximum blocks. At this point, the maximum * is not chosen to mean anything special. XXXmiken */ num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); ASSERT(num_scan_bblks <= INT_MAX); if (last_blk < num_scan_bblks) num_scan_bblks = last_blk; start_blk = last_blk - num_scan_bblks; /* * We search for any instances of cycle number 0 that occur before * our current estimate of the head. What we're trying to detect is * 1 ... | 0 | 1 | 0... * ^ binary search ends here */ if ((error = xlog_find_verify_cycle(log, start_blk, (int)num_scan_bblks, 0, &new_blk))) goto bp_err; if (new_blk != -1) last_blk = new_blk; /* * Potentially backup over partial log record write. We don't need * to search the end of the log because we know it is zero. */ if ((error = xlog_find_verify_log_record(log, start_blk, &last_blk, 0)) == -1) { error = XFS_ERROR(EIO); goto bp_err; } else if (error) goto bp_err; *blk_no = last_blk; bp_err: xlog_put_bp(bp); if (error) return error; return -1; } STATIC xlog_recover_t * xlog_recover_find_tid( struct hlist_head *head, xlog_tid_t tid) { xlog_recover_t *trans; struct hlist_node *n; hlist_for_each_entry(trans, n, head, r_list) { if (trans->r_log_tid == tid) return trans; } return NULL; } STATIC void xlog_recover_new_tid( struct hlist_head *head, xlog_tid_t tid, xfs_lsn_t lsn) { xlog_recover_t *trans; trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP); trans->r_log_tid = tid; trans->r_lsn = lsn; INIT_LIST_HEAD(&trans->r_itemq); INIT_HLIST_NODE(&trans->r_list); hlist_add_head(&trans->r_list, head); } STATIC void xlog_recover_add_item( struct list_head *head) { xlog_recover_item_t *item; item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP); INIT_LIST_HEAD(&item->ri_list); list_add_tail(&item->ri_list, head); } STATIC int xlog_recover_add_to_cont_trans( struct xlog *log, struct xlog_recover *trans, char *dp, int len) { xlog_recover_item_t *item; char *ptr, *old_ptr; int old_len; if (list_empty(&trans->r_itemq)) { /* finish copying rest of trans header */ xlog_recover_add_item(&trans->r_itemq); ptr = (char *) &trans->r_theader + sizeof(xfs_trans_header_t) - len; memcpy(ptr, dp, len); /* d, s, l */ return 0; } /* take the tail entry */ item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; old_len = item->ri_buf[item->ri_cnt-1].i_len; ptr = kmem_realloc(old_ptr, len+old_len, KM_SLEEP); memcpy(&ptr[old_len], dp, len); /* d, s, l */ item->ri_buf[item->ri_cnt-1].i_len += len; item->ri_buf[item->ri_cnt-1].i_addr = ptr; trace_xfs_log_recover_item_add_cont(log, trans, item, 0); return 0; } /* * The next region to add is the start of a new region. It could be * a whole region or it could be the first part of a new region. Because * of this, the assumption here is that the type and size fields of all * format structures fit into the first 32 bits of the structure. * * This works because all regions must be 32 bit aligned. Therefore, we * either have both fields or we have neither field. In the case we have * neither field, the data part of the region is zero length. We only have * a log_op_header and can throw away the header since a new one will appear * later. If we have at least 4 bytes, then we can determine how many regions * will appear in the current log item. */ STATIC int xlog_recover_add_to_trans( struct xlog *log, struct xlog_recover *trans, char *dp, int len) { struct xfs_inode_log_format *in_f; /* any will do */ xlog_recover_item_t *item; char *ptr; if (!len) return 0; if (list_empty(&trans->r_itemq)) { /* we need to catch log corruptions here */ if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { xfs_warn(log->l_mp, "%s: bad header magic number", __func__); ASSERT(0); return XFS_ERROR(EIO); } if (len == sizeof(xfs_trans_header_t)) xlog_recover_add_item(&trans->r_itemq); memcpy(&trans->r_theader, dp, len); /* d, s, l */ return 0; } ptr = kmem_alloc(len, KM_SLEEP); memcpy(ptr, dp, len); in_f = (struct xfs_inode_log_format *)ptr; /* take the tail entry */ item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); if (item->ri_total != 0 && item->ri_total == item->ri_cnt) { /* tail item is in use, get a new one */ xlog_recover_add_item(&trans->r_itemq); item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); } if (item->ri_total == 0) { /* first region to be added */ if (in_f->ilf_size == 0 || in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) { xfs_warn(log->l_mp, "bad number of regions (%d) in inode log format", in_f->ilf_size); ASSERT(0); kmem_free(ptr); return XFS_ERROR(EIO); } item->ri_total = in_f->ilf_size; item->ri_buf = kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t), KM_SLEEP); } ASSERT(item->ri_total > item->ri_cnt); /* Description region is ri_buf[0] */ item->ri_buf[item->ri_cnt].i_addr = ptr; item->ri_buf[item->ri_cnt].i_len = len; item->ri_cnt++; trace_xfs_log_recover_item_add(log, trans, item, 0); return 0; } /* * Free up any resources allocated by the transaction * * Remember that EFIs, EFDs, and IUNLINKs are handled later. */ STATIC void xlog_recover_free_trans( struct xlog_recover *trans) { xlog_recover_item_t *item, *n; int i; list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) { /* Free the regions in the item. */ list_del(&item->ri_list); for (i = 0; i < item->ri_cnt; i++) kmem_free(item->ri_buf[i].i_addr); /* Free the item itself */ kmem_free(item->ri_buf); kmem_free(item); } /* Free the transaction recover structure */ kmem_free(trans); } /* * Perform the transaction. * * If the transaction modifies a buffer or inode, do it now. Otherwise, * EFIs and EFDs get queued up by adding entries into the AIL for them. */ STATIC int xlog_recover_commit_trans( struct xlog *log, struct xlog_recover *trans, int pass) { int error = 0; hlist_del(&trans->r_list); if ((error = xlog_recover_do_trans(log, trans, pass))) return error; xlog_recover_free_trans(trans); return 0; } STATIC int xlog_recover_unmount_trans( xlog_recover_t *trans) { /* Do nothing now */ xfs_warn(log->l_mp, "%s: Unmount LR", __func__); return 0; } /* * There are two valid states of the r_state field. 0 indicates that the * transaction structure is in a normal state. We have either seen the * start of the transaction or the last operation we added was not a partial * operation. If the last operation we added to the transaction was a * partial operation, we need to mark r_state with XLOG_WAS_CONT_TRANS. * * NOTE: skip LRs with 0 data length. */ STATIC int xlog_recover_process_data( struct xlog *log, struct hlist_head rhash[], struct xlog_rec_header *rhead, char *dp, int pass) { char *lp; int num_logops; xlog_op_header_t *ohead; xlog_recover_t *trans; xlog_tid_t tid; int error; unsigned long hash; uint flags; lp = dp + be32_to_cpu(rhead->h_len); num_logops = be32_to_cpu(rhead->h_num_logops); /* check the log format matches our own - else we can't recover */ if (xlog_header_check_recover(log->l_mp, rhead)) return (XFS_ERROR(EIO)); while ((dp < lp) && num_logops) { ASSERT(dp + sizeof(xlog_op_header_t) <= lp); ohead = (xlog_op_header_t *)dp; dp += sizeof(xlog_op_header_t); if (ohead->oh_clientid != XFS_TRANSACTION && ohead->oh_clientid != XFS_LOG) { xfs_warn(log->l_mp, "%s: bad clientid 0x%x", __func__, ohead->oh_clientid); ASSERT(0); return (XFS_ERROR(EIO)); } tid = be32_to_cpu(ohead->oh_tid); hash = XLOG_RHASH(tid); trans = xlog_recover_find_tid(&rhash[hash], tid); if (trans == NULL) { /* not found; add new tid */ if (ohead->oh_flags & XLOG_START_TRANS) xlog_recover_new_tid(&rhash[hash], tid, be64_to_cpu(rhead->h_lsn)); } else { if (dp + be32_to_cpu(ohead->oh_len) > lp) { xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, be32_to_cpu(ohead->oh_len)); return (XFS_ERROR(EIO)); } flags = ohead->oh_flags & ~XLOG_END_TRANS; if (flags & XLOG_WAS_CONT_TRANS) flags &= ~XLOG_CONTINUE_TRANS; switch (flags) { case XLOG_COMMIT_TRANS: error = xlog_recover_commit_trans(log, trans, pass); break; case XLOG_UNMOUNT_TRANS: error = xlog_recover_unmount_trans(trans); break; case XLOG_WAS_CONT_TRANS: error = xlog_recover_add_to_cont_trans(log, trans, dp, be32_to_cpu(ohead->oh_len)); break; case XLOG_START_TRANS: xfs_warn(log->l_mp, "%s: bad transaction", __func__); ASSERT(0); error = XFS_ERROR(EIO); break; case 0: case XLOG_CONTINUE_TRANS: error = xlog_recover_add_to_trans(log, trans, dp, be32_to_cpu(ohead->oh_len)); break; default: xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags); ASSERT(0); error = XFS_ERROR(EIO); break; } if (error) return error; } dp += be32_to_cpu(ohead->oh_len); num_logops--; } return 0; } /* * Upack the log buffer data and crc check it. If the check fails, issue a * warning if and only if the CRC in the header is non-zero. This makes the * check an advisory warning, and the zero CRC check will prevent failure * warnings from being emitted when upgrading the kernel from one that does not * add CRCs by default. * * When filesystems are CRC enabled, this CRC mismatch becomes a fatal log * corruption failure * * XXX: we do not calculate the CRC here yet. It's not clear what we should do * with CRC errors here in userspace, so we'll address that problem later on. */ #define xlog_cksum(l,r,dp,len) ((r)->h_crc) STATIC int xlog_unpack_data_crc( struct xlog_rec_header *rhead, char *dp, struct xlog *log) { __le32 crc; crc = xlog_cksum(log, rhead, dp, be32_to_cpu(rhead->h_len)); if (crc != rhead->h_crc) { if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) { xfs_alert(log->l_mp, "log record CRC mismatch: found 0x%x, expected 0x%x.", le32_to_cpu(rhead->h_crc), le32_to_cpu(crc)); xfs_hex_dump(dp, 32); } /* * If we've detected a log record corruption, then we can't * recover past this point. Abort recovery if we are enforcing * CRC protection by punting an error back up the stack. */ if (xfs_sb_version_hascrc(&log->l_mp->m_sb)) return EFSCORRUPTED; } return 0; } STATIC int xlog_unpack_data( struct xlog_rec_header *rhead, char *dp, struct xlog *log) { int i, j, k; int error; error = xlog_unpack_data_crc(rhead, dp, log); if (error) return error; for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) && i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { *(__be32 *)dp = *(__be32 *)&rhead->h_cycle_data[i]; dp += BBSIZE; } if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { xlog_in_core_2_t *xhdr = (xlog_in_core_2_t *)rhead; for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) { j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); *(__be32 *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; dp += BBSIZE; } } return 0; } STATIC int xlog_valid_rec_header( struct xlog *log, struct xlog_rec_header *rhead, xfs_daddr_t blkno) { int hlen; if (unlikely(rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))) { XFS_ERROR_REPORT("xlog_valid_rec_header(1)", XFS_ERRLEVEL_LOW, log->l_mp); return XFS_ERROR(EFSCORRUPTED); } if (unlikely( (!rhead->h_version || (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) { xfs_warn(log->l_mp, "%s: unrecognised log version (%d).", __func__, be32_to_cpu(rhead->h_version)); return XFS_ERROR(EIO); } /* LR body must have data or it wouldn't have been written */ hlen = be32_to_cpu(rhead->h_len); if (unlikely( hlen <= 0 || hlen > INT_MAX )) { XFS_ERROR_REPORT("xlog_valid_rec_header(2)", XFS_ERRLEVEL_LOW, log->l_mp); return XFS_ERROR(EFSCORRUPTED); } if (unlikely( blkno > log->l_logBBsize || blkno > INT_MAX )) { XFS_ERROR_REPORT("xlog_valid_rec_header(3)", XFS_ERRLEVEL_LOW, log->l_mp); return XFS_ERROR(EFSCORRUPTED); } return 0; } /* * Read the log from tail to head and process the log records found. * Handle the two cases where the tail and head are in the same cycle * and where the active portion of the log wraps around the end of * the physical log separately. The pass parameter is passed through * to the routines called to process the data and is not looked at * here. */ int xlog_do_recovery_pass( struct xlog *log, xfs_daddr_t head_blk, xfs_daddr_t tail_blk, int pass) { xlog_rec_header_t *rhead; xfs_daddr_t blk_no; char *offset; xfs_buf_t *hbp, *dbp; int error = 0, h_size; int bblks, split_bblks; int hblks, split_hblks, wrapped_hblks; struct hlist_head rhash[XLOG_RHASH_SIZE]; ASSERT(head_blk != tail_blk); /* * Read the header of the tail block and get the iclog buffer size from * h_size. Use this to tell how many sectors make up the log header. */ if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { /* * When using variable length iclogs, read first sector of * iclog header and extract the header size from it. Get a * new hbp that is the correct size. */ hbp = xlog_get_bp(log, 1); if (!hbp) return ENOMEM; error = xlog_bread(log, tail_blk, 1, hbp, &offset); if (error) goto bread_err1; rhead = (xlog_rec_header_t *)offset; error = xlog_valid_rec_header(log, rhead, tail_blk); if (error) goto bread_err1; h_size = be32_to_cpu(rhead->h_size); if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) && (h_size > XLOG_HEADER_CYCLE_SIZE)) { hblks = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) hblks++; xlog_put_bp(hbp); hbp = xlog_get_bp(log, hblks); } else { hblks = 1; } } else { ASSERT(log->l_sectBBsize == 1); hblks = 1; hbp = xlog_get_bp(log, 1); h_size = XLOG_BIG_RECORD_BSIZE; } if (!hbp) return ENOMEM; dbp = xlog_get_bp(log, BTOBB(h_size)); if (!dbp) { xlog_put_bp(hbp); return ENOMEM; } memset(rhash, 0, sizeof(rhash)); if (tail_blk <= head_blk) { for (blk_no = tail_blk; blk_no < head_blk; ) { error = xlog_bread(log, blk_no, hblks, hbp, &offset); if (error) goto bread_err2; rhead = (xlog_rec_header_t *)offset; error = xlog_valid_rec_header(log, rhead, blk_no); if (error) goto bread_err2; /* blocks in data section */ bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); error = xlog_bread(log, blk_no + hblks, bblks, dbp, &offset); if (error) goto bread_err2; error = xlog_unpack_data(rhead, offset, log); if (error) goto bread_err2; error = xlog_recover_process_data(log, rhash, rhead, offset, pass); if (error) goto bread_err2; blk_no += bblks + hblks; } } else { /* * Perform recovery around the end of the physical log. * When the head is not on the same cycle number as the tail, * we can't do a sequential recovery as above. */ blk_no = tail_blk; while (blk_no < log->l_logBBsize) { /* * Check for header wrapping around physical end-of-log */ offset = hbp->b_addr; split_hblks = 0; wrapped_hblks = 0; if (blk_no + hblks <= log->l_logBBsize) { /* Read header in one read */ error = xlog_bread(log, blk_no, hblks, hbp, &offset); if (error) goto bread_err2; } else { /* This LR is split across physical log end */ if (blk_no != log->l_logBBsize) { /* some data before physical log end */ ASSERT(blk_no <= INT_MAX); split_hblks = log->l_logBBsize - (int)blk_no; ASSERT(split_hblks > 0); error = xlog_bread(log, blk_no, split_hblks, hbp, &offset); if (error) goto bread_err2; } /* * Note: this black magic still works with * large sector sizes (non-512) only because: * - we increased the buffer size originally * by 1 sector giving us enough extra space * for the second read; * - the log start is guaranteed to be sector * aligned; * - we read the log end (LR header start) * _first_, then the log start (LR header end) * - order is important. */ wrapped_hblks = hblks - split_hblks; error = xlog_bread_offset(log, 0, wrapped_hblks, hbp, offset + BBTOB(split_hblks)); if (error) goto bread_err2; } rhead = (xlog_rec_header_t *)offset; error = xlog_valid_rec_header(log, rhead, split_hblks ? blk_no : 0); if (error) goto bread_err2; bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); blk_no += hblks; /* Read in data for log record */ if (blk_no + bblks <= log->l_logBBsize) { error = xlog_bread(log, blk_no, bblks, dbp, &offset); if (error) goto bread_err2; } else { /* This log record is split across the * physical end of log */ offset = dbp->b_addr; split_bblks = 0; if (blk_no != log->l_logBBsize) { /* some data is before the physical * end of log */ ASSERT(!wrapped_hblks); ASSERT(blk_no <= INT_MAX); split_bblks = log->l_logBBsize - (int)blk_no; ASSERT(split_bblks > 0); error = xlog_bread(log, blk_no, split_bblks, dbp, &offset); if (error) goto bread_err2; } /* * Note: this black magic still works with * large sector sizes (non-512) only because: * - we increased the buffer size originally * by 1 sector giving us enough extra space * for the second read; * - the log start is guaranteed to be sector * aligned; * - we read the log end (LR header start) * _first_, then the log start (LR header end) * - order is important. */ error = xlog_bread_offset(log, 0, bblks - split_bblks, dbp, offset + BBTOB(split_bblks)); if (error) goto bread_err2; } error = xlog_unpack_data(rhead, offset, log); if (error) goto bread_err2; error = xlog_recover_process_data(log, rhash, rhead, offset, pass); if (error) goto bread_err2; blk_no += bblks; } ASSERT(blk_no >= log->l_logBBsize); blk_no -= log->l_logBBsize; /* read first part of physical log */ while (blk_no < head_blk) { error = xlog_bread(log, blk_no, hblks, hbp, &offset); if (error) goto bread_err2; rhead = (xlog_rec_header_t *)offset; error = xlog_valid_rec_header(log, rhead, blk_no); if (error) goto bread_err2; bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); error = xlog_bread(log, blk_no+hblks, bblks, dbp, &offset); if (error) goto bread_err2; error = xlog_unpack_data(rhead, offset, log); if (error) goto bread_err2; error = xlog_recover_process_data(log, rhash, rhead, offset, pass); if (error) goto bread_err2; blk_no += bblks + hblks; } } bread_err2: xlog_put_bp(dbp); bread_err1: xlog_put_bp(hbp); return error; } xfsprogs-5.3.0/logprint/Makefile0000644000175000017500000000122413435336037016550 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_logprint HFILES = logprint.h CFILES = logprint.c \ log_copy.c log_dump.c log_misc.c \ log_print_all.c log_print_trans.c log_redo.c LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG) $(LIBFROG) LLDFLAGS = -static-libtool-libs default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/logprint/log_copy.c0000644000175000017500000000246313435336037017075 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "logprint.h" /* * Extract a log and write it out to a file */ void xfs_log_copy( struct xlog *log, int fd, char *filename) { int ofd, r; xfs_daddr_t blkno; char buf[XLOG_HEADER_SIZE]; if ((ofd = open(filename, O_CREAT|O_EXCL|O_RDWR|O_TRUNC, 0666)) == -1) { perror("open"); exit(1); } xlog_print_lseek(log, fd, 0, SEEK_SET); for (blkno = 0; blkno < log->l_logBBsize; blkno++) { r = read(fd, buf, sizeof(buf)); if (r < 0) { fprintf(stderr, _("%s: read error (%lld): %s\n"), __FUNCTION__, (long long)blkno, strerror(errno)); continue; } else if (r == 0) { printf(_("%s: physical end of log at %lld\n"), __FUNCTION__, (long long)blkno); break; } else if (r != sizeof(buf)) { fprintf(stderr, _("%s: short read? (%lld)\n"), __FUNCTION__, (long long)blkno); continue; } r = write(ofd, buf, sizeof(buf)); if (r < 0) { fprintf(stderr, _("%s: write error (%lld): %s\n"), __FUNCTION__, (long long)blkno, strerror(errno)); break; } else if (r != sizeof(buf)) { fprintf(stderr, _("%s: short write? (%lld)\n"), __FUNCTION__, (long long)blkno); continue; } } close(ofd); } xfsprogs-5.3.0/logprint/log_dump.c0000644000175000017500000000273513435336037017072 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "logprint.h" /* * Dump log blocks, not data */ void xfs_log_dump( struct xlog *log, int fd, int print_block_start) { int r; uint last_cycle = -1; xfs_daddr_t blkno, dupblkno; xlog_rec_header_t *hdr; char buf[XLOG_HEADER_SIZE]; dupblkno = 0; hdr = (xlog_rec_header_t *)buf; xlog_print_lseek(log, fd, 0, SEEK_SET); for (blkno = 0; blkno < log->l_logBBsize; blkno++) { r = read(fd, buf, sizeof(buf)); if (r < 0) { fprintf(stderr, _("%s: read error (%lld): %s\n"), __FUNCTION__, (long long)blkno, strerror(errno)); continue; } else if (r == 0) { printf(_("%s: physical end of log at %lld\n"), __FUNCTION__, (long long)blkno); break; } if (CYCLE_LSN(be64_to_cpu(*(__be64 *)buf)) == XLOG_HEADER_MAGIC_NUM && !print_no_data) { printf(_( "%6lld HEADER Cycle %d tail %d:%06d len %6d ops %d\n"), (long long)blkno, be32_to_cpu(hdr->h_cycle), CYCLE_LSN(be64_to_cpu(hdr->h_tail_lsn)), BLOCK_LSN(be64_to_cpu(hdr->h_tail_lsn)), be32_to_cpu(hdr->h_len), be32_to_cpu(hdr->h_num_logops)); } if (xlog_get_cycle(buf) != last_cycle) { printf(_( "[%05lld - %05lld] Cycle 0x%08x New Cycle 0x%08x\n"), (long long)dupblkno, (long long)blkno, last_cycle, xlog_get_cycle(buf)); last_cycle = xlog_get_cycle(buf); dupblkno = blkno; } } } xfsprogs-5.3.0/logprint/log_misc.c0000644000175000017500000011716113435336037017060 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "logprint.h" #define CLEARED_BLKS (-5) #define ZEROED_LOG (-4) #define FULL_READ (-3) #define PARTIAL_READ (-2) #define BAD_HEADER (-1) #define NO_ERROR (0) static int logBBsize; typedef struct xlog_split_item { struct xlog_split_item *si_next; struct xlog_split_item *si_prev; xlog_tid_t si_xtid; int si_skip; } xlog_split_item_t; static xlog_split_item_t *split_list = NULL; void print_xlog_op_line(void) { printf("--------------------------------------" "--------------------------------------\n"); } /* print_xlog_op_line */ static void print_xlog_xhdr_line(void) { printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); } /* print_xlog_xhdr_line */ void print_xlog_record_line(void) { printf("======================================" "======================================\n"); } /* print_xlog_record_line */ void print_stars(void) { printf("***********************************" "***********************************\n"); } /* print_stars */ /* * Given a pointer to a data segment, print out the data as if it were * a log operation header. */ static void xlog_print_op_header(xlog_op_header_t *op_head, int i, char **ptr) { xlog_op_header_t hbuf; /* * memmove because on 64/n32, partial reads can cause the op_head * pointer to come in pointing to an odd-numbered byte */ memmove(&hbuf, op_head, sizeof(xlog_op_header_t)); op_head = &hbuf; *ptr += sizeof(xlog_op_header_t); printf(_("Oper (%d): tid: %x len: %d clientid: %s "), i, be32_to_cpu(op_head->oh_tid), be32_to_cpu(op_head->oh_len), (op_head->oh_clientid == XFS_TRANSACTION ? "TRANS" : (op_head->oh_clientid == XFS_LOG ? "LOG" : "ERROR"))); printf(_("flags: ")); if (op_head->oh_flags) { if (op_head->oh_flags & XLOG_START_TRANS) printf("START "); if (op_head->oh_flags & XLOG_COMMIT_TRANS) printf("COMMIT "); if (op_head->oh_flags & XLOG_WAS_CONT_TRANS) printf("WAS_CONT "); if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) printf("UNMOUNT "); if (op_head->oh_flags & XLOG_CONTINUE_TRANS) printf("CONTINUE "); if (op_head->oh_flags & XLOG_END_TRANS) printf("END "); } else { printf(_("none")); } printf("\n"); } /* xlog_print_op_header */ static void xlog_print_add_to_trans(xlog_tid_t tid, int skip) { xlog_split_item_t *item; item = (xlog_split_item_t *)calloc(sizeof(xlog_split_item_t), 1); item->si_xtid = tid; item->si_skip = skip; item->si_next = split_list; item->si_prev = NULL; if (split_list) split_list->si_prev = item; split_list = item; } /* xlog_print_add_to_trans */ static int xlog_print_find_tid(xlog_tid_t tid, uint was_cont) { xlog_split_item_t *listp = split_list; if (!split_list) { if (was_cont != 0) /* Not first time we have used this tid */ return 1; else return 0; } while (listp) { if (listp->si_xtid == tid) break; listp = listp->si_next; } if (!listp) { return 0; } if (--listp->si_skip == 0) { if (listp == split_list) { /* delete at head */ split_list = listp->si_next; if (split_list) split_list->si_prev = NULL; } else { if (listp->si_next) listp->si_next->si_prev = listp->si_prev; listp->si_prev->si_next = listp->si_next; } free(listp); } return 1; } /* xlog_print_find_tid */ static int xlog_print_trans_header(char **ptr, int len) { xfs_trans_header_t *h; char *cptr = *ptr; uint32_t magic; char *magic_c = (char *)&magic; *ptr += len; magic = *(uint32_t *)cptr; /* XXX be32_to_cpu soon */ if (len >= 4) { #if __BYTE_ORDER == __LITTLE_ENDIAN printf("%c%c%c%c:", magic_c[3], magic_c[2], magic_c[1], magic_c[0]); #else printf("%c%c%c%c:", magic_c[0], magic_c[1], magic_c[2], magic_c[3]); #endif } if (len != sizeof(xfs_trans_header_t)) { printf(_(" Not enough data to decode further\n")); return 1; } h = (xfs_trans_header_t *)cptr; printf(_(" tid: %x num_items: %d\n"), h->th_tid, h->th_num_items); return 0; } /* xlog_print_trans_header */ static int xlog_print_trans_buffer(char **ptr, int len, int *i, int num_ops) { xfs_buf_log_format_t *f; xlog_op_header_t *head = NULL; int num, skip; int super_block = 0; int bucket, col, buckets; int64_t blkno; xfs_buf_log_format_t lbuf; int size, blen, map_size, struct_size; unsigned short flags; /* * memmove to ensure 8-byte alignment for the long longs in * buf_log_format_t structure */ memmove(&lbuf, *ptr, min(sizeof(xfs_buf_log_format_t), len)); f = &lbuf; *ptr += len; ASSERT(f->blf_type == XFS_LI_BUF); printf("BUF: "); blkno = f->blf_blkno; size = f->blf_size; blen = f->blf_len; map_size = f->blf_map_size; flags = f->blf_flags; /* * size of the format header is dependent on the size of the bitmap, not * the size of the in-memory structure. Hence the slightly obtuse * calculation. */ struct_size = offsetof(struct xfs_buf_log_format, blf_map_size) + map_size; if (len >= struct_size) { ASSERT((len - sizeof(struct_size)) % sizeof(int) == 0); printf(_("#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d flags: 0x%x\n"), size, (long long)blkno, (unsigned long long)blkno, blen, map_size, flags); if (blkno == 0) super_block = 1; } else { ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ printf(_("#regs: %d Not printing rest of data\n"), f->blf_size); return size; } num = size-1; /* Check if all regions in this log item were in the given LR ptr */ if (*i+num > num_ops-1) { skip = num - (num_ops-1-*i); num = num_ops-1-*i; } else { skip = 0; } while (num-- > 0) { (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); if (super_block) { printf(_("SUPER BLOCK Buffer: ")); if (be32_to_cpu(head->oh_len) < 4*8) { printf(_("Out of space\n")); } else { __be64 a, b; printf("\n"); /* * memmove because *ptr may not be 8-byte aligned */ memmove(&a, *ptr, sizeof(__be64)); memmove(&b, *ptr+8, sizeof(__be64)); printf(_("icount: %llu ifree: %llu "), (unsigned long long) be64_to_cpu(a), (unsigned long long) be64_to_cpu(b)); memmove(&a, *ptr+16, sizeof(__be64)); memmove(&b, *ptr+24, sizeof(__be64)); printf(_("fdblks: %llu frext: %llu\n"), (unsigned long long) be64_to_cpu(a), (unsigned long long) be64_to_cpu(b)); } super_block = 0; } else if (be32_to_cpu(*(__be32 *)(*ptr)) == XFS_AGI_MAGIC) { struct xfs_agi *agi, agi_s; /* memmove because *ptr may not be 8-byte aligned */ agi = &agi_s; memmove(agi, *ptr, sizeof(struct xfs_agi)); printf(_("AGI Buffer: XAGI ")); /* * v4 filesystems only contain the fields before the uuid. * Even v5 filesystems don't log any field beneath it. That * means that the size that is logged is almost always going to * be smaller than the structure itself. Hence we need to make * sure that the buffer contains all the data we want to print * rather than just check against the structure size. */ if (be32_to_cpu(head->oh_len) < offsetof(xfs_agi_t, agi_uuid) - XFS_AGI_UNLINKED_BUCKETS*sizeof(xfs_agino_t)) { printf(_("out of space\n")); } else { printf("\n"); printf(_("ver: %d "), be32_to_cpu(agi->agi_versionnum)); printf(_("seq#: %d len: %d cnt: %d root: %d\n"), be32_to_cpu(agi->agi_seqno), be32_to_cpu(agi->agi_length), be32_to_cpu(agi->agi_count), be32_to_cpu(agi->agi_root)); printf(_("level: %d free#: 0x%x newino: 0x%x\n"), be32_to_cpu(agi->agi_level), be32_to_cpu(agi->agi_freecount), be32_to_cpu(agi->agi_newino)); if (be32_to_cpu(head->oh_len) == 128) { buckets = 17; } else if (be32_to_cpu(head->oh_len) == 256) { buckets = 32 + 17; } else { if (head->oh_flags & XLOG_CONTINUE_TRANS) { printf(_("AGI unlinked data skipped ")); printf(_("(CONTINUE set, no space)\n")); continue; } buckets = XFS_AGI_UNLINKED_BUCKETS; } for (bucket = 0; bucket < buckets;) { printf(_("bucket[%d - %d]: "), bucket, bucket+3); for (col = 0; col < 4; col++, bucket++) { if (bucket < buckets) { printf("0x%x ", be32_to_cpu(agi->agi_unlinked[bucket])); } } printf("\n"); } } } else if (be32_to_cpu(*(__be32 *)(*ptr)) == XFS_AGF_MAGIC) { struct xfs_agf *agf, agf_s; /* memmove because *ptr may not be 8-byte aligned */ agf = &agf_s; memmove(agf, *ptr, sizeof(struct xfs_agf)); printf(_("AGF Buffer: XAGF ")); /* * v4 filesystems only contain the fields before the uuid. * Even v5 filesystems don't log any field beneath it. That * means that the size that is logged is almost always going to * be smaller than the structure itself. Hence we need to make * sure that the buffer contains all the data we want to print * rather than just check against the structure size. */ if (be32_to_cpu(head->oh_len) < offsetof(xfs_agf_t, agf_uuid)) { printf(_("Out of space\n")); } else { printf("\n"); printf(_("ver: %d seq#: %d len: %d \n"), be32_to_cpu(agf->agf_versionnum), be32_to_cpu(agf->agf_seqno), be32_to_cpu(agf->agf_length)); printf(_("root BNO: %d CNT: %d\n"), be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi]), be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); printf(_("level BNO: %d CNT: %d\n"), be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]), be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); printf(_("1st: %d last: %d cnt: %d " "freeblks: %d longest: %d\n"), be32_to_cpu(agf->agf_flfirst), be32_to_cpu(agf->agf_fllast), be32_to_cpu(agf->agf_flcount), be32_to_cpu(agf->agf_freeblks), be32_to_cpu(agf->agf_longest)); } } else if (be32_to_cpu(*(__be32 *)(*ptr)) == XFS_DQUOT_MAGIC) { struct xfs_disk_dquot *dq, dq_s; /* memmove because *ptr may not be 8-byte aligned */ dq = &dq_s; memmove(dq, *ptr, sizeof(struct xfs_disk_dquot)); printf(_("DQUOT Buffer: DQ ")); if (be32_to_cpu(head->oh_len) < sizeof(xfs_disk_dquot_t)) { printf(_("Out of space\n")); } else { printf("\n"); printf(_("ver: %d flags: 0x%x id: %d \n"), dq->d_version, dq->d_flags, be32_to_cpu(dq->d_id)); printf(_("blk limits hard: %llu soft: %llu\n"), (unsigned long long) be64_to_cpu(dq->d_blk_hardlimit), (unsigned long long) be64_to_cpu(dq->d_blk_softlimit)); printf(_("blk count: %llu warns: %d timer: %d\n"), (unsigned long long) be64_to_cpu(dq->d_bcount), (int) be16_to_cpu(dq->d_bwarns), be32_to_cpu(dq->d_btimer)); printf(_("ino limits hard: %llu soft: %llu\n"), (unsigned long long) be64_to_cpu(dq->d_ino_hardlimit), (unsigned long long) be64_to_cpu(dq->d_ino_softlimit)); printf(_("ino count: %llu warns: %d timer: %d\n"), (unsigned long long) be64_to_cpu(dq->d_icount), (int) be16_to_cpu(dq->d_iwarns), be32_to_cpu(dq->d_itimer)); } } else { printf(_("BUF DATA\n")); if (print_data) { uint *dp = (uint *)*ptr; int nums = be32_to_cpu(head->oh_len) >> 2; int byte = 0; while (byte < nums) { if ((byte % 8) == 0) printf("%2x ", byte); printf("%8x ", *dp); dp++; byte++; if ((byte % 8) == 0) printf("\n"); } printf("\n"); } } *ptr += be32_to_cpu(head->oh_len); } if (head && head->oh_flags & XLOG_CONTINUE_TRANS) skip++; return skip; } /* xlog_print_trans_buffer */ static int xlog_print_trans_qoff(char **ptr, uint len) { xfs_qoff_logformat_t *f; xfs_qoff_logformat_t lbuf; memmove(&lbuf, *ptr, min(sizeof(xfs_qoff_logformat_t), len)); f = &lbuf; *ptr += len; if (len >= sizeof(xfs_qoff_logformat_t)) { printf(_("QOFF: #regs: %d flags: 0x%x\n"), f->qf_size, f->qf_flags); return 0; } else { printf(_("QOFF: Not enough data to decode further\n")); return 1; } } /* xlog_print_trans_qoff */ static void xlog_print_trans_inode_core( struct xfs_log_dinode *ip) { printf(_("INODE CORE\n")); printf(_("magic 0x%hx mode 0%ho version %d format %d\n"), ip->di_magic, ip->di_mode, (int)ip->di_version, (int)ip->di_format); printf(_("nlink %hd uid %d gid %d\n"), ip->di_nlink, ip->di_uid, ip->di_gid); printf(_("atime 0x%x mtime 0x%x ctime 0x%x\n"), ip->di_atime.t_sec, ip->di_mtime.t_sec, ip->di_ctime.t_sec); printf(_("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n"), (unsigned long long)ip->di_size, (unsigned long long)ip->di_nblocks, ip->di_extsize, ip->di_nextents); printf(_("naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n"), ip->di_anextents, (int)ip->di_forkoff, ip->di_dmevmask, ip->di_dmstate); printf(_("flags 0x%x gen 0x%x\n"), ip->di_flags, ip->di_gen); if (ip->di_version == 3) { printf(_("flags2 0x%llx cowextsize 0x%x\n"), (unsigned long long)ip->di_flags2, ip->di_cowextsize); } } static void xlog_print_dir2_sf( struct xlog *log, xfs_dir2_sf_hdr_t *sfp, int size) { __be64 pino; /* parent inode nr */ xfs_ino_t ino; int count; int i; char namebuf[257]; xfs_dir2_sf_entry_t *sfep; printf(_("SHORTFORM DIRECTORY size %d\n"), size); /* bail out for now */ return; printf(_("SHORTFORM DIRECTORY size %d count %d\n"), size, sfp->count); memmove(&pino, &(sfp->parent), sizeof(pino)); printf(_(".. ino 0x%llx\n"), (unsigned long long) be64_to_cpu(pino)); count = sfp->count; sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0; i < count; i++) { ino = M_DIROPS(log->l_mp)->sf_get_ino(sfp, sfep); memmove(namebuf, (sfep->name), sfep->namelen); namebuf[sfep->namelen] = '\0'; printf(_("%s ino 0x%llx namelen %d\n"), namebuf, (unsigned long long)ino, sfep->namelen); sfep = M_DIROPS(log->l_mp)->sf_nextentry(sfp, sfep); } } static int xlog_print_trans_inode( struct xlog *log, char **ptr, int len, int *i, int num_ops, int continued) { struct xfs_log_dinode dino; struct xlog_op_header *op_head; struct xfs_inode_log_format dst_lbuf; struct xfs_inode_log_format src_lbuf; struct xfs_inode_log_format *f; int mode; int size; int skip_count; /* * print inode type header region * * memmove to ensure 8-byte alignment for the long longs in * struct xfs_inode_log_format structure * * len can be smaller than struct xfs_inode_log_format * if format data is split over operations */ memmove(&src_lbuf, *ptr, min(sizeof(src_lbuf), len)); (*i)++; /* bump index */ *ptr += len; if (!continued && (len == sizeof(struct xfs_inode_log_format_32) || len == sizeof(struct xfs_inode_log_format))) { f = xfs_inode_item_format_convert((char*)&src_lbuf, len, &dst_lbuf); printf(_("INODE: ")); printf(_("#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n"), f->ilf_size, (unsigned long long)f->ilf_ino, f->ilf_fields, f->ilf_dsize); printf(_(" blkno: %lld len: %d boff: %d\n"), (long long)f->ilf_blkno, f->ilf_len, f->ilf_boffset); } else { ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ f = (struct xfs_inode_log_format *)&src_lbuf; printf(_("INODE: #regs: %d Not printing rest of data\n"), f->ilf_size); return f->ilf_size; } skip_count = f->ilf_size-1; if (*i >= num_ops) /* end of LR */ return skip_count; /* core inode comes 2nd */ op_head = (xlog_op_header_t *)*ptr; xlog_print_op_header(op_head, *i, ptr); if (op_head->oh_flags & XLOG_CONTINUE_TRANS) { return skip_count; } memmove(&dino, *ptr, sizeof(dino)); mode = dino.di_mode & S_IFMT; size = (int)dino.di_size; xlog_print_trans_inode_core(&dino); *ptr += xfs_log_dinode_size(dino.di_version); skip_count--; switch (f->ilf_fields & (XFS_ILOG_DEV | XFS_ILOG_UUID)) { case XFS_ILOG_DEV: printf(_("DEV inode: no extra region\n")); break; case XFS_ILOG_UUID: printf(_("UUID inode: no extra region\n")); break; } /* Only the inode core is logged */ if (f->ilf_size == 2) return 0; ASSERT(f->ilf_size <= 4); ASSERT((f->ilf_size == 3) || (f->ilf_fields & XFS_ILOG_AFORK)); /* does anything come next */ op_head = (xlog_op_header_t *)*ptr; if (f->ilf_fields & XFS_ILOG_DFORK) { if (*i == num_ops-1) return skip_count; (*i)++; xlog_print_op_header(op_head, *i, ptr); switch (f->ilf_fields & XFS_ILOG_DFORK) { case XFS_ILOG_DEXT: printf(_("EXTENTS inode data\n")); break; case XFS_ILOG_DBROOT: printf(_("BTREE inode data\n")); break; case XFS_ILOG_DDATA: printf(_("LOCAL inode data\n")); if (mode == S_IFDIR) xlog_print_dir2_sf(log, (xfs_dir2_sf_hdr_t *)*ptr, size); break; default: ASSERT((f->ilf_fields & XFS_ILOG_DFORK) == 0); break; } *ptr += be32_to_cpu(op_head->oh_len); if (op_head->oh_flags & XLOG_CONTINUE_TRANS) return skip_count; op_head = (xlog_op_header_t *)*ptr; skip_count--; } if (f->ilf_fields & XFS_ILOG_AFORK) { if (*i == num_ops-1) return skip_count; (*i)++; xlog_print_op_header(op_head, *i, ptr); switch (f->ilf_fields & XFS_ILOG_AFORK) { case XFS_ILOG_AEXT: printf(_("EXTENTS attr data\n")); break; case XFS_ILOG_ABROOT: printf(_("BTREE attr data\n")); break; case XFS_ILOG_ADATA: printf(_("LOCAL attr data\n")); if (mode == S_IFDIR) xlog_print_dir2_sf(log, (xfs_dir2_sf_hdr_t *)*ptr, size); break; default: ASSERT((f->ilf_fields & XFS_ILOG_AFORK) == 0); break; } *ptr += be32_to_cpu(op_head->oh_len); if (op_head->oh_flags & XLOG_CONTINUE_TRANS) return skip_count; skip_count--; } ASSERT(skip_count == 0); return 0; } /* xlog_print_trans_inode */ static int xlog_print_trans_dquot(char **ptr, int len, int *i, int num_ops) { xfs_dq_logformat_t *f; xfs_dq_logformat_t lbuf = {0}; xfs_disk_dquot_t ddq; xlog_op_header_t *head = NULL; int num, skip; /* * print dquot header region * * memmove to ensure 8-byte alignment for the long longs in * xfs_dq_logformat_t structure */ memmove(&lbuf, *ptr, min(sizeof(xfs_dq_logformat_t), len)); f = &lbuf; (*i)++; /* bump index */ *ptr += len; if (len == sizeof(xfs_dq_logformat_t)) { printf(_("#regs: %d id: 0x%x"), f->qlf_size, f->qlf_id); printf(_(" blkno: %lld len: %d boff: %d\n"), (long long)f->qlf_blkno, f->qlf_len, f->qlf_boffset); } else { ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ printf(_("DQUOT: #regs: %d Not printing rest of data\n"), f->qlf_size); return f->qlf_size; } num = f->qlf_size-1; /* Check if all regions in this log item were in the given LR ptr */ if (*i+num > num_ops-1) { skip = num - (num_ops-1-*i); num = num_ops-1-*i; } else { skip = 0; } while (num-- > 0) { head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); ASSERT(be32_to_cpu(head->oh_len) == sizeof(xfs_disk_dquot_t)); memmove(&ddq, *ptr, sizeof(xfs_disk_dquot_t)); printf(_("DQUOT: magic 0x%hx flags 0%ho\n"), be16_to_cpu(ddq.d_magic), ddq.d_flags); *ptr += be32_to_cpu(head->oh_len); } if (head && head->oh_flags & XLOG_CONTINUE_TRANS) skip++; return skip; } /* xlog_print_trans_dquot */ STATIC int xlog_print_trans_icreate( char **ptr, int len, int *i, int num_ops) { struct xfs_icreate_log icl_buf = {0}; struct xfs_icreate_log *icl; memmove(&icl_buf, *ptr, min(sizeof(struct xfs_icreate_log), len)); icl = &icl_buf; *ptr += len; /* handle complete header only */ if (len != sizeof(struct xfs_icreate_log)) { printf(_("ICR: split header, not printing\n")); return 1; /* to skip leftover in next region */ } printf(_("ICR: #ag: %d agbno: 0x%x len: %d\n" " cnt: %d isize: %d gen: 0x%x\n"), be32_to_cpu(icl->icl_ag), be32_to_cpu(icl->icl_agbno), be32_to_cpu(icl->icl_length), be32_to_cpu(icl->icl_count), be32_to_cpu(icl->icl_isize), be32_to_cpu(icl->icl_gen)); return 0; } /****************************************************************************** * * Log print routines * ****************************************************************************** */ void xlog_print_lseek(struct xlog *log, int fd, xfs_daddr_t blkno, int whence) { #define BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) xfs_off_t offset; if (whence == SEEK_SET) offset = BBTOOFF64(blkno+log->l_logBBstart); else offset = BBTOOFF64(blkno); if (lseek(fd, offset, whence) < 0) { fprintf(stderr, _("%s: lseek to %lld failed: %s\n"), progname, (long long)offset, strerror(errno)); exit(1); } } /* xlog_print_lseek */ static void print_lsn(char *string, __be64 *lsn) { printf("%s: %u,%u", string, CYCLE_LSN(be64_to_cpu(*lsn)), BLOCK_LSN(be64_to_cpu(*lsn))); } static int xlog_print_record( struct xlog *log, int fd, int num_ops, int len, int *read_type, char **partial_buf, xlog_rec_header_t *rhead, xlog_rec_ext_header_t *xhdrs, int bad_hdr_warn) { char *buf, *ptr; int read_len, skip, lost_context = 0; int ret, n, i, j, k; if (print_no_print) return NO_ERROR; if (!len) { printf("\n"); return NO_ERROR; } /* read_len must read up to some block boundary */ read_len = (int) BBTOB(BTOBB(len)); /* read_type => don't malloc() new buffer, use old one */ if (*read_type == FULL_READ) { if ((ptr = buf = malloc(read_len)) == NULL) { fprintf(stderr, _("%s: xlog_print_record: malloc failed\n"), progname); exit(1); } } else { read_len -= *read_type; buf = (char *)((intptr_t)(*partial_buf) + (intptr_t)(*read_type)); ptr = *partial_buf; } if ((ret = (int) read(fd, buf, read_len)) == -1) { fprintf(stderr, _("%s: xlog_print_record: read error\n"), progname); exit(1); } /* Did we overflow the end? */ if (*read_type == FULL_READ && BLOCK_LSN(be64_to_cpu(rhead->h_lsn)) + BTOBB(read_len) >= logBBsize) { *read_type = BBTOB(logBBsize - BLOCK_LSN(be64_to_cpu(rhead->h_lsn))-1); *partial_buf = buf; return PARTIAL_READ; } /* Did we read everything? */ if ((ret == 0 && read_len != 0) || ret != read_len) { *read_type = ret; *partial_buf = buf; return PARTIAL_READ; } if (*read_type != FULL_READ) read_len += *read_type; /* Everything read in. Start from beginning of buffer * Unpack the data, by putting the saved cycle-data back * into the first word of each BB. * Do some checks. */ buf = ptr; for (i = 0; ptr < buf + read_len; ptr += BBSIZE, i++) { xlog_rec_header_t *rechead = (xlog_rec_header_t *)ptr; /* sanity checks */ if (be32_to_cpu(rechead->h_magicno) == XLOG_HEADER_MAGIC_NUM) { /* data should not have magicno as first word * as it should by cycle# */ free(buf); return -1; } else { /* verify cycle# * FIXME: cycle+1 should be a macro pv#900369 */ if (be32_to_cpu(rhead->h_cycle) != be32_to_cpu(*(__be32 *)ptr)) { if ((*read_type == FULL_READ) || (be32_to_cpu(rhead->h_cycle) + 1 != be32_to_cpu(*(__be32 *)ptr))) { free(buf); return -1; } } } /* copy back the data from the header */ if (i < XLOG_HEADER_CYCLE_SIZE / BBSIZE) { /* from 1st header */ *(__be32 *)ptr = rhead->h_cycle_data[i]; } else { ASSERT(xhdrs != NULL); /* from extra headers */ j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); *(__be32 *)ptr = xhdrs[j-1].xh_cycle_data[k]; } } ptr = buf; for (i=0; ioh_flags & XLOG_WAS_CONT_TRANS) || (op_head->oh_flags & XLOG_CONTINUE_TRANS)); if (continued && be32_to_cpu(op_head->oh_len) == 0) continue; if (print_no_data) { for (n = 0; n < be32_to_cpu(op_head->oh_len); n++) { printf("0x%02x ", (unsigned int)*ptr); if (n % 16 == 15) printf("\n"); ptr++; } printf("\n"); continue; } /* print transaction data */ if (xlog_print_find_tid(be32_to_cpu(op_head->oh_tid), op_head->oh_flags & XLOG_WAS_CONT_TRANS)) { printf(_("Left over region from split log item\n")); /* Skip this leftover bit */ ptr += be32_to_cpu(op_head->oh_len); /* We've lost context; don't complain if next one looks bad too */ lost_context = 1; continue; } if (be32_to_cpu(op_head->oh_len) != 0) { if (*(uint *)ptr == XFS_TRANS_HEADER_MAGIC) { skip = xlog_print_trans_header(&ptr, be32_to_cpu(op_head->oh_len)); } else { switch (*(unsigned short *)ptr) { case XFS_LI_BUF: { skip = xlog_print_trans_buffer(&ptr, be32_to_cpu(op_head->oh_len), &i, num_ops); break; } case XFS_LI_ICREATE: { skip = xlog_print_trans_icreate(&ptr, be32_to_cpu(op_head->oh_len), &i, num_ops); break; } case XFS_LI_INODE: { skip = xlog_print_trans_inode(log, &ptr, be32_to_cpu(op_head->oh_len), &i, num_ops, continued); break; } case XFS_LI_DQUOT: { skip = xlog_print_trans_dquot(&ptr, be32_to_cpu(op_head->oh_len), &i, num_ops); break; } case XFS_LI_EFI: { skip = xlog_print_trans_efi(&ptr, be32_to_cpu(op_head->oh_len), continued); break; } case XFS_LI_EFD: { skip = xlog_print_trans_efd(&ptr, be32_to_cpu(op_head->oh_len)); break; } case XFS_LI_RUI: { skip = xlog_print_trans_rui(&ptr, be32_to_cpu(op_head->oh_len), continued); break; } case XFS_LI_RUD: { skip = xlog_print_trans_rud(&ptr, be32_to_cpu(op_head->oh_len)); break; } case XFS_LI_CUI: { skip = xlog_print_trans_cui(&ptr, be32_to_cpu(op_head->oh_len), continued); break; } case XFS_LI_CUD: { skip = xlog_print_trans_cud(&ptr, be32_to_cpu(op_head->oh_len)); break; } case XFS_LI_BUI: { skip = xlog_print_trans_bui(&ptr, be32_to_cpu(op_head->oh_len), continued); break; } case XFS_LI_BUD: { skip = xlog_print_trans_bud(&ptr, be32_to_cpu(op_head->oh_len)); break; } case XFS_LI_QUOTAOFF: { skip = xlog_print_trans_qoff(&ptr, be32_to_cpu(op_head->oh_len)); break; } case XLOG_UNMOUNT_TYPE: { printf(_("Unmount filesystem\n")); skip = 0; break; } default: { if (bad_hdr_warn && !lost_context) { fprintf(stderr, _("%s: unknown log operation type (%x)\n"), progname, *(unsigned short *)ptr); if (print_exit) { free(buf); return BAD_HEADER; } } else { printf( _("Left over region from split log item\n")); } skip = 0; ptr += be32_to_cpu(op_head->oh_len); lost_context = 0; } } /* switch */ } /* else */ if (skip != 0) xlog_print_add_to_trans(be32_to_cpu(op_head->oh_tid), skip); } } printf("\n"); free(buf); return NO_ERROR; } /* xlog_print_record */ static int xlog_print_rec_head(xlog_rec_header_t *head, int *len, int bad_hdr_warn) { int i; char uub[64]; int datalen,bbs; if (print_no_print) return be32_to_cpu(head->h_num_logops); if (!head->h_magicno) return ZEROED_LOG; if (be32_to_cpu(head->h_magicno) != XLOG_HEADER_MAGIC_NUM) { if (bad_hdr_warn) printf(_("Header 0x%x wanted 0x%x\n"), be32_to_cpu(head->h_magicno), XLOG_HEADER_MAGIC_NUM); return BAD_HEADER; } /* check for cleared blocks written by xlog_clear_stale_blocks() */ if (!head->h_len && !head->h_crc && !head->h_prev_block && !head->h_num_logops && !head->h_size) return CLEARED_BLKS; datalen=be32_to_cpu(head->h_len); bbs=BTOBB(datalen); printf(_("cycle: %d version: %d "), be32_to_cpu(head->h_cycle), be32_to_cpu(head->h_version)); print_lsn(" lsn", &head->h_lsn); print_lsn(" tail_lsn", &head->h_tail_lsn); printf("\n"); printf(_("length of Log Record: %d prev offset: %d num ops: %d\n"), datalen, be32_to_cpu(head->h_prev_block), be32_to_cpu(head->h_num_logops)); if (print_overwrite) { printf(_("cycle num overwrites: ")); for (i=0; i< min(bbs, XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) printf("%d - 0x%x ", i, be32_to_cpu(head->h_cycle_data[i])); printf("\n"); } platform_uuid_unparse(&head->h_fs_uuid, uub); printf(_("uuid: %s format: "), uub); switch (be32_to_cpu(head->h_fmt)) { case XLOG_FMT_UNKNOWN: printf(_("unknown\n")); break; case XLOG_FMT_LINUX_LE: printf(_("little endian linux\n")); break; case XLOG_FMT_LINUX_BE: printf(_("big endian linux\n")); break; case XLOG_FMT_IRIX_BE: printf(_("big endian irix\n")); break; default: printf("? (%d)\n", be32_to_cpu(head->h_fmt)); break; } printf(_("h_size: %d\n"), be32_to_cpu(head->h_size)); *len = be32_to_cpu(head->h_len); return(be32_to_cpu(head->h_num_logops)); } /* xlog_print_rec_head */ static void xlog_print_rec_xhead(xlog_rec_ext_header_t *head, int coverage) { int i; print_xlog_xhdr_line(); printf(_("extended-header: cycle: %d\n"), be32_to_cpu(head->xh_cycle)); if (print_overwrite) { printf(_("cycle num overwrites: ")); for (i = 0; i < coverage; i++) printf("%d - 0x%x ", i, be32_to_cpu(head->xh_cycle_data[i])); printf("\n"); } } /* xlog_print_rec_xhead */ static void print_xlog_bad_zeroed(xfs_daddr_t blkno) { print_stars(); printf(_("* ERROR: found data after zeroed blocks block=%-21lld *\n"), (long long)blkno); print_stars(); if (print_exit) xlog_exit("Bad log - data after zeroed blocks"); } /* print_xlog_bad_zeroed */ static void print_xlog_bad_header(xfs_daddr_t blkno, char *buf) { print_stars(); printf(_("* ERROR: header cycle=%-11d block=%-21lld *\n"), xlog_get_cycle(buf), (long long)blkno); print_stars(); if (print_exit) xlog_exit("Bad log record header"); } /* print_xlog_bad_header */ static void print_xlog_bad_data(xfs_daddr_t blkno) { print_stars(); printf(_("* ERROR: data block=%-21lld *\n"), (long long)blkno); print_stars(); if (print_exit) xlog_exit("Bad data in log"); } /* print_xlog_bad_data */ static void print_xlog_bad_reqd_hdrs(xfs_daddr_t blkno, int num_reqd, int num_hdrs) { print_stars(); printf(_("* ERROR: for header block=%lld\n" "* not enough hdrs for data length, " "required num = %d, hdr num = %d\n"), (long long)blkno, num_reqd, num_hdrs); print_stars(); if (print_exit) xlog_exit(_("Not enough headers for data length.")); } /* print_xlog_bad_reqd_hdrs */ static void xlog_reallocate_xhdrs(int num_hdrs, xlog_rec_ext_header_t **ret_xhdrs) { int len = (num_hdrs-1) * sizeof(xlog_rec_ext_header_t); *ret_xhdrs = (xlog_rec_ext_header_t *)realloc(*ret_xhdrs, len); if (*ret_xhdrs == NULL) { fprintf(stderr, _("%s: xlog_print: malloc failed for ext hdrs\n"), progname); exit(1); } } /* for V2 logs read each extra hdr and print it out */ static int xlog_print_extended_headers( int fd, int len, xfs_daddr_t *blkno, xlog_rec_header_t *hdr, int *ret_num_hdrs, xlog_rec_ext_header_t **ret_xhdrs) { int i, j; int coverage_bb; int num_hdrs; int num_required; char xhbuf[XLOG_HEADER_SIZE]; xlog_rec_ext_header_t *xhdr; num_required = howmany(len, XLOG_HEADER_CYCLE_SIZE); num_hdrs = be32_to_cpu(hdr->h_size) / XLOG_HEADER_CYCLE_SIZE; if (be32_to_cpu(hdr->h_size) % XLOG_HEADER_CYCLE_SIZE) num_hdrs++; if (num_required > num_hdrs) { print_xlog_bad_reqd_hdrs((*blkno)-1, num_required, num_hdrs); } if (num_hdrs == 1) { free(*ret_xhdrs); *ret_xhdrs = NULL; *ret_num_hdrs = 1; return 0; } if (*ret_xhdrs == NULL || num_hdrs > *ret_num_hdrs) { xlog_reallocate_xhdrs(num_hdrs, ret_xhdrs); } *ret_num_hdrs = num_hdrs; /* don't include 1st header */ for (i = 1, xhdr = *ret_xhdrs; i < num_hdrs; i++, (*blkno)++, xhdr++) { /* read one extra header blk */ if (read(fd, xhbuf, 512) == 0) { printf(_("%s: physical end of log\n"), progname); print_xlog_record_line(); /* reached the end so return 1 */ return 1; } if (print_only_data) { printf(_("BLKNO: %lld\n"), (long long)*blkno); xlog_recover_print_data(xhbuf, 512); } else { if (i == num_hdrs - 1) { /* last header */ coverage_bb = BTOBB(len) % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); } else { /* earliear header */ coverage_bb = XLOG_HEADER_CYCLE_SIZE / BBSIZE; } xlog_print_rec_xhead((xlog_rec_ext_header_t*)xhbuf, coverage_bb); } /* Copy from buffer into xhdrs array for later. * Could endian convert here but then code later on * will look asymmetric with the 1 hdr normal case * which does endian coversion on access. */ xhdr->xh_cycle = ((xlog_rec_ext_header_t*)xhbuf)->xh_cycle; for (j = 0; j < XLOG_HEADER_CYCLE_SIZE / BBSIZE; j++) { xhdr->xh_cycle_data[j] = ((xlog_rec_ext_header_t*)xhbuf)->xh_cycle_data[j]; } } return 0; } /* * This code is gross and needs to be rewritten. */ void xfs_log_print(struct xlog *log, int fd, int print_block_start) { char hbuf[XLOG_HEADER_SIZE]; xlog_rec_header_t *hdr = (xlog_rec_header_t *)&hbuf[0]; xlog_rec_ext_header_t *xhdrs = NULL; int num_ops, len, num_hdrs = 1; xfs_daddr_t block_end = 0, block_start, blkno, error; xfs_daddr_t zeroed_blkno = 0, cleared_blkno = 0; int read_type = FULL_READ; char *partial_buf; int zeroed = 0; int cleared = 0; int first_hdr_found = 0; logBBsize = log->l_logBBsize; /* * Normally, block_start and block_end are the same value since we * are printing the entire log. However, if the start block is given, * we still end at the end of the logical log. */ if ((error = xlog_print_find_oldest(log, &block_end))) { fprintf(stderr, _("%s: problem finding oldest LR\n"), progname); return; } if (print_block_start == -1) block_start = block_end; else block_start = print_block_start; xlog_print_lseek(log, fd, block_start, SEEK_SET); blkno = block_start; for (;;) { if (read(fd, hbuf, 512) == 0) { printf(_("%s: physical end of log\n"), progname); print_xlog_record_line(); break; } if (print_only_data) { printf(_("BLKNO: %lld\n"), (long long)blkno); xlog_recover_print_data(hbuf, 512); blkno++; goto loop; } num_ops = xlog_print_rec_head(hdr, &len, first_hdr_found); blkno++; if (zeroed && num_ops != ZEROED_LOG) { printf(_("%s: after %d zeroed blocks\n"), progname, zeroed); /* once we find zeroed blocks - that's all we expect */ print_xlog_bad_zeroed(blkno-1); /* reset count since we're assuming previous zeroed blocks * were bad */ zeroed = 0; } if (num_ops == ZEROED_LOG || num_ops == CLEARED_BLKS || num_ops == BAD_HEADER) { if (num_ops == ZEROED_LOG) { if (zeroed == 0) zeroed_blkno = blkno-1; zeroed++; } else if (num_ops == CLEARED_BLKS) { if (cleared == 0) cleared_blkno = blkno-1; cleared++; } else { if (!first_hdr_found) block_start = blkno; else print_xlog_bad_header(blkno-1, hbuf); } goto loop; } if (be32_to_cpu(hdr->h_version) == 2) { if (xlog_print_extended_headers(fd, len, &blkno, hdr, &num_hdrs, &xhdrs) != 0) break; } error = xlog_print_record(log, fd, num_ops, len, &read_type, &partial_buf, hdr, xhdrs, first_hdr_found); first_hdr_found++; switch (error) { case 0: { blkno += BTOBB(len); if (print_block_start != -1 && blkno >= block_end) /* If start specified, we */ goto end; /* end early */ break; } case -1: { print_xlog_bad_data(blkno-1); if (print_block_start != -1 && blkno >= block_end) /* If start specified, */ goto end; /* we end early */ xlog_print_lseek(log, fd, blkno, SEEK_SET); goto loop; } case PARTIAL_READ: { print_xlog_record_line(); printf(_("%s: physical end of log\n"), progname); print_xlog_record_line(); blkno = 0; xlog_print_lseek(log, fd, 0, SEEK_SET); /* * We may have hit the end of the log when we started at 0. * In this case, just end. */ if (block_start == 0) goto end; goto partial_log_read; } default: xlog_panic(_("illegal value")); } print_xlog_record_line(); loop: if (blkno >= logBBsize) { if (cleared) { printf(_("%s: skipped %d cleared blocks in range: %lld - %lld\n"), progname, cleared, (long long)(cleared_blkno), (long long)(cleared + cleared_blkno - 1)); if (cleared == logBBsize) printf(_("%s: totally cleared log\n"), progname); cleared=0; } if (zeroed) { printf(_("%s: skipped %d zeroed blocks in range: %lld - %lld\n"), progname, zeroed, (long long)(zeroed_blkno), (long long)(zeroed + zeroed_blkno - 1)); if (zeroed == logBBsize) printf(_("%s: totally zeroed log\n"), progname); zeroed=0; } printf(_("%s: physical end of log\n"), progname); print_xlog_record_line(); break; } } /* Do we need to print the first part of physical log? */ if (block_start != 0) { blkno = 0; xlog_print_lseek(log, fd, 0, SEEK_SET); for (;;) { if (read(fd, hbuf, 512) == 0) { xlog_panic(_("xlog_find_head: bad read")); } if (print_only_data) { printf(_("BLKNO: %lld\n"), (long long)blkno); xlog_recover_print_data(hbuf, 512); blkno++; goto loop2; } num_ops = xlog_print_rec_head(hdr, &len, first_hdr_found); blkno++; if (num_ops == ZEROED_LOG || num_ops == CLEARED_BLKS || num_ops == BAD_HEADER) { /* we only expect zeroed log entries or cleared log * entries at the end of the _physical_ log, * so treat them the same as bad blocks here */ print_xlog_bad_header(blkno-1, hbuf); if (blkno >= block_end) break; continue; } if (be32_to_cpu(hdr->h_version) == 2) { if (xlog_print_extended_headers(fd, len, &blkno, hdr, &num_hdrs, &xhdrs) != 0) break; } partial_log_read: error= xlog_print_record(log, fd, num_ops, len, &read_type, &partial_buf, (xlog_rec_header_t *)hbuf, xhdrs, first_hdr_found); if (read_type != FULL_READ) len -= read_type; read_type = FULL_READ; if (!error) blkno += BTOBB(len); else { print_xlog_bad_data(blkno-1); xlog_print_lseek(log, fd, blkno, SEEK_SET); goto loop2; } print_xlog_record_line(); loop2: if (blkno >= block_end) break; } } end: printf(_("%s: logical end of log\n"), progname); print_xlog_record_line(); } /* * if necessary, convert an xfs_inode_log_format struct from the old 32bit version * (which can have different field alignments) to the native 64 bit version */ struct xfs_inode_log_format * xfs_inode_item_format_convert(char *src_buf, uint len, struct xfs_inode_log_format *in_f) { struct xfs_inode_log_format_32 *in_f32; /* if we have native format then just return buf without copying data */ if (len == sizeof(struct xfs_inode_log_format)) { return (struct xfs_inode_log_format *)src_buf; } in_f32 = (struct xfs_inode_log_format_32 *)src_buf; in_f->ilf_type = in_f32->ilf_type; in_f->ilf_size = in_f32->ilf_size; in_f->ilf_fields = in_f32->ilf_fields; in_f->ilf_asize = in_f32->ilf_asize; in_f->ilf_dsize = in_f32->ilf_dsize; in_f->ilf_ino = in_f32->ilf_ino; /* copy biggest field of ilf_u */ memcpy(&in_f->ilf_u.__pad, &in_f32->ilf_u.__pad, sizeof(in_f->ilf_u.__pad)); in_f->ilf_blkno = in_f32->ilf_blkno; in_f->ilf_len = in_f32->ilf_len; in_f->ilf_boffset = in_f32->ilf_boffset; return in_f; } xfsprogs-5.3.0/logprint/log_print_all.c0000644000175000017500000003275313435336037020114 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "logprint.h" /* * Start is defined to be the block pointing to the oldest valid log record. */ int xlog_print_find_oldest( struct xlog *log, xfs_daddr_t *last_blk) { xfs_buf_t *bp; xfs_daddr_t first_blk; uint first_half_cycle, last_half_cycle; int error = 0; if (xlog_find_zeroed(log, &first_blk)) return 0; first_blk = 0; /* read first block */ bp = xlog_get_bp(log, 1); xlog_bread_noalign(log, 0, 1, bp); first_half_cycle = xlog_get_cycle(bp->b_addr); *last_blk = log->l_logBBsize-1; /* read last block */ xlog_bread_noalign(log, *last_blk, 1, bp); last_half_cycle = xlog_get_cycle(bp->b_addr); ASSERT(last_half_cycle != 0); if (first_half_cycle == last_half_cycle) /* all cycle nos are same */ *last_blk = 0; else /* have 1st and last; look for middle cycle */ error = xlog_find_cycle_start(log, bp, first_blk, last_blk, last_half_cycle); xlog_put_bp(bp); return error; } void xlog_recover_print_data( char *p, int len) { if (print_data) { uint *dp = (uint *)p; int nums = len >> 2; int j = 0; while (j < nums) { if ((j % 8) == 0) printf("%2x ", j); printf("%8x ", *dp); dp++; j++; if ((j % 8) == 0) printf("\n"); } printf("\n"); } } STATIC void xlog_recover_print_buffer( xlog_recover_item_t *item) { xfs_agi_t *agi; xfs_agf_t *agf; xfs_buf_log_format_t *f; char *p; int len, num, i; xfs_daddr_t blkno; xfs_disk_dquot_t *ddq; f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; printf(" "); ASSERT(f->blf_type == XFS_LI_BUF); printf(_("BUF: #regs:%d start blkno:0x%llx len:%d bmap size:%d flags:0x%x\n"), f->blf_size, (long long)f->blf_blkno, f->blf_len, f->blf_map_size, f->blf_flags); blkno = (xfs_daddr_t)f->blf_blkno; num = f->blf_size-1; i = 1; while (num-- > 0) { p = item->ri_buf[i].i_addr; len = item->ri_buf[i].i_len; i++; if (blkno == 0) { /* super block */ printf(_(" SUPER Block Buffer:\n")); if (!print_buffer) continue; printf(_(" icount:%llu ifree:%llu "), (unsigned long long) be64_to_cpu(*(__be64 *)(p)), (unsigned long long) be64_to_cpu(*(__be64 *)(p+8))); printf(_("fdblks:%llu frext:%llu\n"), (unsigned long long) be64_to_cpu(*(__be64 *)(p+16)), (unsigned long long) be64_to_cpu(*(__be64 *)(p+24))); printf(_(" sunit:%u swidth:%u\n"), be32_to_cpu(*(__be32 *)(p+56)), be32_to_cpu(*(__be32 *)(p+60))); } else if (be32_to_cpu(*(__be32 *)p) == XFS_AGI_MAGIC) { int bucket, buckets; agi = (xfs_agi_t *)p; printf(_(" AGI Buffer: (XAGI)\n")); if (!print_buffer) continue; printf(_(" ver:%d "), be32_to_cpu(agi->agi_versionnum)); printf(_("seq#:%d len:%d cnt:%d root:%d\n"), be32_to_cpu(agi->agi_seqno), be32_to_cpu(agi->agi_length), be32_to_cpu(agi->agi_count), be32_to_cpu(agi->agi_root)); printf(_(" level:%d free#:0x%x newino:0x%x\n"), be32_to_cpu(agi->agi_level), be32_to_cpu(agi->agi_freecount), be32_to_cpu(agi->agi_newino)); if (len == 128) { buckets = 17; } else if (len == 256) { buckets = 32 + 17; } else { buckets = XFS_AGI_UNLINKED_BUCKETS; } for (bucket = 0; bucket < buckets;) { int col; printf(_("bucket[%d - %d]: "), bucket, bucket+3); for (col = 0; col < 4; col++, bucket++) { if (bucket < buckets) { printf("0x%x ", be32_to_cpu(agi->agi_unlinked[bucket])); } } printf("\n"); } } else if (be32_to_cpu(*(__be32 *)p) == XFS_AGF_MAGIC) { agf = (xfs_agf_t *)p; printf(_(" AGF Buffer: (XAGF)\n")); if (!print_buffer) continue; printf(_(" ver:%d seq#:%d len:%d \n"), be32_to_cpu(agf->agf_versionnum), be32_to_cpu(agf->agf_seqno), be32_to_cpu(agf->agf_length)); printf(_(" root BNO:%d CNT:%d\n"), be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi]), be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); printf(_(" level BNO:%d CNT:%d\n"), be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]), be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); printf(_(" 1st:%d last:%d cnt:%d " "freeblks:%d longest:%d\n"), be32_to_cpu(agf->agf_flfirst), be32_to_cpu(agf->agf_fllast), be32_to_cpu(agf->agf_flcount), be32_to_cpu(agf->agf_freeblks), be32_to_cpu(agf->agf_longest)); } else if (*(uint *)p == XFS_DQUOT_MAGIC) { ddq = (xfs_disk_dquot_t *)p; printf(_(" DQUOT Buffer:\n")); if (!print_buffer) continue; printf(_(" UIDs 0x%lx-0x%lx\n"), (unsigned long)be32_to_cpu(ddq->d_id), (unsigned long)be32_to_cpu(ddq->d_id) + (BBTOB(f->blf_len) / sizeof(xfs_dqblk_t)) - 1); } else { printf(_(" BUF DATA\n")); if (!print_buffer) continue; xlog_recover_print_data(p, len); } } } STATIC void xlog_recover_print_quotaoff( xlog_recover_item_t *item) { xfs_qoff_logformat_t *qoff_f; char str[32] = { 0 }; qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr; ASSERT(qoff_f); if (qoff_f->qf_flags & XFS_UQUOTA_ACCT) strcat(str, "USER QUOTA"); if (qoff_f->qf_flags & XFS_GQUOTA_ACCT) strcat(str, "GROUP QUOTA"); if (qoff_f->qf_flags & XFS_PQUOTA_ACCT) strcat(str, "PROJECT QUOTA"); printf(_("\tQUOTAOFF: #regs:%d type:%s\n"), qoff_f->qf_size, str); } STATIC void xlog_recover_print_dquot( xlog_recover_item_t *item) { xfs_dq_logformat_t *f; xfs_disk_dquot_t *d; f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr; ASSERT(f); ASSERT(f->qlf_len == 1); d = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr; printf(_("\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n"), f->qlf_size, (long long)f->qlf_blkno, f->qlf_boffset, f->qlf_id); if (!print_quota) return; printf(_("\t\tmagic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n"), be16_to_cpu(d->d_magic), d->d_version, be32_to_cpu(d->d_id), be32_to_cpu(d->d_id)); printf(_("\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x" "\tino_soft 0x%x\n"), (int)be64_to_cpu(d->d_blk_hardlimit), (int)be64_to_cpu(d->d_blk_softlimit), (int)be64_to_cpu(d->d_ino_hardlimit), (int)be64_to_cpu(d->d_ino_softlimit)); printf(_("\t\tbcount 0x%x (%d) icount 0x%x (%d)\n"), (int)be64_to_cpu(d->d_bcount), (int)be64_to_cpu(d->d_bcount), (int)be64_to_cpu(d->d_icount), (int)be64_to_cpu(d->d_icount)); printf(_("\t\tbtimer 0x%x itimer 0x%x \n"), (int)be32_to_cpu(d->d_btimer), (int)be32_to_cpu(d->d_itimer)); } STATIC void xlog_recover_print_inode_core( struct xfs_log_dinode *di) { printf(_(" CORE inode:\n")); if (!print_inode) return; printf(_(" magic:%c%c mode:0x%x ver:%d format:%d\n"), (di->di_magic>>8) & 0xff, di->di_magic & 0xff, di->di_mode, di->di_version, di->di_format); printf(_(" uid:%d gid:%d nlink:%d projid:0x%04x%04x\n"), di->di_uid, di->di_gid, di->di_nlink, di->di_projid_hi, di->di_projid_lo); printf(_(" atime:%d mtime:%d ctime:%d\n"), di->di_atime.t_sec, di->di_mtime.t_sec, di->di_ctime.t_sec); printf(_(" flushiter:%d\n"), di->di_flushiter); printf(_(" size:0x%llx nblks:0x%llx exsize:%d " "nextents:%d anextents:%d\n"), (unsigned long long) di->di_size, (unsigned long long)di->di_nblocks, di->di_extsize, di->di_nextents, (int)di->di_anextents); printf(_(" forkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x " "gen:%u\n"), (int)di->di_forkoff, di->di_dmevmask, (int)di->di_dmstate, (int)di->di_flags, di->di_gen); if (di->di_version == 3) { printf(_(" flags2 0x%llx cowextsize 0x%x\n"), (unsigned long long)di->di_flags2, di->di_cowextsize); } } STATIC void xlog_recover_print_inode( xlog_recover_item_t *item) { struct xfs_inode_log_format f_buf; struct xfs_inode_log_format *f; int attr_index; int hasdata; int hasattr; ASSERT(item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format_32) || item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)); f = xfs_inode_item_format_convert(item->ri_buf[0].i_addr, item->ri_buf[0].i_len, &f_buf); printf(_(" INODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n"), f->ilf_size, (unsigned long long)f->ilf_ino, f->ilf_fields, f->ilf_dsize); /* core inode comes 2nd */ ASSERT(item->ri_buf[1].i_len == xfs_log_dinode_size(2) || item->ri_buf[1].i_len == xfs_log_dinode_size(3)); xlog_recover_print_inode_core((struct xfs_log_dinode *) item->ri_buf[1].i_addr); hasdata = (f->ilf_fields & XFS_ILOG_DFORK) != 0; hasattr = (f->ilf_fields & XFS_ILOG_AFORK) != 0; /* does anything come next */ switch (f->ilf_fields & (XFS_ILOG_DFORK|XFS_ILOG_DEV|XFS_ILOG_UUID)) { case XFS_ILOG_DEXT: ASSERT(f->ilf_size == 3 + hasattr); printf(_(" DATA FORK EXTENTS inode data:\n")); if (print_inode && print_data) xlog_recover_print_data(item->ri_buf[2].i_addr, item->ri_buf[2].i_len); break; case XFS_ILOG_DBROOT: ASSERT(f->ilf_size == 3 + hasattr); printf(_(" DATA FORK BTREE inode data:\n")); if (print_inode && print_data) xlog_recover_print_data(item->ri_buf[2].i_addr, item->ri_buf[2].i_len); break; case XFS_ILOG_DDATA: ASSERT(f->ilf_size == 3 + hasattr); printf(_(" DATA FORK LOCAL inode data:\n")); if (print_inode && print_data) xlog_recover_print_data(item->ri_buf[2].i_addr, item->ri_buf[2].i_len); break; case XFS_ILOG_DEV: ASSERT(f->ilf_size == 2 + hasattr); printf(_(" DEV inode: no extra region\n")); break; case XFS_ILOG_UUID: ASSERT(f->ilf_size == 2 + hasattr); printf(_(" UUID inode: no extra region\n")); break; case 0: ASSERT(f->ilf_size == 2 + hasattr); break; default: xlog_panic("xlog_print_trans_inode: illegal inode type"); } if (hasattr) { attr_index = 2 + hasdata; switch (f->ilf_fields & XFS_ILOG_AFORK) { case XFS_ILOG_AEXT: ASSERT(f->ilf_size == 3 + hasdata); printf(_(" ATTR FORK EXTENTS inode data:\n")); if (print_inode && print_data) xlog_recover_print_data( item->ri_buf[attr_index].i_addr, item->ri_buf[attr_index].i_len); break; case XFS_ILOG_ABROOT: ASSERT(f->ilf_size == 3 + hasdata); printf(_(" ATTR FORK BTREE inode data:\n")); if (print_inode && print_data) xlog_recover_print_data( item->ri_buf[attr_index].i_addr, item->ri_buf[attr_index].i_len); break; case XFS_ILOG_ADATA: ASSERT(f->ilf_size == 3 + hasdata); printf(_(" ATTR FORK LOCAL inode data:\n")); if (print_inode && print_data) xlog_recover_print_data( item->ri_buf[attr_index].i_addr, item->ri_buf[attr_index].i_len); break; default: xlog_panic("%s: illegal inode log flag", __FUNCTION__); } } } STATIC void xlog_recover_print_icreate( struct xlog_recover_item *item) { struct xfs_icreate_log *icl; icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr; printf(_(" ICR: #ag: %d agbno: 0x%x len: %d\n" " cnt: %d isize: %d gen: 0x%x\n"), be32_to_cpu(icl->icl_ag), be32_to_cpu(icl->icl_agbno), be32_to_cpu(icl->icl_length), be32_to_cpu(icl->icl_count), be32_to_cpu(icl->icl_isize), be32_to_cpu(icl->icl_gen)); } void xlog_recover_print_logitem( xlog_recover_item_t *item) { switch (ITEM_TYPE(item)) { case XFS_LI_BUF: xlog_recover_print_buffer(item); break; case XFS_LI_ICREATE: xlog_recover_print_icreate(item); break; case XFS_LI_INODE: xlog_recover_print_inode(item); break; case XFS_LI_EFD: xlog_recover_print_efd(item); break; case XFS_LI_EFI: xlog_recover_print_efi(item); break; case XFS_LI_RUD: xlog_recover_print_rud(item); break; case XFS_LI_RUI: xlog_recover_print_rui(item); break; case XFS_LI_CUD: xlog_recover_print_cud(item); break; case XFS_LI_CUI: xlog_recover_print_cui(item); break; case XFS_LI_BUD: xlog_recover_print_bud(item); break; case XFS_LI_BUI: xlog_recover_print_bui(item); break; case XFS_LI_DQUOT: xlog_recover_print_dquot(item); break; case XFS_LI_QUOTAOFF: xlog_recover_print_quotaoff(item); break; default: printf(_("xlog_recover_print_logitem: illegal type\n")); break; } } static void xlog_recover_print_item( xlog_recover_item_t *item) { int i; switch (ITEM_TYPE(item)) { case XFS_LI_BUF: printf("BUF"); break; case XFS_LI_ICREATE: printf("ICR"); break; case XFS_LI_INODE: printf("INO"); break; case XFS_LI_EFD: printf("EFD"); break; case XFS_LI_EFI: printf("EFI"); break; case XFS_LI_RUD: printf("RUD"); break; case XFS_LI_RUI: printf("RUI"); break; case XFS_LI_CUD: printf("CUD"); break; case XFS_LI_CUI: printf("CUI"); break; case XFS_LI_BUD: printf("BUD"); break; case XFS_LI_BUI: printf("BUI"); break; case XFS_LI_DQUOT: printf("DQ "); break; case XFS_LI_QUOTAOFF: printf("QOFF"); break; default: cmn_err(CE_PANIC, _("%s: illegal type"), __FUNCTION__); break; } /* type isn't filled in yet printf(_("ITEM: type: %d cnt: %d total: %d "), item->ri_type, item->ri_cnt, item->ri_total); */ printf(_(": cnt:%d total:%d "), item->ri_cnt, item->ri_total); for (i=0; iri_cnt; i++) { printf(_("a:0x%lx len:%d "), (long)item->ri_buf[i].i_addr, item->ri_buf[i].i_len); } printf("\n"); xlog_recover_print_logitem(item); } void xlog_recover_print_trans( xlog_recover_t *trans, struct list_head *itemq, int print) { xlog_recover_item_t *item; if (print < 3) return; print_xlog_record_line(); xlog_recover_print_trans_head(trans); list_for_each_entry(item, itemq, ri_list) xlog_recover_print_item(item); } xfsprogs-5.3.0/logprint/log_print_trans.c0000644000175000017500000000415113435336037020462 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "logprint.h" void xlog_recover_print_trans_head( xlog_recover_t *tr) { printf(_("TRANS: tid:0x%x #items:%d trans:0x%x q:0x%lx\n"), tr->r_log_tid, tr->r_theader.th_num_items, tr->r_theader.th_tid, (long)&tr->r_itemq); } int xlog_recover_do_trans( struct xlog *log, xlog_recover_t *trans, int pass) { xlog_recover_print_trans(trans, &trans->r_itemq, 3); return 0; } void xfs_log_print_trans( struct xlog *log, int print_block_start) { xfs_daddr_t head_blk, tail_blk; int error; error = xlog_find_tail(log, &head_blk, &tail_blk); if (error) { fprintf(stderr, _("%s: failed to find head and tail, error: %d\n"), progname, error); exit(1); } printf(_(" log tail: %lld head: %lld state: %s\n"), (long long)tail_blk, (long long)head_blk, (tail_blk == head_blk)?"":""); if (print_block_start != -1) { printf(_(" override tail: %d\n"), print_block_start); tail_blk = print_block_start; } printf("\n"); print_record_header = 1; if (head_blk == tail_blk) return; /* * Version 5 superblock log feature mask validation. We know the * log is dirty so check if there are any unknown log features * in what we need to recover. If there are unknown features * (e.g. unsupported transactions) then warn about it. */ if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 && xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb, XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) { printf(_( "Superblock has unknown incompatible log features (0x%x) enabled.\n" "Output may be incomplete or inaccurate. It is recommended that you\n" "upgrade your xfsprogs installation to match the filesystem features.\n"), (log->l_mp->m_sb.sb_features_log_incompat & XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)); } if ((error = xlog_do_recovery_pass(log, head_blk, tail_blk, XLOG_RECOVER_PASS1))) { fprintf(stderr, _("%s: failed in xfs_do_recovery_pass, error: %d\n"), progname, error); exit(1); } } xfsprogs-5.3.0/logprint/log_redo.c0000644000175000017500000003535113435336037017056 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2016 Oracle, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "logprint.h" /* Extent Free Items */ static int xfs_efi_copy_format( char *buf, uint len, struct xfs_efi_log_format *dst_efi_fmt, int continued) { uint i; uint nextents = ((xfs_efi_log_format_t *)buf)->efi_nextents; uint dst_len = sizeof(xfs_efi_log_format_t) + (nextents - 1) * sizeof(xfs_extent_t); uint len32 = sizeof(xfs_efi_log_format_32_t) + (nextents - 1) * sizeof(xfs_extent_32_t); uint len64 = sizeof(xfs_efi_log_format_64_t) + (nextents - 1) * sizeof(xfs_extent_64_t); if (len == dst_len || continued) { memcpy((char *)dst_efi_fmt, buf, len); return 0; } else if (len == len32) { xfs_efi_log_format_32_t *src_efi_fmt_32 = (xfs_efi_log_format_32_t *)buf; dst_efi_fmt->efi_type = src_efi_fmt_32->efi_type; dst_efi_fmt->efi_size = src_efi_fmt_32->efi_size; dst_efi_fmt->efi_nextents = src_efi_fmt_32->efi_nextents; dst_efi_fmt->efi_id = src_efi_fmt_32->efi_id; for (i = 0; i < dst_efi_fmt->efi_nextents; i++) { dst_efi_fmt->efi_extents[i].ext_start = src_efi_fmt_32->efi_extents[i].ext_start; dst_efi_fmt->efi_extents[i].ext_len = src_efi_fmt_32->efi_extents[i].ext_len; } return 0; } else if (len == len64) { xfs_efi_log_format_64_t *src_efi_fmt_64 = (xfs_efi_log_format_64_t *)buf; dst_efi_fmt->efi_type = src_efi_fmt_64->efi_type; dst_efi_fmt->efi_size = src_efi_fmt_64->efi_size; dst_efi_fmt->efi_nextents = src_efi_fmt_64->efi_nextents; dst_efi_fmt->efi_id = src_efi_fmt_64->efi_id; for (i = 0; i < dst_efi_fmt->efi_nextents; i++) { dst_efi_fmt->efi_extents[i].ext_start = src_efi_fmt_64->efi_extents[i].ext_start; dst_efi_fmt->efi_extents[i].ext_len = src_efi_fmt_64->efi_extents[i].ext_len; } return 0; } fprintf(stderr, _("%s: bad size of efi format: %u; expected %u or %u; nextents = %u\n"), progname, len, len32, len64, nextents); return 1; } int xlog_print_trans_efi( char **ptr, uint src_len, int continued) { xfs_efi_log_format_t *src_f, *f = NULL; uint dst_len; xfs_extent_t *ex; int i; int error = 0; int core_size = offsetof(xfs_efi_log_format_t, efi_extents); /* * memmove to ensure 8-byte alignment for the long longs in * xfs_efi_log_format_t structure */ if ((src_f = (xfs_efi_log_format_t *)malloc(src_len)) == NULL) { fprintf(stderr, _("%s: xlog_print_trans_efi: malloc failed\n"), progname); exit(1); } memmove((char*)src_f, *ptr, src_len); *ptr += src_len; /* convert to native format */ dst_len = sizeof(xfs_efi_log_format_t) + (src_f->efi_nextents - 1) * sizeof(xfs_extent_t); if (continued && src_len < core_size) { printf(_("EFI: Not enough data to decode further\n")); error = 1; goto error; } if ((f = (xfs_efi_log_format_t *)malloc(dst_len)) == NULL) { fprintf(stderr, _("%s: xlog_print_trans_efi: malloc failed\n"), progname); exit(1); } if (xfs_efi_copy_format((char*)src_f, src_len, f, continued)) { error = 1; goto error; } printf(_("EFI: #regs: %d num_extents: %d id: 0x%llx\n"), f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id); if (continued) { printf(_("EFI free extent data skipped (CONTINUE set, no space)\n")); goto error; } ex = f->efi_extents; for (i=0; i < f->efi_nextents; i++) { printf("(s: 0x%llx, l: %d) ", (unsigned long long)ex->ext_start, ex->ext_len); if (i % 4 == 3) printf("\n"); ex++; } if (i % 4 != 0) printf("\n"); error: free(src_f); free(f); return error; } /* xlog_print_trans_efi */ void xlog_recover_print_efi( xlog_recover_item_t *item) { xfs_efi_log_format_t *f, *src_f; xfs_extent_t *ex; int i; uint src_len, dst_len; src_f = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr; src_len = item->ri_buf[0].i_len; /* * An xfs_efi_log_format structure contains a variable length array * as the last field. * Each element is of size xfs_extent_32_t or xfs_extent_64_t. * Need to convert to native format. */ dst_len = sizeof(xfs_efi_log_format_t) + (src_f->efi_nextents - 1) * sizeof(xfs_extent_t); if ((f = (xfs_efi_log_format_t *)malloc(dst_len)) == NULL) { fprintf(stderr, _("%s: xlog_recover_print_efi: malloc failed\n"), progname); exit(1); } if (xfs_efi_copy_format((char*)src_f, src_len, f, 0)) { free(f); return; } printf(_(" EFI: #regs:%d num_extents:%d id:0x%llx\n"), f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id); ex = f->efi_extents; printf(" "); for (i=0; i< f->efi_nextents; i++) { printf("(s: 0x%llx, l: %d) ", (unsigned long long)ex->ext_start, ex->ext_len); if (i % 4 == 3) printf("\n"); ex++; } if (i % 4 != 0) printf("\n"); free(f); } int xlog_print_trans_efd(char **ptr, uint len) { xfs_efd_log_format_t *f; xfs_efd_log_format_t lbuf; /* size without extents at end */ uint core_size = sizeof(xfs_efd_log_format_t) - sizeof(xfs_extent_t); /* * memmove to ensure 8-byte alignment for the long longs in * xfs_efd_log_format_t structure */ memmove(&lbuf, *ptr, min(core_size, len)); f = &lbuf; *ptr += len; if (len >= core_size) { printf(_("EFD: #regs: %d num_extents: %d id: 0x%llx\n"), f->efd_size, f->efd_nextents, (unsigned long long)f->efd_efi_id); /* don't print extents as they are not used */ return 0; } else { printf(_("EFD: Not enough data to decode further\n")); return 1; } } /* xlog_print_trans_efd */ void xlog_recover_print_efd( xlog_recover_item_t *item) { xfs_efd_log_format_t *f; f = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr; /* * An xfs_efd_log_format structure contains a variable length array * as the last field. * Each element is of size xfs_extent_32_t or xfs_extent_64_t. * However, the extents are never used and won't be printed. */ printf(_(" EFD: #regs: %d num_extents: %d id: 0x%llx\n"), f->efd_size, f->efd_nextents, (unsigned long long)f->efd_efi_id); } /* Reverse Mapping Update Items */ static int xfs_rui_copy_format( char *buf, uint len, struct xfs_rui_log_format *dst_fmt, int continued) { uint nextents = ((struct xfs_rui_log_format *)buf)->rui_nextents; uint dst_len = xfs_rui_log_format_sizeof(nextents); if (len == dst_len || continued) { memcpy((char *)dst_fmt, buf, len); return 0; } fprintf(stderr, _("%s: bad size of RUI format: %u; expected %u; nextents = %u\n"), progname, len, dst_len, nextents); return 1; } int xlog_print_trans_rui( char **ptr, uint src_len, int continued) { struct xfs_rui_log_format *src_f, *f = NULL; uint dst_len; uint nextents; struct xfs_map_extent *ex; int i; int error = 0; int core_size; core_size = offsetof(struct xfs_rui_log_format, rui_extents); /* * memmove to ensure 8-byte alignment for the long longs in * struct xfs_rui_log_format structure */ src_f = malloc(src_len); if (src_f == NULL) { fprintf(stderr, _("%s: %s: malloc failed\n"), progname, __func__); exit(1); } memmove((char*)src_f, *ptr, src_len); *ptr += src_len; /* convert to native format */ nextents = src_f->rui_nextents; dst_len = xfs_rui_log_format_sizeof(nextents); if (continued && src_len < core_size) { printf(_("RUI: Not enough data to decode further\n")); error = 1; goto error; } f = malloc(dst_len); if (f == NULL) { fprintf(stderr, _("%s: %s: malloc failed\n"), progname, __func__); exit(1); } if (xfs_rui_copy_format((char *)src_f, src_len, f, continued)) { error = 1; goto error; } printf(_("RUI: #regs: %d num_extents: %d id: 0x%llx\n"), f->rui_size, f->rui_nextents, (unsigned long long)f->rui_id); if (continued) { printf(_("RUI extent data skipped (CONTINUE set, no space)\n")); goto error; } ex = f->rui_extents; for (i=0; i < f->rui_nextents; i++) { printf("(s: 0x%llx, l: %d, own: %lld, off: %llu, f: 0x%x) ", (unsigned long long)ex->me_startblock, ex->me_len, (long long)ex->me_owner, (unsigned long long)ex->me_startoff, ex->me_flags); printf("\n"); ex++; } error: free(src_f); free(f); return error; } void xlog_recover_print_rui( struct xlog_recover_item *item) { char *src_f; uint src_len; src_f = item->ri_buf[0].i_addr; src_len = item->ri_buf[0].i_len; xlog_print_trans_rui(&src_f, src_len, 0); } int xlog_print_trans_rud( char **ptr, uint len) { struct xfs_rud_log_format *f; struct xfs_rud_log_format lbuf; /* size without extents at end */ uint core_size = sizeof(struct xfs_rud_log_format); /* * memmove to ensure 8-byte alignment for the long longs in * xfs_efd_log_format_t structure */ memmove(&lbuf, *ptr, min(core_size, len)); f = &lbuf; *ptr += len; if (len >= core_size) { printf(_("RUD: #regs: %d id: 0x%llx\n"), f->rud_size, (unsigned long long)f->rud_rui_id); /* don't print extents as they are not used */ return 0; } else { printf(_("RUD: Not enough data to decode further\n")); return 1; } } void xlog_recover_print_rud( struct xlog_recover_item *item) { char *f; f = item->ri_buf[0].i_addr; xlog_print_trans_rud(&f, sizeof(struct xfs_rud_log_format)); } /* Reference Count Update Items */ static int xfs_cui_copy_format( struct xfs_cui_log_format *cui, uint len, struct xfs_cui_log_format *dst_fmt, int continued) { uint nextents; uint dst_len; nextents = cui->cui_nextents; dst_len = xfs_cui_log_format_sizeof(nextents); if (len == dst_len || continued) { memcpy(dst_fmt, cui, len); return 0; } fprintf(stderr, _("%s: bad size of CUI format: %u; expected %u; nextents = %u\n"), progname, len, dst_len, nextents); return 1; } int xlog_print_trans_cui( char **ptr, uint src_len, int continued) { struct xfs_cui_log_format *src_f, *f = NULL; uint dst_len; uint nextents; struct xfs_phys_extent *ex; int i; int error = 0; int core_size; core_size = offsetof(struct xfs_cui_log_format, cui_extents); src_f = malloc(src_len); if (src_f == NULL) { fprintf(stderr, _("%s: %s: malloc failed\n"), progname, __func__); exit(1); } memcpy(src_f, *ptr, src_len); *ptr += src_len; /* convert to native format */ nextents = src_f->cui_nextents; dst_len = xfs_cui_log_format_sizeof(nextents); if (continued && src_len < core_size) { printf(_("CUI: Not enough data to decode further\n")); error = 1; goto error; } f = malloc(dst_len); if (f == NULL) { fprintf(stderr, _("%s: %s: malloc failed\n"), progname, __func__); exit(1); } if (xfs_cui_copy_format(src_f, src_len, f, continued)) { error = 1; goto error; } printf(_("CUI: #regs: %d num_extents: %d id: 0x%llx\n"), f->cui_size, f->cui_nextents, (unsigned long long)f->cui_id); if (continued) { printf(_("CUI extent data skipped (CONTINUE set, no space)\n")); goto error; } ex = f->cui_extents; for (i=0; i < f->cui_nextents; i++) { printf("(s: 0x%llx, l: %d, f: 0x%x) ", (unsigned long long)ex->pe_startblock, ex->pe_len, ex->pe_flags); printf("\n"); ex++; } error: free(src_f); free(f); return error; } void xlog_recover_print_cui( struct xlog_recover_item *item) { char *src_f; uint src_len; src_f = item->ri_buf[0].i_addr; src_len = item->ri_buf[0].i_len; xlog_print_trans_cui(&src_f, src_len, 0); } int xlog_print_trans_cud( char **ptr, uint len) { struct xfs_cud_log_format *f; struct xfs_cud_log_format lbuf; /* size without extents at end */ uint core_size = sizeof(struct xfs_cud_log_format); memcpy(&lbuf, *ptr, min(core_size, len)); f = &lbuf; *ptr += len; if (len >= core_size) { printf(_("CUD: #regs: %d id: 0x%llx\n"), f->cud_size, (unsigned long long)f->cud_cui_id); /* don't print extents as they are not used */ return 0; } else { printf(_("CUD: Not enough data to decode further\n")); return 1; } } void xlog_recover_print_cud( struct xlog_recover_item *item) { char *f; f = item->ri_buf[0].i_addr; xlog_print_trans_cud(&f, sizeof(struct xfs_cud_log_format)); } /* Block Mapping Update Items */ static int xfs_bui_copy_format( struct xfs_bui_log_format *bui, uint len, struct xfs_bui_log_format *dst_fmt, int continued) { uint nextents; uint dst_len; nextents = bui->bui_nextents; dst_len = xfs_bui_log_format_sizeof(nextents); if (len == dst_len || continued) { memcpy(dst_fmt, bui, len); return 0; } fprintf(stderr, _("%s: bad size of BUI format: %u; expected %u; nextents = %u\n"), progname, len, dst_len, nextents); return 1; } int xlog_print_trans_bui( char **ptr, uint src_len, int continued) { struct xfs_bui_log_format *src_f, *f = NULL; uint dst_len; uint nextents; struct xfs_map_extent *ex; int i; int error = 0; int core_size; core_size = offsetof(struct xfs_bui_log_format, bui_extents); src_f = malloc(src_len); if (src_f == NULL) { fprintf(stderr, _("%s: %s: malloc failed\n"), progname, __func__); exit(1); } memcpy(src_f, *ptr, src_len); *ptr += src_len; /* convert to native format */ nextents = src_f->bui_nextents; dst_len = xfs_bui_log_format_sizeof(nextents); if (continued && src_len < core_size) { printf(_("BUI: Not enough data to decode further\n")); error = 1; goto error; } f = malloc(dst_len); if (f == NULL) { fprintf(stderr, _("%s: %s: malloc failed\n"), progname, __func__); exit(1); } if (xfs_bui_copy_format(src_f, src_len, f, continued)) { error = 1; goto error; } printf(_("BUI: #regs: %d num_extents: %d id: 0x%llx\n"), f->bui_size, f->bui_nextents, (unsigned long long)f->bui_id); if (continued) { printf(_("BUI extent data skipped (CONTINUE set, no space)\n")); goto error; } ex = f->bui_extents; for (i=0; i < f->bui_nextents; i++) { printf("(s: 0x%llx, l: %d, own: %lld, off: %llu, f: 0x%x) ", (unsigned long long)ex->me_startblock, ex->me_len, (long long)ex->me_owner, (unsigned long long)ex->me_startoff, ex->me_flags); printf("\n"); ex++; } error: free(src_f); free(f); return error; } void xlog_recover_print_bui( struct xlog_recover_item *item) { char *src_f; uint src_len; src_f = item->ri_buf[0].i_addr; src_len = item->ri_buf[0].i_len; xlog_print_trans_bui(&src_f, src_len, 0); } int xlog_print_trans_bud( char **ptr, uint len) { struct xfs_bud_log_format *f; struct xfs_bud_log_format lbuf; /* size without extents at end */ uint core_size = sizeof(struct xfs_bud_log_format); memcpy(&lbuf, *ptr, min(core_size, len)); f = &lbuf; *ptr += len; if (len >= core_size) { printf(_("BUD: #regs: %d id: 0x%llx\n"), f->bud_size, (unsigned long long)f->bud_bui_id); /* don't print extents as they are not used */ return 0; } else { printf(_("BUD: Not enough data to decode further\n")); return 1; } } void xlog_recover_print_bud( struct xlog_recover_item *item) { char *f; f = item->ri_buf[0].i_addr; xlog_print_trans_bud(&f, sizeof(struct xfs_bud_log_format)); } xfsprogs-5.3.0/logprint/logprint.c0000644000175000017500000001306713435336037017122 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2004 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include "libxfs.h" #include "libxlog.h" #include "logprint.h" #define OP_PRINT 0 #define OP_PRINT_TRANS 1 #define OP_DUMP 2 #define OP_COPY 3 int print_data; int print_only_data; int print_inode; int print_quota; int print_buffer; int print_overwrite; int print_no_data; int print_no_print; int print_exit = 1; /* -e is now default. specify -c to override */ static int print_operation = OP_PRINT; static void usage(void) { fprintf(stderr, _("Usage: %s [options...] \n\n\ Options:\n\ -c try to continue if error found in log\n\ -C copy the log from the filesystem to filename\n\ -d dump the log in log-record format\n\ -e exit when an error is found in the log\n\ -f specified device is actually a file\n\ -l filename of external log\n\ -n don't try and interpret log data\n\ -o print buffer data in hex\n\ -s block # to start printing\n\ -v print \"overwrite\" data\n\ -t print out transactional view\n\ -b in transactional view, extract buffer info\n\ -i in transactional view, extract inode info\n\ -q in transactional view, extract quota info\n\ -D print only data; no decoding\n\ -V print version information\n"), progname); exit(1); } static int logstat(xfs_mount_t *mp) { int fd; char buf[BBSIZE]; xfs_sb_t *sb; /* On Linux we always read the superblock of the * filesystem. We need this to get the length of the * log. Otherwise we end up seeking forever. -- mkp */ if ((fd = open(x.dname, O_RDONLY)) == -1) { fprintf(stderr, _(" Can't open device %s: %s\n"), x.dname, strerror(errno)); exit(1); } lseek(fd, 0, SEEK_SET); if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { fprintf(stderr, _(" read of XFS superblock failed\n")); exit(1); } close (fd); if (!x.disfile) { /* * Conjure up a mount structure */ sb = &mp->m_sb; libxfs_sb_from_disk(sb, (xfs_dsb_t *)buf); mp->m_blkbb_log = sb->sb_blocklog - BBSHIFT; x.logBBsize = XFS_FSB_TO_BB(mp, sb->sb_logblocks); x.logBBstart = XFS_FSB_TO_DADDR(mp, sb->sb_logstart); x.lbsize = BBSIZE; if (xfs_sb_version_hassector(sb)) x.lbsize <<= (sb->sb_logsectlog - BBSHIFT); if (!x.logname && sb->sb_logstart == 0) { fprintf(stderr, _(" external log device not specified\n\n")); usage(); /*NOTREACHED*/ } } else { struct stat s; stat(x.dname, &s); x.logBBsize = s.st_size >> 9; x.logBBstart = 0; x.lbsize = BBSIZE; } if (x.logname && *x.logname) { /* External log */ if ((fd = open(x.logname, O_RDONLY)) == -1) { fprintf(stderr, _("Can't open file %s: %s\n"), x.logname, strerror(errno)); exit(1); } close(fd); } else { /* Internal log */ x.logdev = x.ddev; } return 0; } int main(int argc, char **argv) { int print_start = -1; int c; int logfd; char *copy_file = NULL; struct xlog log = {0}; xfs_mount_t mount; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); memset(&mount, 0, sizeof(mount)); progname = basename(argv[0]); while ((c = getopt(argc, argv, "bC:cdefl:iqnors:tDVv")) != EOF) { switch (c) { case 'D': print_only_data++; print_data++; break; case 'b': print_buffer++; break; case 'c': /* default is to stop on error. * -c turns this off. */ print_exit = 0; break; case 'e': /* -e is now default */ print_exit++; break; case 'C': print_operation = OP_COPY; copy_file = optarg; break; case 'd': print_operation = OP_DUMP; break; case 'f': print_skip_uuid++; x.disfile = 1; break; case 'l': x.logname = optarg; x.lisfile = 1; break; case 'i': print_inode++; break; case 'q': print_quota++; break; case 'n': print_no_data++; break; case 'o': print_data++; break; case 's': print_start = atoi(optarg); break; case 't': print_operation = OP_PRINT_TRANS; break; case 'v': print_overwrite++; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); case '?': usage(); } } if (argc - optind != 1) usage(); x.dname = argv[optind]; if (x.dname == NULL) usage(); x.isreadonly = LIBXFS_ISINACTIVE; printf(_("xfs_logprint:\n")); if (!libxfs_init(&x)) exit(1); logstat(&mount); libxfs_buftarg_init(&mount, x.ddev, x.logdev, x.rtdev); logfd = (x.logfd < 0) ? x.dfd : x.logfd; printf(_(" data device: 0x%llx\n"), (unsigned long long)x.ddev); if (x.logname) { printf(_(" log file: \"%s\" "), x.logname); } else { printf(_(" log device: 0x%llx "), (unsigned long long)x.logdev); } printf(_("daddr: %lld length: %lld\n\n"), (long long)x.logBBstart, (long long)x.logBBsize); ASSERT(x.logBBsize <= INT_MAX); log.l_dev = mount.m_logdev_targp; log.l_logBBstart = x.logBBstart; log.l_logBBsize = x.logBBsize; log.l_sectBBsize = BTOBB(x.lbsize); log.l_mp = &mount; switch (print_operation) { case OP_PRINT: xfs_log_print(&log, logfd, print_start); break; case OP_PRINT_TRANS: xfs_log_print_trans(&log, print_start); break; case OP_DUMP: xfs_log_dump(&log, logfd, print_start); break; case OP_COPY: xfs_log_copy(&log, logfd, copy_file); break; } exit(0); } xfsprogs-5.3.0/logprint/logprint.h0000644000175000017500000000375313435336037017130 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef LOGPRINT_H #define LOGPRINT_H /* command line flags */ extern int print_data; extern int print_only_data; extern int print_inode; extern int print_quota; extern int print_buffer; extern int print_transactions; extern int print_overwrite; extern int print_no_data; extern int print_no_print; /* exports */ extern void xlog_print_lseek(struct xlog *, int, xfs_daddr_t, int); extern void xfs_log_copy(struct xlog *, int, char *); extern void xfs_log_dump(struct xlog *, int, int); extern void xfs_log_print(struct xlog *, int, int); extern void xfs_log_print_trans(struct xlog *, int); extern void print_xlog_record_line(void); extern void print_xlog_op_line(void); extern void print_stars(void); extern struct xfs_inode_log_format * xfs_inode_item_format_convert(char *, uint, struct xfs_inode_log_format *); extern int xlog_print_trans_efi(char **ptr, uint src_len, int continued); extern void xlog_recover_print_efi(xlog_recover_item_t *item); extern int xlog_print_trans_efd(char **ptr, uint len); extern void xlog_recover_print_efd(xlog_recover_item_t *item); extern int xlog_print_trans_rui(char **ptr, uint src_len, int continued); extern void xlog_recover_print_rui(struct xlog_recover_item *item); extern int xlog_print_trans_rud(char **ptr, uint len); extern void xlog_recover_print_rud(struct xlog_recover_item *item); extern int xlog_print_trans_cui(char **ptr, uint src_len, int continued); extern void xlog_recover_print_cui(struct xlog_recover_item *item); extern int xlog_print_trans_cud(char **ptr, uint len); extern void xlog_recover_print_cud(struct xlog_recover_item *item); extern int xlog_print_trans_bui(char **ptr, uint src_len, int continued); extern void xlog_recover_print_bui(struct xlog_recover_item *item); extern int xlog_print_trans_bud(char **ptr, uint len); extern void xlog_recover_print_bud(struct xlog_recover_item *item); #endif /* LOGPRINT_H */ xfsprogs-5.3.0/m4/Makefile0000644000175000017500000000125713435336037015240 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs CONFIGURE = \ libtool.m4 \ ltoptions.m4 \ ltsugar.m4 \ ltversion.m4 \ lt~obsolete.m4 LSRCFILES = \ manual_format.m4 \ package_blkid.m4 \ package_devmapper.m4 \ package_globals.m4 \ package_attr.m4 \ package_libcdev.m4 \ package_pthread.m4 \ package_sanitizer.m4 \ package_services.m4 \ package_types.m4 \ package_icu.m4 \ package_utilies.m4 \ package_uuiddev.m4 \ multilib.m4 \ $(CONFIGURE) default: include $(BUILDRULES) install install-dev install-lib: default realclean: distclean rm -f $(CONFIGURE) xfsprogs-5.3.0/m4/manual_format.m40000644000175000017500000000075013034246041016652 0ustar nathansnathans# # Find format of installed man pages. # Always gzipped on Debian, but not Redhat pre-7.0. # We don't deal with bzip2'd man pages, which Mandrake uses, # someone will send us a patch sometime hopefully. :-) # AC_DEFUN([AC_MANUAL_FORMAT], [ have_zipped_manpages=false for d in ${prefix}/share/man ${prefix}/man ; do if test -f $d/man1/man.1.gz then have_zipped_manpages=true break fi done AC_SUBST(have_zipped_manpages) ]) xfsprogs-5.3.0/m4/multilib.m40000644000175000017500000000345413034246041015652 0ustar nathansnathans# The AC_MULTILIB macro was extracted and modified from # gettext-0.15's AC_LIB_PREPARE_MULTILIB macro in the lib-prefix.m4 file # so that the correct paths can be used for 64-bit libraries. # dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_MULTILIB creates a variable libdirsuffix, containing dnl the suffix of the libdir, either "" or "64". dnl Only do this if the given enable parameter is "yes". AC_DEFUN([AC_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. The current dnl practice is that on a system supporting 32-bit and 64-bit instruction dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit dnl libraries go under $prefix/lib. We determine the compiler's default dnl mode by looking at the compiler's library search path. If at least dnl of its elements ends in /lib64 or points to a directory whose absolute dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the dnl default, namely "lib". enable_lib64="$1" libdirsuffix="" searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test "$enable_lib64" = "yes" -a -n "$searchpath"; then save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) libdirsuffix=64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) libdirsuffix=64 ;; esac ;; esac fi done IFS="$save_IFS" fi AC_SUBST(libdirsuffix) ]) xfsprogs-5.3.0/m4/package_aiodev.m40000644000175000017500000000000013034246041016733 0ustar nathansnathansxfsprogs-5.3.0/m4/package_attr.m40000644000175000017500000000103013242461543016451 0ustar nathansnathansAC_DEFUN([AC_PACKAGE_WANT_ATTRIBUTES_H], [ AC_CHECK_HEADERS(attr/attributes.h) ]) # # Check if we have a ATTR_ROOT flag and libattr structures # AC_DEFUN([AC_HAVE_LIBATTR], [ AC_MSG_CHECKING([for struct attrlist_cursor]) AC_TRY_COMPILE([ #include #include ], [ struct attrlist_cursor *cur; struct attrlist *list; struct attrlist_ent *ent; int flags = ATTR_ROOT; ], have_libattr=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_libattr) ]) xfsprogs-5.3.0/m4/package_blkid.m40000644000175000017500000000064613034246041016571 0ustar nathansnathans# # See if blkid has the topology bits # AC_DEFUN([AC_HAVE_BLKID_TOPO], [ AC_SEARCH_LIBS([blkid_probe_all], [blkid]) AC_CHECK_FUNCS(blkid_probe_get_topology) if test $ac_cv_func_blkid_probe_get_topology = yes; then libblkid="-lblkid" else echo echo 'FATAL ERROR: could not find a valid BLKID header.' echo 'Install the Block device ID development package.' exit 1 fi AC_SUBST(libblkid) ]) xfsprogs-5.3.0/m4/package_devmapper.m40000644000175000017500000000043213242461543017467 0ustar nathansnathans# # See if libdevmapper is available on the system. # AC_DEFUN([AC_HAVE_DEVMAPPER], [ AC_SEARCH_LIBS([dm_task_create], [devmapper], libdevmapper="-ldevmapper" have_devmapper=yes, have_devmapper=no,) AC_SUBST(have_devmapper) AC_SUBST(libdevmapper) ]) xfsprogs-5.3.0/m4/package_globals.m40000644000175000017500000000223713435336037017137 0ustar nathansnathans# # Generic macro, sets up all of the global packaging variables. # The following environment variables may be set to override defaults: # DEBUG OPTIMIZER MALLOCLIB PLATFORM DISTRIBUTION INSTALL_USER INSTALL_GROUP # BUILD_VERSION # AC_DEFUN([AC_PACKAGE_GLOBALS], [ pkg_name="$1" AC_SUBST(pkg_name) AC_PROG_CC . ./VERSION pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} AC_SUBST(pkg_version) pkg_release=$PKG_BUILD test -z "$BUILD_VERSION" || pkg_release="$BUILD_VERSION" AC_SUBST(pkg_release) DEBUG=${DEBUG:-'-DDEBUG'} dnl -DNDEBUG debug_build="$DEBUG" AC_SUBST(debug_build) OPTIMIZER=${OPTIMIZER:-'-g -O2'} opt_build="$OPTIMIZER" AC_SUBST(opt_build) MALLOCLIB=${MALLOCLIB:-''} dnl /usr/lib/libefence.a malloc_lib="$MALLOCLIB" AC_SUBST(malloc_lib) pkg_user=`id -u -n` test -z "$INSTALL_USER" || pkg_user="$INSTALL_USER" AC_SUBST(pkg_user) pkg_group=`id -g -n` test -z "$INSTALL_GROUP" || pkg_group="$INSTALL_GROUP" AC_SUBST(pkg_group) pkg_distribution=`uname -s` test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" AC_SUBST(pkg_distribution) ]) xfsprogs-5.3.0/m4/package_icu.m40000644000175000017500000000030113435336037016262 0ustar nathansnathansAC_DEFUN([AC_HAVE_LIBICU], [ PKG_CHECK_MODULES([libicu], [icu-i18n], [have_libicu=yes], [have_libicu=no]) AC_SUBST(have_libicu) AC_SUBST(libicu_CFLAGS) AC_SUBST(libicu_LIBS) ]) xfsprogs-5.3.0/m4/package_libcdev.m40000644000175000017500000002210313466663244017125 0ustar nathansnathans# # Check if we have a working fadvise system call # AC_DEFUN([AC_HAVE_FADVISE], [ AC_MSG_CHECKING([for fadvise ]) AC_TRY_COMPILE([ #define _GNU_SOURCE #include ], [ posix_fadvise(0, 1, 0, POSIX_FADV_NORMAL); ], have_fadvise=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_fadvise) ]) # # Check if we have a working madvise system call # AC_DEFUN([AC_HAVE_MADVISE], [ AC_MSG_CHECKING([for madvise ]) AC_TRY_COMPILE([ #define _GNU_SOURCE #include ], [ posix_madvise(0, 0, MADV_NORMAL); ], have_madvise=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_madvise) ]) # # Check if we have a working mincore system call # AC_DEFUN([AC_HAVE_MINCORE], [ AC_MSG_CHECKING([for mincore ]) AC_TRY_COMPILE([ #define _GNU_SOURCE #include ], [ mincore(0, 0, 0); ], have_mincore=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_mincore) ]) # # Check if we have a working sendfile system call # AC_DEFUN([AC_HAVE_SENDFILE], [ AC_MSG_CHECKING([for sendfile ]) AC_TRY_COMPILE([ #define _GNU_SOURCE #include ], [ sendfile(0, 0, 0, 0); ], have_sendfile=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_sendfile) ]) # # Check if we have a getmntent libc call (Linux) # AC_DEFUN([AC_HAVE_GETMNTENT], [ AC_MSG_CHECKING([for getmntent ]) AC_TRY_COMPILE([ #include #include ], [ getmntent(0); ], have_getmntent=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_getmntent) ]) # # Check if we have a fallocate libc call (Linux) # AC_DEFUN([AC_HAVE_FALLOCATE], [ AC_MSG_CHECKING([for fallocate]) AC_TRY_LINK([ #define _GNU_SOURCE #include #include ], [ fallocate(0, 0, 0, 0); ], have_fallocate=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_fallocate) ]) # # Check if we have the fiemap ioctl (Linux) # AC_DEFUN([AC_HAVE_FIEMAP], [ AC_MSG_CHECKING([for fiemap]) AC_TRY_LINK([ #define _GNU_SOURCE #include #include ], [ struct fiemap *fiemap; ioctl(0, FS_IOC_FIEMAP, (unsigned long)fiemap); ], have_fiemap=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_fiemap) ]) # # Check if we have a preadv libc call (Linux) # AC_DEFUN([AC_HAVE_PREADV], [ AC_MSG_CHECKING([for preadv]) AC_TRY_LINK([ #define _BSD_SOURCE #define _DEFAULT_SOURCE #include ], [ preadv(0, 0, 0, 0); ], have_preadv=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_preadv) ]) # # Check if we have a pwritev2 libc call (Linux) # AC_DEFUN([AC_HAVE_PWRITEV2], [ AC_MSG_CHECKING([for pwritev2]) AC_TRY_LINK([ #define _BSD_SOURCE #include ], [ pwritev2(0, 0, 0, 0, 0); ], have_pwritev2=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_pwritev2) ]) # # Check if we have a copy_file_range system call (Linux) # AC_DEFUN([AC_HAVE_COPY_FILE_RANGE], [ AC_MSG_CHECKING([for copy_file_range]) AC_TRY_LINK([ #define _GNU_SOURCE #include #include ], [ syscall(__NR_copy_file_range, 0, 0, 0, 0, 0, 0); ], have_copy_file_range=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_copy_file_range) ]) # # Check if we have a sync_file_range libc call (Linux) # AC_DEFUN([AC_HAVE_SYNC_FILE_RANGE], [ AC_MSG_CHECKING([for sync_file_range]) AC_TRY_LINK([ #define _GNU_SOURCE #include ], [ sync_file_range(0, 0, 0, 0); ], have_sync_file_range=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_sync_file_range) ]) # # Check if we have a syncfs libc call (Linux) # AC_DEFUN([AC_HAVE_SYNCFS], [ AC_MSG_CHECKING([for syncfs]) AC_TRY_LINK([ #define _GNU_SOURCE #include ], [ syncfs(0); ], have_syncfs=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_syncfs) ]) # # Check if we have a readdir libc call # AC_DEFUN([AC_HAVE_READDIR], [ AC_MSG_CHECKING([for readdir]) AC_TRY_LINK([ #include ], [ readdir(0); ], have_readdir=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_readdir) ]) # # Check if we have a flc call (Mac OS X) # AC_DEFUN([AC_HAVE_FLS], [ AC_CHECK_DECL([fls], have_fls=yes, [], [#include ] ) AC_SUBST(have_fls) ]) # # Check if we have a fsetxattr call # AC_DEFUN([AC_HAVE_FSETXATTR], [ AC_CHECK_DECL([fsetxattr], have_fsetxattr=yes, [], [#include #include ] ) AC_SUBST(have_fsetxattr) ]) # # Check if there is mntent.h # AC_DEFUN([AC_HAVE_MNTENT], [ AC_CHECK_HEADERS(mntent.h, have_mntent=yes) AC_SUBST(have_mntent) ]) # # Check if we have a mremap call (not on Mac OS X) # AC_DEFUN([AC_HAVE_MREMAP], [ AC_CHECK_DECL([mremap], have_mremap=yes, [], [#define _GNU_SOURCE #include ] ) AC_SUBST(have_mremap) ]) # # Check if we need to override the system struct fsxattr with # the internal definition. This /only/ happens if the system # actually defines struct fsxattr /and/ the system definition # is missing certain fields. # AC_DEFUN([AC_NEED_INTERNAL_FSXATTR], [ AC_CHECK_TYPE(struct fsxattr, [ AC_CHECK_MEMBER(struct fsxattr.fsx_cowextsize, , need_internal_fsxattr=yes, [#include ] ) ],, [#include ] ) AC_SUBST(need_internal_fsxattr) ]) # # Check if we have a FS_IOC_GETFSMAP ioctl (Linux) # AC_DEFUN([AC_HAVE_GETFSMAP], [ AC_MSG_CHECKING([for GETFSMAP]) AC_TRY_LINK([ #define _GNU_SOURCE #include #include #include #include ], [ unsigned long x = FS_IOC_GETFSMAP; struct fsmap_head fh; ], have_getfsmap=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_getfsmap) ]) AC_DEFUN([AC_HAVE_STATFS_FLAGS], [ AC_CHECK_TYPE(struct statfs, [ AC_CHECK_MEMBER(struct statfs.f_flags, have_statfs_flags=yes,, [#include ] ) ],, [#include ] ) AC_SUBST(have_statfs_flags) ]) # # Check if we have MAP_SYNC defines (Linux) # AC_DEFUN([AC_HAVE_MAP_SYNC], [ AC_MSG_CHECKING([for MAP_SYNC]) AC_TRY_COMPILE([ #include #include ], [ int flags = MAP_SYNC | MAP_SHARED_VALIDATE; ], have_map_sync=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_map_sync) ]) # # Check if we have a mallinfo libc call # AC_DEFUN([AC_HAVE_MALLINFO], [ AC_MSG_CHECKING([for mallinfo ]) AC_TRY_COMPILE([ #include ], [ struct mallinfo test; test.arena = 0; test.hblkhd = 0; test.uordblks = 0; test.fordblks = 0; test = mallinfo(); ], have_mallinfo=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_mallinfo) ]) # # Check if we have a openat call # AC_DEFUN([AC_HAVE_OPENAT], [ AC_CHECK_DECL([openat], have_openat=yes, [], [#include #include #include ] ) AC_SUBST(have_openat) ]) # # Check if we have a fstatat call # AC_DEFUN([AC_HAVE_FSTATAT], [ AC_CHECK_DECL([fstatat], have_fstatat=yes, [], [#define _GNU_SOURCE #include #include #include ]) AC_SUBST(have_fstatat) ]) # # Check if we have the SG_IO ioctl # AC_DEFUN([AC_HAVE_SG_IO], [ AC_MSG_CHECKING([for struct sg_io_hdr ]) AC_TRY_COMPILE([#include ], [ struct sg_io_hdr hdr; ioctl(0, SG_IO, &hdr); ], have_sg_io=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_sg_io) ]) # # Check if we have the HDIO_GETGEO ioctl # AC_DEFUN([AC_HAVE_HDIO_GETGEO], [ AC_MSG_CHECKING([for struct hd_geometry ]) AC_TRY_COMPILE([#include ], [ struct hd_geometry hdr; ioctl(0, HDIO_GETGEO, &hdr); ], have_hdio_getgeo=yes AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_SUBST(have_hdio_getgeo) ]) AC_DEFUN([AC_PACKAGE_CHECK_LTO], [ AC_MSG_CHECKING([if C compiler supports LTO]) OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" LTO_FLAGS="-flto -ffat-lto-objects" CFLAGS="$CFLAGS $LTO_FLAGS" LDFLAGS="$LDFLAGS $LTO_FLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([])], [AC_MSG_RESULT([yes])] [lto_cflags=$LTO_FLAGS] [lto_ldflags=$LTO_FLAGS] [AC_PATH_PROG(gcc_ar, gcc-ar,,)] [AC_PATH_PROG(gcc_ranlib, gcc-ranlib,,)], [AC_MSG_RESULT([no])]) if test -x "$gcc_ar" && test -x "$gcc_ranlib"; then have_lto=yes fi CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" AC_SUBST(gcc_ar) AC_SUBST(gcc_ranlib) AC_SUBST(have_lto) AC_SUBST(lto_cflags) AC_SUBST(lto_ldflags) ]) xfsprogs-5.3.0/m4/package_pthread.m40000644000175000017500000000072513034246041017131 0ustar nathansnathansAC_DEFUN([AC_PACKAGE_NEED_PTHREAD_H], [ AC_CHECK_HEADERS(pthread.h) if test $ac_cv_header_pthread_h = no; then AC_CHECK_HEADERS(pthread.h,, [ echo echo 'FATAL ERROR: could not find a valid pthread header.' exit 1]) fi ]) AC_DEFUN([AC_PACKAGE_NEED_PTHREADMUTEXINIT], [ AC_CHECK_LIB(pthread, pthread_mutex_init,, [ echo echo 'FATAL ERROR: could not find a valid pthread library.' exit 1 ]) libpthread=-lpthread AC_SUBST(libpthread) ]) xfsprogs-5.3.0/m4/package_rt.m40000644000175000017500000000024013034246041016117 0ustar nathansnathans# Check if the platform has librt # AC_DEFUN([AC_RT], [ if test "$enable_librt" = "yes"; then librt="-lrt" else librt="" fi AC_SUBST(librt) ]) xfsprogs-5.3.0/m4/package_sanitizer.m40000644000175000017500000000347013242461543017521 0ustar nathansnathansAC_DEFUN([AC_PACKAGE_CHECK_UBSAN], [ AC_MSG_CHECKING([if C compiler supports UBSAN]) OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" UBSAN_FLAGS="-fsanitize=undefined" CFLAGS="$CFLAGS $UBSAN_FLAGS" LDFLAGS="$LDFLAGS $UBSAN_FLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([])], [AC_MSG_RESULT([yes])] [ubsan_cflags=$UBSAN_FLAGS] [ubsan_ldflags=$UBSAN_FLAGS] [have_ubsan=yes], [AC_MSG_RESULT([no])]) CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" AC_SUBST(have_ubsan) AC_SUBST(ubsan_cflags) AC_SUBST(ubsan_ldflags) ]) AC_DEFUN([AC_PACKAGE_CHECK_ADDRSAN], [ AC_MSG_CHECKING([if C compiler supports ADDRSAN]) OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" ADDRSAN_FLAGS="-fsanitize=address" CFLAGS="$CFLAGS $ADDRSAN_FLAGS" LDFLAGS="$LDFLAGS $ADDRSAN_FLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([])], [AC_MSG_RESULT([yes])] [addrsan_cflags=$ADDRSAN_FLAGS] [addrsan_ldflags=$ADDRSAN_FLAGS] [have_addrsan=yes], [AC_MSG_RESULT([no])]) CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" AC_SUBST(have_addrsan) AC_SUBST(addrsan_cflags) AC_SUBST(addrsan_ldflags) ]) AC_DEFUN([AC_PACKAGE_CHECK_THREADSAN], [ AC_MSG_CHECKING([if C compiler supports THREADSAN]) OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" THREADSAN_FLAGS="-fsanitize=thread" CFLAGS="$CFLAGS $THREADSAN_FLAGS" LDFLAGS="$LDFLAGS $ADRSAN_FLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([])], [AC_MSG_RESULT([yes])] [threadsan_cflags=$THREADSAN_FLAGS] [threadsan_ldflags=$THREADSAN_FLAGS] [have_threadsan=yes], [AC_MSG_RESULT([no])]) CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" AC_SUBST(have_threadsan) AC_SUBST(threadsan_cflags) AC_SUBST(threadsan_ldflags) ]) xfsprogs-5.3.0/m4/package_services.m40000644000175000017500000000337013242461543017333 0ustar nathansnathans# # Figure out where to put systemd service units # AC_DEFUN([AC_CONFIG_SYSTEMD_SYSTEM_UNIT_DIR], [ AC_REQUIRE([PKG_PROG_PKG_CONFIG]) AC_ARG_WITH([systemd_unit_dir], [AS_HELP_STRING([--with-systemd-unit-dir@<:@=DIR@:>@], [Install systemd system units into DIR.])], [], [with_systemd_unit_dir=yes]) AS_IF([test "x${with_systemd_unit_dir}" != "xno"], [ AS_IF([test "x${with_systemd_unit_dir}" = "xyes"], [ PKG_CHECK_MODULES([systemd], [systemd], [ with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)" ], [ with_systemd_unit_dir="" ]) m4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$]) ]) AC_MSG_CHECKING([for systemd system unit dir]) systemd_system_unit_dir="${with_systemd_unit_dir}" AS_IF([test -n "${systemd_system_unit_dir}"], [ AC_MSG_RESULT(${systemd_system_unit_dir}) have_systemd="yes" ], [ AC_MSG_RESULT(no) have_systemd="no" ]) ], [ have_systemd="disabled" ]) AC_SUBST(have_systemd) AC_SUBST(systemd_system_unit_dir) ]) # # Figure out where to install crontabs # AC_DEFUN([AC_CONFIG_CROND_DIR], [ AC_ARG_WITH([crond_dir], [AS_HELP_STRING([--with-crond-dir@<:@=DIR@:>@], [Install system crontabs into DIR.])], [], [with_crond_dir=yes]) AS_IF([test "x${with_crond_dir}" != "xno"], [ AS_IF([test "x${with_crond_dir}" = "xyes"], [ AS_IF([test -d "/etc/cron.d"], [with_crond_dir="/etc/cron.d"]) ]) AC_MSG_CHECKING([for system crontab dir]) crond_dir="${with_crond_dir}" AS_IF([test -n "${crond_dir}"], [ AC_MSG_RESULT(${crond_dir}) have_crond="yes" ], [ AC_MSG_RESULT(no) have_crond="no" ]) ], [ have_crond="disabled" ]) AC_SUBST(have_crond) AC_SUBST(crond_dir) ]) xfsprogs-5.3.0/m4/package_types.m40000644000175000017500000000045713242461543016657 0ustar nathansnathans# # Check if we have umode_t # AH_TEMPLATE([HAVE_UMODE_T], [Whether you have umode_t]) AC_DEFUN([AC_TYPE_UMODE_T], [ AC_MSG_CHECKING([for umode_t]) AC_TRY_COMPILE([ #include ], [ umode_t umode; ], AC_DEFINE(HAVE_UMODE_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) ]) xfsprogs-5.3.0/m4/package_utilies.m40000644000175000017500000000733713034246041017166 0ustar nathansnathans# Path to search an utility PATH=/bin:/usr/bin:/usr/local/bin:/usr/freeware/bin:/opt/local/bin # # Check for specified utility (env var) - if unset, fail. # AC_DEFUN([AC_PACKAGE_NEED_UTILITY], [ if test -z "$2"; then echo echo FATAL ERROR: $3 does not seem to be installed. echo $1 cannot be built without a working $4 installation. exit 1 fi ]) # #check compiler can generate dependencies # AC_DEFUN([AC_PACKAGE_GCC_DEPS], [AC_CACHE_CHECK(whether gcc -MM is supported, ac_cv_gcc_nodeps, [cat > conftest.c < int main() { exit(0); } EOF ac_cv_gcc_nodeps=no if ${CC} -MM conftest.c >/dev/null 2>&1; then ac_cv_gcc_nodeps=yes fi rm -f conftest.c a.out ]) ]) # # Generic macro, sets up all of the global build variables. # The following environment variables may be set to override defaults: # CC MAKE LIBTOOL TAR ZIP MAKEDEPEND AWK SED ECHO SORT # MSGFMT MSGMERGE XGETTEXT RPM # AC_DEFUN([AC_PACKAGE_UTILITIES], [ AC_PROG_CC cc="$CC" AC_SUBST(cc) AC_PACKAGE_NEED_UTILITY($1, "$cc", cc, [C compiler]) if test -z "$MAKE"; then AC_PATH_PROG(MAKE, gmake,, $PATH) fi if test -z "$MAKE"; then AC_PATH_PROG(MAKE, make,, $PATH) fi make=$MAKE AC_SUBST(make) AC_PACKAGE_NEED_UTILITY($1, "$make", make, [GNU make]) if test -z "$TAR"; then AC_PATH_PROG(TAR, tar,, $PATH) fi tar=$TAR AC_SUBST(tar) if test -z "$ZIP"; then AC_PATH_PROG(ZIP, gzip,, $PATH) fi zip=$ZIP AC_SUBST(zip) AC_PACKAGE_GCC_DEPS() makedepend="$cc -MM" if test $ac_cv_gcc_nodeps = no; then makedepend=/bin/true fi AC_SUBST(makedepend) if test -z "$AWK"; then AC_PATH_PROG(AWK, awk,, /bin:/usr/bin) fi awk=$AWK AC_SUBST(awk) if test -z "$SED"; then AC_PATH_PROG(SED, sed,, /bin:/usr/bin) fi sed=$SED AC_SUBST(sed) if test -z "$ECHO"; then AC_PATH_PROG(ECHO, echo,, /bin:/usr/bin) fi echo=$ECHO AC_SUBST(echo) if test -z "$SORT"; then AC_PATH_PROG(SORT, sort,, /bin:/usr/bin) fi sort=$SORT AC_SUBST(sort) dnl check if symbolic links are supported AC_PROG_LN_S if test "$enable_gettext" = yes; then if test -z "$MSGFMT"; then AC_PATH_PROG(MSGFMT, msgfmt,, $PATH) fi msgfmt=$MSGFMT AC_SUBST(msgfmt) AC_PACKAGE_NEED_UTILITY($1, "$msgfmt", msgfmt, gettext) if test -z "$MSGMERGE"; then AC_PATH_PROG(MSGMERGE, msgmerge,, $PATH) fi msgmerge=$MSGMERGE AC_SUBST(msgmerge) AC_PACKAGE_NEED_UTILITY($1, "$msgmerge", msgmerge, gettext) if test -z "$XGETTEXT"; then AC_PATH_PROG(XGETTEXT, xgettext,, $PATH) fi xgettext=$XGETTEXT AC_SUBST(xgettext) AC_PACKAGE_NEED_UTILITY($1, "$xgettext", xgettext, gettext) fi if test -z "$RPM"; then AC_PATH_PROG(RPM, rpm,, $PATH) fi rpm=$RPM AC_SUBST(rpm) dnl .. and what version is rpm rpm_version=0 test -n "$RPM" && test -x "$RPM" && rpm_version=`$RPM --version \ | awk '{print $NF}' | awk -F. '{V=1; print $V}'` AC_SUBST(rpm_version) dnl At some point in rpm 4.0, rpm can no longer build rpms, and dnl rpmbuild is needed (rpmbuild may go way back; not sure) dnl So, if rpm version >= 4.0, look for rpmbuild. Otherwise build w/ rpm if test $rpm_version -ge 4; then AC_PATH_PROG(RPMBUILD, rpmbuild) rpmbuild=$RPMBUILD else rpmbuild=$RPM fi AC_SUBST(rpmbuild) ]) xfsprogs-5.3.0/m4/package_uuiddev.m40000644000175000017500000000137013034246041017144 0ustar nathansnathansAC_DEFUN([AC_PACKAGE_NEED_UUID_H], [ AC_CHECK_HEADERS([uuid.h sys/uuid.h uuid/uuid.h]) if test $ac_cv_header_uuid_h = no -a \ $ac_cv_header_sys_uuid_h = no -a \ $ac_cv_header_uuid_uuid_h = no; then echo echo 'FATAL ERROR: could not find a valid UUID header.' echo 'Install the Universally Unique Identifiers development package.' exit 1 fi ]) AC_DEFUN([AC_PACKAGE_NEED_UUIDCOMPARE], [ AC_CHECK_FUNCS(uuid_compare) if test $ac_cv_func_uuid_compare = yes; then libuuid="" else AC_CHECK_LIB(uuid, uuid_compare,, [ echo echo 'FATAL ERROR: could not find a valid UUID library.' echo 'Install the Universally Unique Identifiers library package.' exit 1]) libuuid="-luuid" fi AC_SUBST(libuuid) ]) xfsprogs-5.3.0/man/Makefile0000644000175000017500000000066713435336037015477 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs SUBDIRS = man2 man3 man5 man8 default : $(SUBDIRS) install : $(addsuffix -install,$(SUBDIRS)) install-dev : $(addsuffix -install-dev,$(SUBDIRS)) %-install: $(Q)$(MAKE) $(MAKEOPTS) -C $* install %-install-dev: $(Q)$(MAKE) $(MAKEOPTS) -C $* install-dev include $(BUILDRULES) xfsprogs-5.3.0/man/man2/Makefile0000644000175000017500000000060413242461543016320 0ustar nathansnathans# # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = ../.. include $(TOPDIR)/include/builddefs MAN_SECTION = 2 MAN_PAGES = $(shell echo *.$(MAN_SECTION)) MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) default : $(MAN_PAGES) include $(BUILDRULES) install : install-dev : default $(INSTALL) -m 755 -d $(MAN_DEST) $(INSTALL_MAN) xfsprogs-5.3.0/man/man2/ioctl_xfs_ag_geometry.20000644000175000017500000000633713570057155021334 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-AG-GEOMETRY 2 2019-08-30 "XFS" .SH NAME ioctl_xfs_ag_geometry \- query XFS allocation group geometry information .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_AG_GEOMETRY, struct xfs_ag_geometry *" arg ); .SH DESCRIPTION This XFS ioctl retrieves the geometry information for a given allocation group. The geometry information is conveyed in a structure of the following form: .PP .in +4n .nf struct xfs_ag_geometry { uint32_t ag_number; uint32_t ag_length; uint32_t ag_freeblks; uint32_t ag_icount; uint32_t ag_ifree; uint32_t ag_sick; uint32_t ag_checked; uint32_t ag_flags; uint64_t ag_reserved[12]; }; .fi .in .TP .I ag_number The caller must set this field to the index of the allocation group that the caller wishes to learn about. .TP .I ag_length The length of the allocation group is returned in this field, in units of filesystem blocks. .TP .I ag_freeblks The number of free blocks in the allocation group is returned in this field, in units of filesystem blocks. .TP .I ag_icount The number of inode records allocated in this allocation group is returned in this field. .TP .I ag_ifree The number of unused inode records (of the space allocated) in this allocation group is returned in this field. .TP .I ag_flags The caller can set this field to change the operational behavior of the ioctl. Currently no flags are defined, so this field must be zero. .TP .IR ag_reserved All reserved fields will be set to zero on return. .PP The fields .IR ag_sick " and " ag_checked indicate the relative health of various allocation group metadata: .IP \[bu] 2 If a given sick flag is set in .IR ag_sick , then that piece of metadata has been observed to be damaged. The same bit will be set in .IR ag_checked . .IP \[bu] If a given sick flag is set in .I ag_checked and is not set in .IR ag_sick , then that piece of metadata has been checked and is not faulty. .IP \[bu] If a given sick flag is not set in .IR ag_checked , then no conclusion can be made. .PP The following flags apply to these fields: .RS 0.4i .TP .B XFS_AG_GEOM_SICK_SB Allocation group superblock. .TP .B XFS_AG_GEOM_SICK_AGF Free space header. .TP .B XFS_AG_GEOM_SICK_AGFL Free space reserve list. .TP .B XFS_AG_GEOM_SICK_AGI Inode header. .TP .BR XFS_AG_GEOM_SICK_BNOBT " or " XFS_AG_GEOM_SICK_CNTBT Free space btrees. .TP .BR XFS_AG_GEOM_SICK_INOBT " or " XFS_AG_GEOM_SICK_FINOBT Inode btrees. .TP .B XFS_AG_GEOM_SICK_RMAPBT Reverse mapping btree. .TP .B XFS_AG_GEOM_SICK_REFCNTBT Reference count btree. .RE .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL The specified allocation group number is not valid for this filesystem. .TP .B EIO An I/O error was encountered while performing the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_bulkstat.20000644000175000017500000001767613570057155020673 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-BULKSTAT 2 2019-05-23 "XFS" .SH NAME ioctl_xfs_bulkstat \- query information for a batch of XFS inodes .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_BULKSTAT, struct xfs_bulkstat_req *" arg ); .SH DESCRIPTION Query stat information for a group of XFS inodes. This ioctl uses .B struct xfs_bulkstat_req to set up a bulk transfer from the kernel: .PP .in +4n .nf struct xfs_bulkstat_req { struct xfs_bulk_ireq hdr; struct xfs_bulkstat bulkstat[]; }; .fi .in .PP See below for the .B xfs_bulkstat structure definition. .PP .in +4n .nf struct xfs_bulk_ireq { uint64_t ino; uint32_t flags; uint32_t icount; uint32_t ocount; uint32_t agno; uint64_t reserved[5]; }; .fi .in .PP .I hdr.ino should be set to the number of the first inode for which the caller wants information; or zero to start with the first inode in the filesystem; or a special value if .B XFS_BULK_IREQ_SPECIAL is set in the flags field. Note that this is a different semantic than the .B lastip in the old .B FSBULKSTAT ioctl. After the call, this value will be set to the number of the next inode for which information could supplied. This sets up the next call for an iteration loop. .PP If the .B XFS_BULK_IREQ_SPECIAL flag is set in the flags field, the .I ino field is interpreted according to the following special values: .RS 0.4i .TP .B XFS_BULK_IREQ_SPECIAL_ROOT Return stat information for the root directory inode. .RE .PP .PP .I hdr.flags is a bit set of operational flags: .RS 0.4i .TP .B XFS_BULK_IREQ_AGNO If this is set, the call will only return results for the allocation group (AG) set in .BR hdr.agno . If .B hdr.ino is set to zero, results will be returned starting with the first inode in the AG. This flag may not be set at the same time as the .B XFS_BULK_IREQ_SPECIAL flag. .TP .B XFS_BULK_IREQ_SPECIAL If this is set, results will be returned for only the special inode specified in the .B hdr.ino field. This flag may not be set at the same time as the .B XFS_BULK_IREQ_AGNO flag. .RE .PP .I hdr.icount is the maximum number of records to return. This should be the size of the array that comes after the header. .PP .I hdr.ocount will be set to the number of records actually returned. .PP .I hdr.agno is the number of the allocation group (AG) for which we want results. If the .B XFS_BULK_IREQ_AGNO flag is not set, this field is ignored. .PP .I hdr.reserved must be set to zero. .PP .I bulkstat is an array of .B struct xfs_bulkstat which is described below. The array must have at least .I icount elements. .PP .in +4n .nf struct xfs_bulkstat { uint64_t bs_ino; uint64_t bs_size; uint64_t bs_blocks; uint64_t bs_xflags; uint64_t bs_atime; uint64_t bs_mtime; uint64_t bs_ctime; uint64_t bs_btime; uint32_t bs_gen; uint32_t bs_uid; uint32_t bs_gid; uint32_t bs_projectid; uint32_t bs_atime_nsec; uint32_t bs_mtime_nsec; uint32_t bs_ctime_nsec; uint32_t bs_btime_nsec; uint32_t bs_blksize; uint32_t bs_rdev; uint32_t bs_cowextsize_blks; uint32_t bs_extsize_blks; uint32_t bs_nlink; uint32_t bs_extents; uint32_t bs_aextents; uint16_t bs_version; uint16_t bs_forkoff; uint16_t bs_sick; uint16_t bs_checked; uint16_t bs_mode; uint16_t bs_pad2; uint64_t bs_pad[7]; }; .fi .in .PP .I bs_ino is the inode number of this record. .PP .I bs_size is the size of the file, in bytes. .PP .I bs_blocks is the number of filesystem blocks allocated to this file, including metadata. .PP .I bs_xflags tell us what extended flags are set this inode. These flags are the same values as those defined in the .B XFS INODE FLAGS section of the .BR ioctl_xfs_fsgetxattr (2) manpage. .PP .I bs_atime is the last time this file was accessed, in seconds. .PP .I bs_mtime is the last time the contents of this file were modified, in seconds. .PP .I bs_ctime is the last time this inode record was modified, in seconds. .PP .I bs_btime is the time this inode record was created, in seconds. .PP .I bs_gen is the generation number of the inode record. .PP .I bs_uid is the user id. .PP .I bs_gid is the group id. .PP .I bs_projectid is the the project id. .PP .I bs_atime_nsec is the nanoseconds component of the last time this file was accessed. .PP .I bs_mtime_nsec is the nanoseconds component of the last time the contents of this file were modified. .PP .I bs_ctime_nsec is the nanoseconds component of the last time this inode record was modified. .PP .I bs_btime_nsec is the nanoseconds component of the time this inode record was created. .PP .I bs_blksize is the size of a data block for this file, in units of bytes. .PP .I bs_rdev is the encoded device id if this is a special file. .PP .I bs_cowextsize_blks is the Copy on Write extent size hint for this file, in units of data blocks. .PP .I bs_extsize_blks is the extent size hint for this file, in units of data blocks. .PP .I bs_nlink is the number of hard links to this inode. .PP .I bs_extents is the number of storage mappings associated with this file's data. .PP .I bs_aextents is the number of storage mappings associated with this file's extended attributes. .PP .I bs_version is the version of this data structure. This will be set to .I XFS_BULKSTAT_VERSION_V5 by the kernel. .PP .I bs_forkoff is the offset of the attribute fork in the inode record, in bytes. .PP The fields .IR bs_sick " and " bs_checked indicate the relative health of various allocation group metadata. Please see the section .B XFS INODE METADATA HEALTH REPORTING for more information. .PP .I bs_mode is the file type and mode. .PP .I bs_pad[7] is zeroed. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH XFS INODE METADATA HEALTH REPORTING .PP The online filesystem checking utility scans inode metadata and records what it finds in the kernel incore state. The following scheme is used for userspace to read the incore health status of an inode: .IP \[bu] 2 If a given sick flag is set in .IR bs_sick , then that piece of metadata has been observed to be damaged. The same bit should be set in .IR bs_checked . .IP \[bu] If a given sick flag is set in .I bs_checked but is not set in .IR bs_sick , then that piece of metadata has been checked and is not faulty. .IP \[bu] If a given sick flag is not set in .IR bs_checked , then no conclusion can be made. .PP The following flags apply to these fields: .RS 0.4i .TP .B XFS_BS_SICK_INODE The inode's record itself. .TP .B XFS_BS_SICK_BMBTD File data extent mappings. .TP .B XFS_BS_SICK_BMBTA Extended attribute extent mappings. .TP .B XFS_BS_SICK_BMBTC Copy on Write staging extent mappings. .TP .B XFS_BS_SICK_DIR Directory information. .TP .B XFS_BS_SICK_XATTR Extended attribute data. .TP .B XFS_BS_SICK_SYMLINK Symbolic link target. .TP .B XFS_BS_SICK_PARENT Parent pointers. .RE .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL One of the arguments was not valid. .TP .B EIO An I/O error was encountered while performing the query. .TP .B ENOMEM There was insufficient memory to perform the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2), .BR ioctl_xfs_fsgetxattr (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_fsbulkstat.20000644000175000017500000001420213570057155021202 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-FSBULKSTAT 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_fsbulkstat \- query information for a batch of XFS inodes .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_FSBULKSTAT, struct xfs_fsop_bulkreq *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_FSBULKSTAT_SINGLE, struct xfs_fsop_bulkreq *" arg ); .SH DESCRIPTION Query stat information for a group of XFS inodes. .PP NOTE: This ioctl has been superseded. Please see the .BR ioctl_xfs_bulkstat (2) manpage for information about its replacement. .PP These ioctls use .B struct xfs_fsop_bulkreq to set up a bulk transfer with the kernel: .PP .in +4n .nf struct xfs_fsop_bulkreq { __u64 *lastip; __s32 count; void *ubuffer; __s32 *ocount; }; .fi .in .PP .I lastip points to a value that will receive the number of the "last inode." This cannot be NULL. For .BR FSBULKSTAT , this should be set to one less than the number of the first inode for which the caller wants information, or zero to start with the first inode in the filesystem. For .BR FSBULKSTAT_SINGLE , this should be set to the number of the inode for which the caller wants information. After the call, this value will be set to the number of the last inode for which information was supplied. This field will not be updated if .I ocount is NULL. .PP .I count is the number of elements in the .B ubuffer array and therefore the number of inodes for which to return stat information. This value must be set to 1 for .BR FSBULKSTAT_SINGLE . .PP .I ocount points to a value that will receive the number of records returned. If this value is NULL, then neither .I ocount nor .I lastip will be updated. .PP .I ubuffer points to a memory buffer into which inode stat information will be copied. This buffer must be an array of .B struct xfs_bstat which is described below. The array must have at least .I count elements. .PP .in +4n .nf struct xfs_bstat { __u64 bs_ino; __u16 bs_mode; __u16 bs_nlink; __u32 bs_uid; __u32 bs_gid; __u32 bs_rdev; __s32 bs_blksize; __s64 bs_size; struct xfs_bstime bs_atime; struct xfs_bstime bs_mtime; struct xfs_bstime bs_ctime; int64_t bs_blocks; __u32 bs_xflags; __s32 bs_extsize; __s32 bs_extents; __u32 bs_gen; __u16 bs_projid_lo; __u16 bs_forkoff; __u16 bs_projid_hi; uint16_t bs_sick; uint16_t bs_checked; unsigned char bs_pad[2]; __u32 bs_cowextsize; __u32 bs_dmevmask; __u16 bs_dmstate; __u16 bs_aextents; }; .fi .in .PP The structure members are as follows: .PP .I bs_ino is the inode number for this record. .PP .I bs_mode is the file type and mode. .PP .I bs_nlink is the number of hard links to this inode. .PP .I bs_uid is the user id. .PP .I bs_gid is the group id. .PP .I bs_rdev is the encoded device id if this is a special file. .PP .I bs_blksize is the size of a data block for this file, in units of bytes. .PP .I bs_size is the size of the file, in bytes. .PP .I bs_atime is the last time this file was accessed. .PP .I bs_mtime is the last time the contents of this file were modified. .PP .I bs_ctime is the last time this inode record was modified. .PP .I bs_blocks is the number of filesystem blocks allocated to this file, including metadata. .PP .I bs_xflags contains the extended flags that are set on this inode. These flags are the same values as those defined in the .B XFS INODE FLAGS section of the .BR ioctl_xfs_fsgetxattr (2) manpage. .PD 1 .PP .I bs_extsize is the extent size hint for this file, in bytes. .PP .I bs_extents is the number of storage mappings associated with this file's data. .PP .I bs_gen is the generation number of the inode record. .PP .I bs_projid_lo is the lower 16-bits of the project id. .PP .I bs_forkoff is the offset of the attribute fork in the inode record, in bytes. .PP .I bs_projid_hi is the upper 16-bits of the project id. .PP .I bs_pad[6] is zeroed. .PP .I bs_cowextsize is the Copy on Write extent size hint for this file, in bytes. .PP .I bs_dmevmask is unused on Linux. .PP .I bs_dmstate is unused on Linux. .PP .I bs_aextents is the number of storage mappings associated with this file's extended attributes. .PP The fields .IR bs_sick " and " bs_checked indicate the relative health of various inode metadata: .IP \[bu] 2 If a given sick flag is set in .IR bs_sick , then that piece of metadata has been observed to be damaged. The same bit should be set in .IR bs_checked . .IP \[bu] If a given sick flag is set in .I bs_checked but is not set in .IR bs_sick , then that piece of metadata has been checked and is not faulty. .IP \[bu] If a given sick flag is not set in .IR bs_checked , then no conclusion can be made. .PP The following flags apply to these fields: .RS 0.4i .TP .B XFS_BS_SICK_INODE The inode's record itself. .TP .B XFS_BS_SICK_BMBTD File data extent mappings. .TP .B XFS_BS_SICK_BMBTA Extended attribute extent mappings. .TP .B XFS_BS_SICK_BMBTC Copy on Write staging extent mappings. .TP .B XFS_BS_SICK_DIR Directory information. .TP .B XFS_BS_SICK_XATTR Extended attribute data. .TP .B XFS_BS_SICK_SYMLINK Symbolic link target. .TP .B XFS_BS_SICK_PARENT Parent pointers. .RE .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL One of the arguments was not valid. .TP .B EIO An I/O error was encountered while performing the query. .TP .B ENOMEM There was insufficient memory to perform the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2), .BR ioctl_xfs_fsgetxattr (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_fscounts.20000644000175000017500000000335613570057155020674 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-FSCOUNTS 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_fscounts \- query XFS summary counter information .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_FSCOUNTS, struct xfs_fsop_counts *" arg ); .SH DESCRIPTION Query the raw filesystem summary counters. Unlike .BR statvfs (3), the values returned here are the raw values, which do not reflect any alterations or limits set by project quotas. The counter information is conveyed in a structure of the following form: .PP .in +4n .nf struct xfs_fsop_counts { __u64 freedata; __u64 freertx; __u64 freeino; __u64 allocino; }; .fi .in .PP The fields of this structure are as follows: .PP .I freedata is the number of free filesystem blocks on the data device. .PP .I freertx is the number of free extents on the realtime device. .PP .I freeino is the number of inode records that are not in use within the space that has been allocated for them. .PP .I allocino is the number of inode records for which space has been allocated. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL The specified allocation group number is not valid for this filesystem. .TP .B EIO An I/O error was encountered while performing the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_fsgetxattr.20000644000175000017500000001665313570057155021227 0ustar nathansnathans.\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-FSGETXATTR 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_fsgetxattr \- query information for an open file .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_FSGETXATTR, struct fsxattr *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_FSGETXATTRA, struct fsxattr *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_FSSETXATTR, struct fsxattr *" arg ); .SH DESCRIPTION Query or set additional attributes associated with files in various file systems. The attributes are conveyed in a structure of the form: .PP .in +4n .nf struct fsxattr { __u32 fsx_xflags; __u32 fsx_extsize; __u32 fsx_nextents; __u32 fsx_projid; __u32 fsx_cowextsize; unsigned char fsx_pad[8]; }; .fi .in .PP .I fsx_xflags are extended flags that apply to this file. Refer to the section .B XFS INODE FLAGS below for more information. .PP .I fsx_extsize is the preferred extent allocation size for data blocks mapped to this file, in units of filesystem blocks. If this value is zero, the filesystem will choose a default option, which is currently zero. If .B XFS_IOC_FSSETXATTR is called with .B XFS_XFLAG_EXTSIZE set in .I fsx_xflags and this field set to zero, the XFLAG will also be cleared. .PP .I fsx_nextents is the number of data extents in this file. If .B XFS_IOC_FSGETXATTRA was used, then this is the number of extended attribute extents in the file. .PP .I fsx_projid is the project ID of this file. .PP .I fsx_cowextsize is the preferred extent allocation size for copy on write operations targeting this file, in units of filesystem blocks. If this field is zero, the filesystem will choose a default option, which is currently 128 filesystem blocks. If .B XFS_IOC_FSSETXATTR is called with .B XFS_XFLAG_COWEXTSIZE set in .I fsx_xflags and this field set to zero, the XFLAG will also be cleared. .PP .I fsx_pad must be zeroed. .SH XFS INODE FLAGS This field can be a combination of the following: .TP .B XFS_XFLAG_REALTIME The file is a realtime file. This bit can only be changed on a file when it has no allocated extents. .TP .B XFS_XFLAG_PREALLOC The file has preallocated space. .TP .B XFS_XFLAG_IMMUTABLE The file is immutable - it cannot be modified, deleted or renamed, no link can be created to this file and no data can be written to the file. Only the superuser or a process possessing the CAP_LINUX_IMMUTABLE capability can set or clear this flag. If this flag is set before a .B XFS_IOC_FSSETXATTR call and would not be cleared by the call, then no other attributes can be changed and .B EPERM will be returned. .TP .B XFS_XFLAG_APPEND The file is append-only - it can only be opened in append mode for writing. Only the superuser or a process possessing the CAP_LINUX_IMMUTABLE capability can set or clear this flag. .TP .B XFS_XFLAG_SYNC All writes to the file are synchronous. If set on a directory and the .B /proc/sys/fs/xfs/inherit_sync tunable is set to 1, new files and subdirectories created in the directory will also have the flag set. .TP .B XFS_XFLAG_NOATIME When the file is accessed, its atime record is not modified. If set on a directory and the .B /proc/sys/fs/xfs/inherit_noatime tunable is set to 1, new files and subdirectories created in the directory will also have the flag set. .TP .B XFS_XFLAG_NODUMP The file should be skipped by backup utilities. If set on a directory and the .B /proc/sys/fs/xfs/inherit_nodump tunable is set to 1, new files and subdirectories created in the directory will also have the flag set. .TP .B XFS_XFLAG_RTINHERIT Realtime inheritance bit - new files created in the directory will be automatically created as realtime files. If set on a directory, new subdirectories created in the directory will also have the inheritance flag set. .TP .B XFS_XFLAG_PROJINHERIT Project inheritance bit - new files and directories created in this directory will inherit the project ID of this directory. If set on a directory, new subdirectories created in the directory will also have the inheritance flag set. .TP .B XFS_XFLAG_NOSYMLINKS Disallows creation of symbolic links in the directory. This flag can only be set on a directory. If set on a directory and the .B /proc/sys/fs/xfs/inherit_nosymlinks tunable is set to 1, new files and subdirectories created in the directory will also have the flag set. .TP .B XFS_XFLAG_EXTSIZE Extent size bit - if a basic extent size value is set on the file then the allocator will allocate in multiples of the set size for this file (see .B fsx_extsize below). The extent size can only be changed on a file when it has no allocated extents. .TP .B XFS_XFLAG_EXTSZINHERIT Extent size inheritance bit - new files and directories created in the directory will inherit the extent size value (see .B fsx_extsize below) of the parent directory. New subdirectories created in the directory will inherit the extent size inheritance bit. .TP .B XFS_XFLAG_NODEFRAG No defragment file bit - the file should be skipped during a defragmentation operation. If set on a directory and the .B /proc/sys/fs/xfs/inherit_nodefrag tunable is set to 1, new files and subdirectories created in the directory will also have the flag set. .TP .B XFS_XFLAG_FILESTREAM Filestream allocator bit - allows a directory to reserve an allocation group for exclusive use by files created within that directory. Files being written in other directories will not use the same allocation group and so files within different directories will not interleave extents on disk. The reservation is only active while files are being created and written into the directory. If set on a directory, new files and subdirectories created in the directory will also have the flag set. .TP .B XFS_XFLAG_DAX If the filesystem lives on directly accessible persistent memory, reads and writes to this file will go straight to the persistent memory, bypassing the page cache. If set on a directory, new files and subdirectories created in the directory will also have the flag set. This flag cannot be set on filesystems which have the reflink feature enabled. .TP .B XFS_XFLAG_COWEXTSIZE Copy on Write Extent size bit - if a CoW extent size value is set on the file, the allocator will allocate extents for staging a copy on write operation in multiples of the set size for this file (see .B fsx_cowextsize below). If set on a directory, new files and subdirectories created in the directory will have both the flag and the CoW extent size value set. .TP .B XFS_XFLAG_HASATTR The file has extended attributes associated with it. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EACCESS Caller does not have sufficient access to change the attributes. .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL One of the arguments was not valid. .TP .B EIO An I/O error was encountered while performing the query. .TP .B ENOMEM There was insufficient memory to perform the query. .TP .B EPERM Caller did not have permission to change the attributes. .SH CONFORMING TO This API is implemented by the ext4, xfs, btrfs, and f2fs filesystems on the Linux kernel. Not all fields may be understood by filesystems other than xfs. .SH SEE ALSO .BR ioctl (2), .BR ioctl_iflags (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_fsgetxattra.20000644000175000017500000000004013570057155021347 0ustar nathansnathans.so man2/ioctl_xfs_fsgetxattr.2 xfsprogs-5.3.0/man/man2/ioctl_xfs_fsinumbers.20000644000175000017500000000603613570057155021203 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-FSINUMBERS 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_fsinumbers \- extract a list of valid inode numbers from an XFS filesystem .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_FSINUMBERS, struct xfs_fsop_bulkreq *" arg ); .SH DESCRIPTION Queries inode allocation information from an XFS filesystem. It is intended to be called iteratively to obtain the entire set of inodes. These ioctls use .B struct xfs_fsop_bulkreq to set up a bulk transfer with the kernel: .PP .in +4n .nf struct xfs_fsop_bulkreq { __u64 *lastip; __s32 count; void *ubuffer; __s32 *ocount; }; .fi .in .PP .I lastip points to a value that will receive the number of the "last inode." This should be set to one less than the number of the first inode for which the caller wants information, or zero to start with the first inode in the filesystem. After the call, this value will be set to the number of the last inode for which information is supplied. This field will not be updated if .I ocount is NULL. .PP .I count is the number of elements in the .B ubuffer array and therefore the number of inode groups for which to return allocation information. .PP .I ocount points to a value that will receive the number of records returned. An output value of zero means that there are no more inode groups left to enumerate. If this value is NULL, then neither .I ocount nor .I lastip will be updated. .PP .I ubuffer points to a memory buffer where inode group information will be copied. This buffer must be an array of .B struct xfs_inogrp which is described below. The array must have at least .I count elements. .PP .in +4n .nf struct xfs_inogrp { __u64 xi_startino; __s32 xi_alloccount; __u64 xi_allocmask; } .fi .in .PP This structure describes inode usage information for a group of 64 consecutive inode numbers. The fields are as follows: .PP .I xi_startino is the first inode number of this group. .PP .I xi_alloccount is the number of bits that are set in .IR xi_allocmask . This is the number of inodes allocated in this group. .PP .I xi_allocmask is a bitmask of inodes that are allocated in this inode group. The bitmask is 64 bits long, and the least significant bit corresponds to inode .BR xi_startino . .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL One of the arguments was not valid. .TP .B EIO An I/O error was encountered while performing the query. .TP .B ENOMEM There was insufficient memory to perform the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_fsop_geometry.20000644000175000017500000001656413570057155021717 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-FSOP-GEOMETRY 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_fsop_geometry \- report XFS filesystem layout and features .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_FSOP_GEOMETRY, struct xfs_fsop_geom*" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_FSOP_GEOMETRY_V4, struct xfs_fsop_geom_v4 *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_FSOP_GEOMETRY_V1, struct xfs_fsop_geom_v1 *" arg ); .SH DESCRIPTION Report the details of an XFS filesystem layout, features, and other descriptive items. This information is conveyed in a structure of the following form: .PP .in +4n .nf struct xfs_fsop_geom { __u32 blocksize; __u32 rtextsize; __u32 agblocks; __u32 agcount; __u32 logblocks; __u32 sectsize; __u32 inodesize; __u32 imaxpct; __u64 datablocks; __u64 rtblocks; __u64 rtextents; __u64 logstart; unsigned char uuid[16]; __u32 sunit; __u32 swidth; __s32 version; __u32 flags; __u32 logsectsize; __u32 rtsectsize; __u32 dirblocksize; /* struct xfs_fsop_geom_v1 stops here. */ __u32 logsunit; /* struct xfs_fsop_geom_v4 stops here. */ __u32 sick; __u32 checked; __u64 reserved[17]; }; .fi .in .PP .I blocksize is the size of a fundamental filesystem block, in bytes. .PP .I rtextsize is the size of an extent on the realtime volume, in bytes. .PP .I agblocks is the size of an allocation group, in units of filesystem blocks. .PP .I agcount is the number of allocation groups in the filesystem. .PP .I logblocks is the size of the log, in units of filesystem blocks. .PP .I sectsize is the smallest amount of data that can be written to the data device atomically, in bytes. .PP .I inodesize is the size of an inode record, in bytes. .PP .I imaxpct is the maximum percentage of the filesystem that can be allocated to inode record blocks. .PP .I datablocks is the size of the data device, in units of filesystem blocks. .PP .I rtblocks is the size of the realtime device, in units of filesystem blocks. .PP .I rtextents is the number of extents that can be allocated on the realtime device. .PP .I logstart is the start of the log, in units of filesystem blocks. If the filesystem has an external log, this will be zero. .PP .I uuid is the universal unique identifier of the filesystem. .PP .I sunit is what the filesystem has been told is the size of a RAID stripe unit on the underlying data device, in filesystem blocks. .PP .I swidth is what the filesystem has been told is the width of a RAID stripe on the underlying data device, in units of RAID stripe units. .PP .I version is the version of this structure. This value will be XFS_FSOP_GEOM_VERSION. .PP .I flags tell us what features are enabled on the filesystem. Refer to the section .B FILESYSTEM FEATURE FLAGS below for more information about each feature. .PP .I logsectsize is the smallest amount of data that can be written to the log device atomically, in bytes. .PP .I rtsectsize is the smallest amount of data that can be written to the realtime device atomically, in bytes. .PP .I dirblocksize is the size of directory blocks, in bytes. .PP .I logsunit is what the filesystem has been told is the size of a RAID stripe unit on the underlying log device, in filesystem blocks. This field is meaningful only if the flag .B XFS_FSOP_GEOM_FLAGS_LOGV2 is set. .PP The fields .IR sick " and " checked indicate the relative health of various whole-filesystem metadata. Please see the section .B XFS METADATA HEALTH REPORTING for more details. .PP .I reserved is set to zero. .SH FILESYSTEM FEATURE FLAGS Filesystem features are reported to userspace as a combination the following flags: .TP .B XFS_FSOP_GEOM_FLAGS_ATTR Extended attributes are present. .TP .B XFS_FSOP_GEOM_FLAGS_NLINK Files on this filesystem support up to 2^32 hard links. If this flag is not set, files on this filesystem support only up to 2^16 hard links. .TP .B XFS_FSOP_GEOM_FLAGS_QUOTA Quotas are enabled. .TP .B XFS_FSOP_GEOM_FLAGS_IALIGN Inodes are aligned for better performance. .TP .B XFS_FSOP_GEOM_FLAGS_DALIGN Filesystem tries to align data block allocations to RAID stripe units for better performance. .TP .B XFS_FSOP_GEOM_FLAGS_SHARED Unused. .TP .B XFS_FSOP_GEOM_FLAGS_EXTFLG Filesystem supports unwritten extents. .TP .B XFS_FSOP_GEOM_FLAGS_DIRV2 Directories are in version 2 format and maintain free space data for better performance. Version 1 format directories are no longer supported. .TP .B XFS_FSOP_GEOM_FLAGS_LOGV2 Log uses the V2 format. .TP .B XFS_FSOP_GEOM_FLAGS_SECTOR The log device has a sector size larger than 512 bytes. .TP .B XFS_FSOP_GEOM_FLAGS_ATTR2 Filesystem contains V2 extended attributes. .TP .B XFS_FSOP_GEOM_FLAGS_PROJID32 Project IDs can be as large as 2^32. If this flag is not set, the filesystem supports only 2^16 project IDs. .TP .B XFS_FSOP_GEOM_FLAGS_DIRV2CI Case-insensitive lookups are supported on directories. .TP .B XFS_FSOP_GEOM_FLAGS_LAZYSB On-disk superblock counters are updated only at unmount time. .TP .B XFS_FSOP_GEOM_FLAGS_V5SB Metadata blocks are self describing and contain checksums. .TP .B XFS_FSOP_GEOM_FLAGS_FTYPE Directories contain inode types in directory entries. .TP .B XFS_FSOP_GEOM_FLAGS_FINOBT Filesystem maintains an index of free inodes. .TP .B XFS_FSOP_GEOM_FLAGS_SPINODES Filesystem may allocate discontiguous inode chunks when free space is fragmented. .TP .B XFS_FSOP_GEOM_FLAGS_RMAPBT Filesystem stores reverse mappings of blocks to owners. .TP .B XFS_FSOP_GEOM_FLAGS_REFLINK Filesystem supports sharing blocks between files. .RE .SH XFS METADATA HEALTH REPORTING .PP The online filesystem checking utility scans metadata and records what it finds in the kernel incore state. The following scheme is used for userspace to read the incore health status of the filesystem: .IP \[bu] 2 If a given sick flag is set in .IR sick , then that piece of metadata has been observed to be damaged. The same bit should be set in .IR checked . .IP \[bu] If a given sick flag is set in .I checked but is not set in .IR sick , then that piece of metadata has been checked and is not faulty. .IP \[bu] If a given sick flag is not set in .IR checked , then no conclusion can be made. .PP The following flags apply to these fields: .RS 0.4i .TP .B XFS_FSOP_GEOM_SICK_COUNTERS Inode and space summary counters. .TP .B XFS_FSOP_GEOM_SICK_UQUOTA User quota information. .TP .B XFS_FSOP_GEOM_SICK_GQUOTA Group quota information. .TP .B XFS_FSOP_GEOM_SICK_PQUOTA Project quota information. .TP .B XFS_FSOP_GEOM_SICK_RT_BITMAP Free space bitmap for the realtime device. .TP .B XFS_FSOP_GEOM_SICK_RT_SUMMARY Free space summary for the realtime device. .RE .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EIO An I/O error was encountered while performing the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_fssetxattr.20000644000175000017500000000004013570057155021222 0ustar nathansnathans.so man2/ioctl_xfs_fsgetxattr.2 xfsprogs-5.3.0/man/man2/ioctl_xfs_getbmap.20000644000175000017500000000003613570057155020437 0ustar nathansnathans.so man2/ioctl_xfs_getbmapx.2 xfsprogs-5.3.0/man/man2/ioctl_xfs_getbmapa.20000644000175000017500000000003613570057155020600 0ustar nathansnathans.so man2/ioctl_xfs_getbmapx.2 xfsprogs-5.3.0/man/man2/ioctl_xfs_getbmapx.20000644000175000017500000001025213570057155020630 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-GETBMAPX 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_getbmapx \- query extent information for an open file .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_GETBMAP, struct getbmap *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_GETBMAPA, struct getbmap *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_GETBMAPX, struct getbmapx *" arg ); .SH DESCRIPTION Get the block map for a segment of a file in an XFS file system. The mapping information is conveyed via an array of structures of the following form: .PP .in +4n .nf struct getbmap { __s64 bmv_offset; __s64 bmv_block; __s64 bmv_length; __s32 bmv_count; __s32 bmv_entries; }; .fi .in .PP The .B XFS_IOC_GETBMAPX ioctl uses a larger version of that structure: .PP .in +4n .nf struct getbmapx { __s64 bmv_offset; __s64 bmv_block; __s64 bmv_length; __s32 bmv_count; __s32 bmv_entries; __s32 bmv_iflags; __s32 bmv_oflags; __s32 bmv_unused1; __s32 bmv_unused2; }; .fi .in .PP All sizes and offsets in the structure are in units of 512 bytes. .PP The first structure in the array is a header and the remaining structures in the array contain block map information on return. The header controls iterative calls to the command and should be filled out as follows: .TP .I bmv_offset The file offset of the area of interest in the file. .TP .I bmv_length The length of the area of interest in the file. If this value is set to -1, the length of the interesting area is the rest of the file. .TP .I bmv_count The number of elements in the array, including this header. The minimum value is 2. .TP .I bmv_entries The number of entries actually filled in by the call. This does not need to be filled out before the call. This value may be zero if no extents were found in the requested range, or if iterated calls have reached the end of the requested range. .TP .I bmv_iflags For the .B XFS_IOC_GETBMAPX function, this is a bitmask containing a combination of the following flags: .RS 0.4i .TP .B BMV_IF_ATTRFORK Return information about the extended attribute fork. .TP .B BMV_IF_PREALLOC Return information about unwritten pre-allocated segments. .TP .B BMV_IF_DELALLOC Return information about delayed allocation reservation segments. .TP .B BMV_IF_NO_HOLES Do not return information about holes. .RE .PD 1 .PP The other .I bmv_* fields in the header are ignored. .PP On successful return from a call, the offset and length values in the header are updated so that the command can be reused to obtain more information. The remaining elements of the array will be filled out by the call as follows: .TP .I bmv_offset File offset of segment. .TP .I bmv_block Physical starting block of segment. If this is -1, then the segment is a hole. .TP .I bmv_length Length of segment. .TP .I bmv_oflags The .B XFS_IOC_GETBMAPX function will fill this field with a combination of the following flags: .RS 0.4i .TP .B BMV_OF_PREALLOC The segment is an unwritten pre-allocation. .TP .B BMV_OF_DELALLOC The segment is a delayed allocation reservation. .TP .B BMV_OF_LAST This segment is the last in the file. .TP .B BMV_OF_SHARED This segment shares blocks with other files. .RE .PD 1 .PP The other .I bmv_* fields are unused in the array of output records. .PP The .B XFS_IOC_GETBMAPA command is identical to .B XFS_IOC_GETBMAP except that information about the attribute fork of the file is returned. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL One of the arguments was not valid. .TP .B EIO An I/O error was encountered while performing the query. .TP .B ENOMEM There was insufficient memory to perform the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_getresblks.20000644000175000017500000000355613570057155021177 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-GETRESBLKS 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_getresblks \- query and set XFS free space reservation information .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_GET_RESBLKS, struct xfs_fsop_resblks *" arg ); .br .BI "int ioctl(int " fd ", XFS_IOC_SET_RESBLKS, struct xfs_fsop_resblks *" arg ); .SH DESCRIPTION Query or set the free space reservation information. These blocks are reserved by the filesystem as a final attempt to prevent metadata update failures due to insufficient space. Only the system administrator can use these ioctls, because overriding the defaults is extremely dangerous. .PP This functionality is intended only for use by XFS filesystem developers. .PP The reservation information is conveyed in a structure of the following form: .PP .in +4n .nf struct xfs_fsop_resblks { __u64 resblks; __u64 resblks_avail; }; .fi .in .PP .I resblks is the number of blocks that the filesystem will try to maintain to prevent critical out of space situations. .PP .I resblks_avail is the number of reserved blocks remaining. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL The specified allocation group number is not valid for this filesystem. .TP .B EIO An I/O error was encountered while performing the query. .TP .B EPERM Caller does not have permission to call this ioctl. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_goingdown.20000644000175000017500000000316113570057155021015 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-GOINGDOWN 2 2019-06-17 "XFS" .SH NAME ioctl_xfs_goingdown \- shut down an XFS filesystem .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_GOINGDOWN, uint32_t " flags ); .SH DESCRIPTION Shuts down a live XFS filesystem. This is a software initiated hard shutdown and should be avoided whenever possible. After this call completes, the filesystem ill be totally unusable until the filesystem has been unmounted and remounted. .PP .I flags can be one of the following: .RS 0.4i .TP .B XFS_FSOP_GOING_FLAGS_DEFAULT Flush all dirty data and metadata to disk, flush pending transactions to the log, and shut down. .TP .B XFS_FSOP_GOING_FLAGS_LOGFLUSH Flush all pending metadata transactions to the log and shut down, leaving all dirty data unwritten. .TP .B XFS_FSOP_GOING_FLAGS_NOLOGFLUSH Shut down immediately, without writing pending transactions or dirty data to disk. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EIO An I/O error was encountered while performing the query. .TP .B EPERM Caller did not have permission to shut down the filesystem. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2) xfsprogs-5.3.0/man/man2/ioctl_xfs_inumbers.20000644000175000017500000000544213570057155020652 0ustar nathansnathans.\" Copyright (c) 2019, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-INUMBERS 2 2019-05-23 "XFS" .SH NAME ioctl_xfs_inumbers \- query allocation information for groups of XFS inodes .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " fd ", XFS_IOC_INUMBERS, struct xfs_inumbers_req *" arg ); .SH DESCRIPTION Query inode allocation information for groups of XFS inodes. This ioctl uses .B struct xfs_inumbers_req to set up a bulk transfer from the kernel: .PP .in +4n .nf struct xfs_inumbers_req { struct xfs_bulk_ireq hdr; struct xfs_inumbers inumbers[]; }; .fi .in .PP See below for the .B xfs_inumbers structure definition. .PP .in +4n .nf struct xfs_bulk_ireq { uint64_t ino; uint32_t flags; uint32_t icount; uint32_t ocount; uint32_t agno; uint64_t reserved[5]; }; .fi .in .PP .I hdr describes the information to query. The layout and behavior are documented in the .BR ioctl_xfs_bulkstat (2) manpage and will not be discussed further here. .PP .I inumbers is an array of .B struct xfs_inumbers which is described below. The array must have at least .I icount elements. .PP .in +4n .nf struct xfs_inumbers { uint64_t xi_startino; uint64_t xi_allocmask; uint8_t xi_alloccount; uint8_t xi_version; uint8_t xi_padding[6]; }; .fi .in .PP This structure describes inode usage information for a group of 64 consecutive inode numbers. .PP .I xi_startino is the first inode number of this group. .PP .I xi_allocmask is a bitmask telling which inodes in this group are allocated. To clarify, bit .B N is set if inode .BR xi_startino + N is allocated. .PP .I xi_alloccount is the number of inodes in this group that are allocated. This should be equal to popcnt(xi_allocmask). .PP .I xi_version is the version of this data structure. This will be set to .I XFS_INUMBERS_VERSION_V5 by the kernel. .PP .I xi_padding[6] is zeroed. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EFAULT The kernel was not able to copy into the userspace buffer. .TP .B EFSBADCRC Metadata checksum validation failed while performing the query. .TP .B EFSCORRUPTED Metadata corruption was encountered while performing the query. .TP .B EINVAL One of the arguments was not valid. .TP .B EIO An I/O error was encountered while performing the query. .TP .B ENOMEM There was insufficient memory to perform the query. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH SEE ALSO .BR ioctl (2), .BR ioctl_xfs_bulkstat (2). xfsprogs-5.3.0/man/man2/ioctl_xfs_scrub_metadata.20000644000175000017500000002070113570057155021777 0ustar nathansnathans.\" Copyright (c) 2017, Oracle. All rights reserved. .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" SPDX-License-Identifier: GPL-2.0+ .\" %%%LICENSE_END .TH IOCTL-XFS-SCRUB-METADATA 2 2017-12-01 "XFS" .SH NAME ioctl_xfs_scrub_metadata \- check XFS filesystem metadata .SH SYNOPSIS .br .B #include .PP .BI "int ioctl(int " dest_fd ", XFS_IOC_SCRUB_METADATA, struct xfs_scrub_metadata *" arg ); .SH DESCRIPTION This XFS ioctl asks the kernel driver to examine a piece of filesystem metadata for errors or suboptimal metadata. Examination includes running metadata verifiers, checking records for obviously incorrect or impossible values, and cross-referencing each record with any other available metadata in the filesystem. This ioctl can also try to repair or optimize metadata, though this may block normal filesystem operations for a long period of time. The type and location of the metadata to scrub is conveyed in a structure of the following form: .PP .in +4n .nf struct xfs_scrub_metadata { __u32 sm_type; __u32 sm_flags; __u64 sm_ino; __u32 sm_gen; __u32 sm_agno; __u64 sm_reserved[5]; }; .fi .in .PP The field .I sm_reserved must be zero. .PP The field .I sm_type indicates the type of metadata to check: .RS 0.4i .TP .B XFS_SCRUB_TYPE_PROBE Probe the kernel to see if it is willing to try to check or repair this filesystem. .BR sm_agno ", " sm_ino ", and " sm_gen must be zero. .PD 0 .PP .nf .B XFS_SCRUB_TYPE_SB .B XFS_SCRUB_TYPE_AGF .B XFS_SCRUB_TYPE_AGFL .fi .TP .B XFS_SCRUB_TYPE_AGI Examine a given allocation group's superblock, free space header, free block list, or inode header, respectively. Headers are checked for obviously incorrect values and cross-referenced against the allocation group's metadata btrees, if possible. The allocation group number must be given in .BR sm_agno "." .BR sm_ino " and " sm_gen must be zero. .PP .nf .B XFS_SCRUB_TYPE_BNOBT .B XFS_SCRUB_TYPE_CNTBT .B XFS_SCRUB_TYPE_INOBT .B XFS_SCRUB_TYPE_FINOBT .B XFS_SCRUB_TYPE_RMAPBT .fi .TP .B XFS_SCRUB_TYPE_REFCNTBT Examine a given allocation group's two free space btrees, two inode btrees, reverse mapping btrees, or reference count btrees, respectively. Records are checked for obviously incorrect values and cross-referenced with other allocation group metadata records to ensure that there are no conflicts. The allocation group number must be given in .BR sm_agno "." .BR sm_ino " and " sm_gen must be zero. .TP .B XFS_SCRUB_TYPE_INODE Examine a given inode record for obviously incorrect values and discrepancies with the rest of filesystem metadata. Parent pointers are checked for impossible inode values and are then followed up to the parent directory to ensure that the linkage is correct. The inode to examine may be specified either through .B sm_ino and .BR sm_gen "; " if not specified, then the file described by .B dest_fd will be examined. .B sm_agno must be zero. .PP .nf .B XFS_SCRUB_TYPE_BMBTD .B XFS_SCRUB_TYPE_BMBTA .B XFS_SCRUB_TYPE_BMBTC .fi .TP .B XFS_SCRUB_TYPE_PARENT Examine a given inode's data block map, extended attribute block map, copy on write block map, or parent inode pointer. Inode records are examined for obviously incorrect values and discrepancies with the three block map types. The block maps are checked for obviously wrong values and cross-referenced with the allocation group space extent metadata for discrepancies. The inode to examine can be specified in the same manner as .BR XFS_SCRUB_TYPE_INODE "." .TP .B XFS_SCRUB_TYPE_XATTR Examine the extended attribute records and indices of a given inode for incorrect pointers and other signs of damage. The inode to examine can be specified in the same manner as .BR XFS_SCRUB_TYPE_INODE "." .TP .B XFS_SCRUB_TYPE_DIR Examine the entries in a given directory for invalid data or dangling pointers. The directory to examine can be specified in the same manner as .BR XFS_SCRUB_TYPE_INODE "." .TP .B XFS_SCRUB_TYPE_SYMLINK Examine the target of a symbolic link for obvious pathname problems. The link to examine can be specified in the same manner as .BR XFS_SCRUB_TYPE_INODE "." .PP .nf .B XFS_SCRUB_TYPE_RTBITMAP .fi .TP .B XFS_SCRUB_TYPE_RTSUM Examine the realtime block bitmap and realtime summary inodes for corruption. .PP .nf .B XFS_SCRUB_TYPE_UQUOTA .B XFS_SCRUB_TYPE_GQUOTA .fi .TP .B XFS_SCRUB_TYPE_PQUOTA Examine all user, group, or project quota records for corruption. .TP .B XFS_SCRUB_TYPE_FSCOUNTERS Examine all filesystem summary counters (free blocks, inode count, free inode count) for errors. .RE .PD 1 .PP The field .I sm_flags control the behavior of the scrub operation and provide more information about the outcome of the operation. If none of the .B XFS_SCRUB_OFLAG_* flags are set upon return, the metadata is clean. .RS 0.4i .TP .B XFS_SCRUB_IFLAG_REPAIR If the caller sets this flag, the kernel driver will examine the metadata and try to fix all problems and to optimize metadata when possible. If no errors occur during the repair operation, the check is performed a second time to determine whether the repair succeeded. If errors occur, the call returns an error status immediately. .TP .B XFS_SCRUB_OFLAG_CORRUPT The metadata was corrupt when the call returned. If .B XFS_SCRUB_IFLAG_REPAIR was specified, then an attempted repair failed to fix the problem. Unmount the filesystem and run .B xfs_repair to fix the filesystem. .TP .B XFS_SCRUB_OFLAG_PREEN The metadata is ok, but some aspect of the metadata could be optimized to increase performance. Call again with .B XFS_SCRUB_IFLAG_REPAIR to optimize the metadata. .TP .B XFS_SCRUB_OFLAG_XFAIL Filesystem errors were encountered when accessing other metadata to cross-reference the records attached to this metadata object. .TP .B XFS_SCRUB_OFLAG_XCORRUPT Discrepancies were found when cross-referencing the records attached to this metadata object against all other available metadata in the system. .TP .B XFS_SCRUB_OFLAG_INCOMPLETE The checker was unable to complete its check of all records. .TP .B XFS_SCRUB_OFLAG_WARNING The checker encountered a metadata object with potentially problematic records. However, the records were not obviously corrupt. .RE .PP For metadata checkers that operate on inodes or inode metadata, the fields .IR sm_ino " and " sm_gen are the inode number and generation number of the inode to check. If the inode number is zero, the inode represented by .I dest_fd is used instead. If the generation number of the inode does not match .IR sm_gen ", " the call will return an error code for the invalid argument. The .I sm_agno field must be zero. .PP For metadata checkers that operate on allocation group metadata, the field .I sm_agno indicates the allocation group in which to find the metadata. The .IR sm_ino " and " sm_gen fields must be zero. .PP For metadata checkers that operate on filesystem-wide metadata, no further arguments are required. .IR sm_agno ", " sm_ino ", and " sm_gen must all be zero. .SH RETURN VALUE On error, \-1 is returned, and .I errno is set to indicate the error. .PP .SH ERRORS Error codes can be one of, but are not limited to, the following: .TP .B EBUSY The filesystem object is busy; the operation will have to be tried again. .TP .B EFSCORRUPTED Severe filesystem corruption was detected and could not be repaired. Unmount the filesystem and run .B xfs_repair to fix the filesystem. .TP .B EINVAL One or more of the arguments specified is invalid. .TP .B ENOENT The specified metadata object does not exist. For example, this error code is returned for a .B XFS_SCRUB_TYPE_REFCNTBT request on a filesystem that does not support reflink. .TP .B ENOMEM There was not sufficient memory to perform the scrub or repair operation. Some operations (most notably reference count checking) require large amounts of memory. .TP .B ENOSPC There is not enough free disk space to attempt a repair. .TP .B ENOTRECOVERABLE Filesystem was mounted in .B norecovery mode and therefore has an unclean log. Neither scrub nor repair operations can be attempted with an unclean log. .TP .B ENOTTY Online scrubbing or repair were not enabled. .TP .B EOPNOTSUPP Repairs of the requested metadata object are not supported. .TP .B EROFS Filesystem is read-only and a repair was requested. .TP .B ESHUTDOWN Filesystem is shut down due to previous errors. .SH CONFORMING TO This API is specific to XFS filesystem on the Linux kernel. .SH NOTES These operations may block other filesystem operations for a long time. A calling process can stop the operation by being sent a fatal signal, but non-fatal signals are blocked. .SH SEE ALSO .BR ioctl (2) .BR xfs_scrub (8) .BR xfs_repair (8) xfsprogs-5.3.0/man/man2/ioctl_xfs_setresblks.20000644000175000017500000000004013570057155021174 0ustar nathansnathans.so man2/ioctl_xfs_getresblks.2 xfsprogs-5.3.0/man/man3/Makefile0000644000175000017500000000060413034246041016312 0ustar nathansnathans# # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = ../.. include $(TOPDIR)/include/builddefs MAN_SECTION = 3 MAN_PAGES = $(shell echo *.$(MAN_SECTION)) MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) default : $(MAN_PAGES) include $(BUILDRULES) install : install-dev : default $(INSTALL) -m 755 -d $(MAN_DEST) $(INSTALL_MAN) xfsprogs-5.3.0/man/man3/handle.30000644000175000017500000001363713034246041016203 0ustar nathansnathans.TH HANDLE 3 .SH NAME path_to_handle, path_to_fshandle, fd_to_handle, handle_to_fshandle, open_by_handle, readlink_by_handle, attr_multi_by_handle, attr_list_by_handle, fssetdm_by_handle, free_handle, getparents_by_handle, getparentpaths_by_handle \- file handle operations .SH C SYNOPSIS .B #include .br .B #include .HP .BI "int\ path_to_handle(char *" path ", void **" hanp ", size_t *" hlen ); .HP .BI "int\ path_to_fshandle(char *" path ", void **" hanp ", size_t *" hlen ); .HP .BI "int\ fd_to_handle(int " fd ", void **" hanp ", size_t *" hlen ); .HP .BI "int\ handle_to_fshandle(void *" hanp ", size_t " hlen ", void **" fshanp , .BI "size_t *" fshlen ); .HP .BI "int\ open_by_handle(void *" hanp ", size_t " hlen ", int " oflag ); .HP .BI "int\ readlink_by_handle(void *" hanp ", size_t " hlen ", void *" buf , .BI "size_t " bs ); .HP .BI "int\ attr_multi_by_handle(void *" hanp ", size_t " hlen ", void *" buf , .BI "int " rtrvcnt ", int " flags ); .HP .BI "int\ attr_list_by_handle(void *" hanp ", size_t " hlen ", char *" buf , .BI "size_t " bufsiz ", int " flags ", struct attrlist_cursor *" cursor ); .HP .BI "int\ fssetdm_by_handle(void *" hanp ", size_t " hlen ", struct fsdmidata" .BI * fssetdm ); .HP .BI "void\ free_handle(void *" hanp ", size_t " hlen ); .HP .BI "int\ getparents_by_handle(void *" hanp ", size_t " hlen ", parent_t *" buf , .BI "size_t " bufsiz ", parent_cursor_t *" cursor ", unsigned int *" count , .BI "unsigned int *" more ); .HP .BI "int\ getparentpaths_by_handle(void *" hanp ", size_t " hlen ", parent_t" .BI * buf ", size_t " bufsiz ", parent_cursor_t *" cursor ", unsigned int " .BI * count ", unsigned int *" more ); .SH DESCRIPTION These functions provide a way to perform certain filesystem operations without using a file descriptor to access filesystem objects. They are intended for use by a limited set of system utilities such as backup programs. They are supported only by the XFS filesystem. Link with the .B libhandle library to access these functions. .PP A handle, .IR hanp , uniquely identifies a filesystem object or an entire filesystem. There is one and only one handle per filesystem or filesystem object. Handles consist of some number of bytes. The size of a handle (i.e. the number of bytes comprising it) varies by the type of handle and may vary for different objects of the same type. The content of a handle is opaque to applications. Since handle sizes vary and their contents are opaque, handles are described by two quantities, a pointer .RI ( hanp ") and a size (" hlen ). The size, .IR hlen , indicates the number of bytes in the handle which are pointed to by the pointer. .PP The .BR path_to_handle () function returns the handle for the object given by the .I path argument. If the final component of the path name is a symbolic link, the handle returned is that of the link itself. .PP The .BR path_to_fshandle () function returns the handle for the filesystem in which the object given by the .I path argument resides. .PP The .BR fd_to_handle () function returns the handle for the object referenced by the .I fd argument, which must be a valid file descriptor. .PP The .BR handle_to_fshandle () function returns the handle for the filesystem in which the object referenced by the handle given by the .I hanp and .I hlen arguments resides. .PP The .BR open_by_handle () function opens a file descriptor for the object referenced by a handle. It is analogous and identical to .BR open (2) with the exception of accepting handles instead of path names. .PP The .BR readlink_by_handle () function returns the contents of a symbolic link referenced by a handle. .PP The .BR attr_multi_by_handle () function manipulates multiple user attributes on a filesystem object. It is analogous and identical to .BR attr_multif (3) except that a handle is specified instead of a file descriptor. .PP The .BR attr_list_by_handle () function returns the names of the user attributes of a filesystem object. It is analogous and identical to .BR attr_listf (3) except that a handle is specified instead of a file descriptor. .PP The .BR fssetdm_by_handle () function sets the .B di_dmevmask and .B di_dmstate fields in an XFS on-disk inode. It is analogous to the .BR "XFS_IOC_FSSETDM xfsctl" (3) command, except that a handle is specified instead of a file. .PP The .BR free_handle () function frees the storage allocated for handles returned by the following functions: .BR path_to_handle (), .BR path_to_fshandle (), .BR fd_to_handle (), and .BR handle_to_fshandle (). .PP The .BR getparents_by_handle () function returns an array of .B parent_t structures for each hardlink to the inode represented by the given handle. The parent structure encodes the parent inode number, generation number and the basename of the link. .B This function is not operational on Linux. .PP The .BR getparentpaths_by_handle () function is identical to the .BR getparents_by_handle () function except that instead of returning the basename it returns the path of the link up to the mount point. .B This function is also not operational on Linux. .SH RETURN VALUE The function .BR free_handle () has no failure indication. The other functions return the value 0 to the calling process if they succeed; otherwise, they return the value \-1 and set .I errno to indicate the error. .SH ERRORS .TP .B EACCES Search permission was denied for a component of .IR path . .TP .B EBADF .I fd is not a valid and open file descriptor. .TP .B EFAULT An argument pointed to an invalid address. .TP .B EINVAL .I path is in a filesystem that does not support these functions. .TP .B ELOOP Too many symbolic links were encountered in translating the path name. .TP .B ENAMETOOLONG A component of .I path or the entire length of .I path exceeds filesystem limits. .TP .B ENOENT A component of .I path does not exist. .TP .B EPERM The caller does not have sufficient privileges. .SH SEE ALSO .BR open (2), .BR readlink (2), .BR attr_multi (3), .BR attr_list (3), .BR xfsctl (3), .BR xfs (5). xfsprogs-5.3.0/man/man3/xfsctl.30000644000175000017500000002714513570057155016265 0ustar nathansnathans.TH XFSCTL 3 .SH NAME xfsctl \- control XFS filesystems and individual files .SH C SYNOPSIS .B #include .HP .BI "int\ xfsctl(const char *" path ", int " fd ", int " cmd ", void *" ptr ); .PP .BI "int platform_test_xfs_fd(int " fd ); .br .BI "int platform_test_xfs_path(const char *" path ); .SH DESCRIPTION Some functionality specific to the XFS filesystem is accessible to applications through platform-specific system call interfaces. These operations can be divided into two sections \- operations that operate on individual files, and operations that operate on the filesystem itself. Care should be taken when issuing .BR xfsctl () calls to ensure the target path and file descriptor (both must be supplied) do indeed represent a file from an XFS filesystem. The .BR statfs (2) and .BR fstatfs (2) system calls can be used to determine whether or not an arbitrary path or file descriptor belong to an XFS filesystem. These are not portable however, so the routines .BR platform_test_xfs_fd () and .BR platform_test_xfs_path () provide a platform-independent mechanism. .SS File Operations In order to effect an operation on an individual file, the pathname and descriptor arguments passed to .B xfsctl identifies the file being operated on. The final argument described below refers to the final argument of .BR xfsctl . All of the data structures and macros mentioned below are defined in the .RI < xfs/xfs_fs.h > header file. .PP .B XFS_IOC_ALLOCSP .br .B XFS_IOC_ALLOCSP64 .br .B XFS_IOC_FREESP .PD 0 .TP .B XFS_IOC_FREESP64 Alter storage space associated with a section of the ordinary file specified. The section is specified by a variable of type .BR xfs_flock64_t , pointed to by the final argument. The data type .B xfs_flock64_t contains the following members: .B l_whence is 0, 1, or 2 to indicate that the relative offset .B l_start will be measured from the start of the file, the current position, or the end of the file, respectively (i.e., .B l_start is the offset from the position specified in .BR l_whence ). If the offset specified is before the current end of file, any data previously written into this section is no longer accessible. If the offset specified is beyond the current end of file, the file is grown and filled with zeroes. The .B l_len field is currently ignored, and should be set to zero. .BR XFS_IOC_ALLOCSP , .BR XFS_IOC_ALLOCSP64 , .B XFS_IOC_FREESP and .B XFS_IOC_FREESP64 operations are all identical. .TP .B XFS_IOC_FSSETDM Set the di_dmevmask and di_dmstate fields in an XFS on-disk inode. The only legitimate values for these fields are those previously returned in the .B bs_dmevmask and .B bs_dmstate fields of the bulkstat structure. The data referred to by the final argument is a .BR "struct fsdmidata" . This structure's members are .B fsd_dmevmask and .BR fsd_dmstate . The di_dmevmask field is set to the value in .BR fsd_dmevmask . The di_dmstate field is set to the value in .BR fsd_dmstate . This command is restricted to root or to processes with device management capabilities. Its sole purpose is to allow backup and restore programs to restore the aforementioned critical on-disk inode fields. .TP .B XFS_IOC_DIOINFO Get information required to perform direct I/O on the specified file descriptor. Direct I/O is performed directly to and from a user's data buffer. Since the kernel's buffer cache is no longer between the two, the user's data buffer must conform to the same type of constraints as required for accessing a raw disk partition. The final argument points to a variable of type .BR "struct dioattr" , which contains the following members: .B d_mem is the memory alignment requirement of the user's data buffer. .B d_miniosz specifies block size, minimum I/O request size, and I/O alignment. The size of all I/O requests must be a multiple of this amount and the value of the seek pointer at the time of the I/O request must also be an integer multiple of this amount. .B d_maxiosz is the maximum I/O request size which can be performed on the file descriptor. If an I/O request does not meet these constraints, the .BR read (2) or .BR write (2) will fail with EINVAL. All I/O requests are kept consistent with any data brought into the cache with an access through a non-direct I/O file descriptor. .PP .nf .B XFS_IOC_FSGETXATTR .B XFS_IOC_FSGETXATTRA .fi .PD 0 .TP .B XFS_IOC_FSSETXATTR See .BR ioctl_xfs_fsgetxattr (2) for more information. .PP .nf .B XFS_IOC_GETBMAP .B XFS_IOC_GETBMAPA .fi .PD 0 .TP .B XFS_IOC_GETBMAPX See .BR ioctl_getbmap (2) for more information. .PP .B XFS_IOC_RESVSP .TP .B XFS_IOC_RESVSP64 This command is used to allocate space to a file. A range of bytes is specified using a pointer to a variable of type .B xfs_flock64_t in the final argument. The blocks are allocated, but not zeroed, and the file size does not change. If the XFS filesystem is configured to flag unwritten file extents, performance will be negatively affected when writing to preallocated space, since extra filesystem transactions are required to convert extent flags on the range of the file written. If .BR xfs_info (8) reports unwritten=1, then the filesystem was made to flag unwritten extents. .PP .B XFS_IOC_UNRESVSP .TP .B XFS_IOC_UNRESVSP64 This command is used to free space from a file. A range of bytes is specified using a pointer to a variable of type .B xfs_flock64_t in the final argument. Partial filesystem blocks are zeroed, and whole filesystem blocks are removed from the file. The file size does not change. .TP .B XFS_IOC_ZERO_RANGE This command is used to convert a range of a file to zeros without issuing data IO. A range of bytes is specified using a pointer to a variable of type .B xfs_flock64_t in the final argument. Blocks are preallocated for regions that span holes in the file, and the entire range is converted to unwritten extents. This operation is a fast method of overwriting any from the range specified with zeros without removing any blocks or having to write zeros to disk. Any subsequent read in the given range will return zeros until new data is written. This functionality requires filesystems to support unwritten extents. If .BR xfs_info (8) reports unwritten=1, then the filesystem was made to flag unwritten extents. .\" .TP .\" .B XFS_IOC_GETBIOSIZE .\" This command gets information about the preferred buffered I/O .\" size used by the system when performing buffered I/O (e.g. .\" standard Unix non-direct I/O) to and from the file. .\" The information is passed back in a structure of type .\" .B "struct biosize" .\" pointed to by the final argument. .\" biosize lengths are expressed in log base 2. .\" That is if the value is 14, then the true size is 2^14 (2 raised to .\" the 14th power). .\" The .\" .B biosz_read .\" field will contain the current value used by the system when reading .\" from the file. .\" Except at the end-of-file, the system will read from the file in .\" multiples of this length. .\" The .\" .B biosz_write .\" field will contain the current value used by the system when writing .\" to the file. .\" Except at the end-of-file, the system will write to the file in .\" multiples of this length. .\" The .\" .B dfl_biosz_read .\" and .\" .B dfl_biosz_write .\" will be set to the system default values for the opened file. .\" The .\" .B biosz_flags .\" field will be set to 1 if the current read or write value has been .\" explicitly set. .\" .\" .TP .\" .B XFS_IOC_SETBIOSIZE .\" This command sets information about the preferred buffered I/O size .\" used by the system when performing buffered I/O (e.g. standard Unix .\" non-direct I/O) to and from the file. .\" The information is passed in a structure of type .\" .B "struct biosize" .\" pointed to by the final argument. .\" Using smaller preferred I/O sizes can result in performance .\" improvements if the file is typically accessed using small .\" synchronous I/Os or if only a small amount of the file is accessed .\" using small random I/Os, resulting in little or no use of the .\" additional data read in near the random I/Os. .\" .\" To explicitly set the preferred I/O sizes, the .\" .B biosz_flags .\" field should be set to zero and the .\" .B biosz_read .\" and .\" .B biosz_write .\" fields should be set to the log base 2 of the desired read and .\" write lengths, respectively (e.g. 13 for 8K bytes, 14 for 16K .\" bytes, 15 for 32K bytes, etc.). Valid values are 13-16 .\" inclusive for machines with a 4K byte pagesize and 14-16 for .\" machines with a 16K byte pagesize. The specified read and .\" write values must also result in lengths that are greater than .\" or equal to the filesystem block size. .\" The .\" .B dfl_biosz_read .\" and .\" .B dfl_biosz_write .\" fields are ignored. .\" .\" If biosizes have already been explicitly set due to a prior use .\" of .\" .BR XFS_IOC_SETBIOSIZE , .\" and the requested sizes are larger than the .\" existing sizes, the .\" .I xfsctl .\" call will return successfully and the .\" system will use the smaller of the two sizes. However, if .\" .B biosz_flags .\" is set to 1, the system will use the new values .\" regardless of whether the new sizes are larger or smaller than the old. .\" .\" To reset the biosize values to the defaults for the filesystem .\" that the file resides in, the .\" .B biosz_flags .\" field should be set to 2. .\" The remainder of the fields will be ignored in that case. .\" .\" Changes made by .\" .B XFS_IOC_SETBIOSIZE .\" are transient. .\" The sizes are reset to the default values once the reference count on the .\" file drops to zero (e.g. all open file descriptors to that file .\" have been closed). .\" See .\" .I mount(8) .\" for details on how to set the .\" default biosize values for a filesystem. .PP .nf .B XFS_IOC_PATH_TO_HANDLE .B XFS_IOC_PATH_TO_FSHANDLE .B XFS_IOC_FD_TO_HANDLE .B XFS_IOC_OPEN_BY_HANDLE .B XFS_IOC_READLINK_BY_HANDLE .B XFS_IOC_ATTR_LIST_BY_HANDLE .B XFS_IOC_ATTR_MULTI_BY_HANDLE .fi .PD 0 .TP .B XFS_IOC_FSSETDM_BY_HANDLE These are all interfaces that are used to implement various .I libhandle functions (see .BR open_by_handle (3)). They are all subject to change and should not be called directly by applications. .SS Filesystem Operations In order to effect one of the following operations, the pathname and descriptor arguments passed to .BR xfsctl () can be any open file in the XFS filesystem in question. .PP .TP .B XFS_IOC_FSINUMBERS See .BR ioctl_xfs_fsinumbers (2) for more information. .TP .B XFS_IOC_FSGEOMETRY See .BR ioctl_xfs_fsop_geometry (2) for more information. .TP .B XFS_IOC_AG_GEOMETRY See .BR ioctl_xfs_ag_geometry (2) for more information. .TP .BR XFS_IOC_FSBULKSTAT " or " XFS_IOC_FSBULKSTAT_SINGLE See .BR ioctl_xfs_fsbulkstat (2) for more information. .TP .B XFS_IOC_SCRUB_METADATA See .BR ioctl_xfs_scrub_metadata (2) for more information. .TP .B XFS_IOC_FSCOUNTS See .BR ioctl_xfs_fscounts (2) for more information. .TP .nf .B XFS_IOC_GET_RESBLKS .fi .TP .B XFS_IOC_SET_RESBLKS See .BR ioctl_xfs_getresblks (2) for more information. Save yourself a lot of frustration and avoid these ioctls. .TP .B XFS_IOC_GOINGDOWN See .BR ioctl_xfs_goingdown (2) for more information. .PP .nf .B XFS_IOC_THAW .B XFS_IOC_FREEZE .B XFS_IOC_FSGROWFSDATA .B XFS_IOC_FSGROWFSLOG .fi .TP .B XFS_IOC_FSGROWFSRT These interfaces are used to implement various filesystem internal operations on XFS filesystems. The remainder of these operations will not be described further as they are not of general use to applications. .SH SEE ALSO .BR ioctl_xfs_fsgetxattr (2), .BR ioctl_xfs_fsop_geometry (2), .BR ioctl_xfs_fsbulkstat (2), .BR ioctl_xfs_scrub_metadata (2), .BR ioctl_xfs_fsinumbers (2), .BR ioctl_xfs_fscounts (2), .BR ioctl_xfs_getresblks (2), .BR ioctl_xfs_getbmap (2), .BR ioctl_xfs_goingdown (2), .BR fstatfs (2), .BR statfs (2), .BR xfs (5), .BR xfs_info (8). xfsprogs-5.3.0/man/man5/Makefile0000644000175000017500000000060313034246041016313 0ustar nathansnathans# # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = ../.. include $(TOPDIR)/include/builddefs MAN_SECTION = 5 MAN_PAGES = $(shell echo *.$(MAN_SECTION)) MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) default : $(MAN_PAGES) include $(BUILDRULES) install : default $(INSTALL) -m 755 -d $(MAN_DEST) $(INSTALL_MAN) install-dev : xfsprogs-5.3.0/man/man5/projects.50000644000175000017500000000107013034246041016571 0ustar nathansnathans.TH projects 5 .SH NAME projects \- persistent project root definition .SH DESCRIPTION The .I /etc/projects file provides a mapping between numeric project identifiers and those directories which are the roots of the quota tree. Its format is simply: .nf .sp .in +5 # comments are hash-prefixed # ... 10:/export/cage 42:/var/log .in -5 .fi .PP The .I /etc/projects file is optional, instead .BR xfs_quota (8) can be used with the .B \-p argument to specify a project root directly for each operation. .SH SEE ALSO .BR xfs_quota (8), .BR xfsctl (3), .BR projid (5). xfsprogs-5.3.0/man/man5/projid.50000644000175000017500000000106713034246041016235 0ustar nathansnathans.TH projid 5 .SH NAME projid \- the project name mapping file .SH DESCRIPTION The .I /etc/projid file provides a mapping between numeric project identifiers and a simple human readable name (similar relationship to the one that exists between usernames and uids). Its format is simply: .nf .sp .in +5 # comments are hash-prefixed # ... cage:10 logfiles:42 .in -5 .fi .PP This file is optional, if a project identifier cannot be mapped to a name, it will be parsed and displayed as a numeric value. .SH SEE ALSO .BR xfs_quota (8), .BR xfsctl (3), .BR projects (5). xfsprogs-5.3.0/man/man5/xfs.50000644000175000017500000003035113435336037015556 0ustar nathansnathans\." tbl .TH xfs 5 .SH NAME xfs \- layout, mount options, and supported file attributes for the XFS filesystem .SH DESCRIPTION An XFS filesystem can reside on a regular disk partition or on a logical volume. An XFS filesystem has up to three parts: a data section, a log section, and a realtime section. Using the default .BR mkfs.xfs (8) options, the realtime section is absent, and the log area is contained within the data section. The log section can be either separate from the data section or contained within it. The filesystem sections are divided into a certain number of .IR blocks , whose size is specified at .BR mkfs.xfs (8) time with the .B \-b option. .PP The data section contains all the filesystem metadata (inodes, directories, indirect blocks) as well as the user file data for ordinary (non-realtime) files and the log area if the log is .I internal to the data section. The data section is divided into a number of .IR "allocation groups" . The number and size of the allocation groups are chosen by .BR mkfs.xfs (8) so that there is normally a small number of equal-sized groups. The number of allocation groups controls the amount of parallelism available in file and block allocation. It should be increased from the default if there is sufficient memory and a lot of allocation activity. The number of allocation groups should not be set very high, since this can cause large amounts of CPU time to be used by the filesystem, especially when the filesystem is nearly full. More allocation groups are added (of the original size) when .BR xfs_growfs (8) is run. .PP The log section (or area, if it is internal to the data section) is used to store changes to filesystem metadata while the filesystem is running until those changes are made to the data section. It is written sequentially during normal operation and read only during mount. When mounting a filesystem after a crash, the log is read to complete operations that were in progress at the time of the crash. .PP The realtime section is used to store the data of realtime files. These files had an attribute bit set through .BR xfsctl (3) after file creation, before any data was written to the file. The realtime section is divided into a number of .I extents of fixed size (specified at .BR mkfs.xfs (8) time). Each file in the realtime section has an extent size that is a multiple of the realtime section extent size. .PP Each allocation group contains several data structures. The first sector contains the superblock. For allocation groups after the first, the superblock is just a copy and is not updated after .BR mkfs.xfs (8). The next three sectors contain information for block and inode allocation within the allocation group. Also contained within each allocation group are data structures to locate free blocks and inodes; these are located through the header structures. .PP Each XFS filesystem is labeled with a Universal Unique Identifier (UUID). The UUID is stored in every allocation group header and is used to help distinguish one XFS filesystem from another, therefore you should avoid using .BR dd (1) or other block-by-block copying programs to copy XFS filesystems. If two XFS filesystems on the same machine have the same UUID, .BR xfsdump (8) may become confused when doing incremental and resumed dumps. .BR xfsdump (8) and .BR xfsrestore (8) are recommended for making copies of XFS filesystems. .SH OPERATIONS Some functionality specific to the XFS filesystem is accessible to applications through the .BR xfsctl (3) and by-handle (see .BR open_by_handle (3)) interfaces. .SH MOUNT OPTIONS The following XFS-specific mount options may be used when mounting an XFS filesystem. Other generic options may be used as well; refer to the .BR mount (8) manual page for more details. .TP .B allocsize=size Sets the buffered I/O end-of-file preallocation size when doing delayed allocation writeout. Valid values for this option are page size (typically 4KiB) through to 1GiB, inclusive, in power-of-2 increments. .sp The default behavior is for dynamic end-of-file preallocation size, which uses a set of heuristics to optimise the preallocation size based on the current allocation patterns within the file and the access patterns to the file. Specifying a fixed allocsize value turns off the dynamic behavior. .TP .BR attr2 | noattr2 The options enable/disable an "opportunistic" improvement to be made in the way inline extended attributes are stored on-disk. When the new form is used for the first time when attr2 is selected (either when setting or removing extended attributes) the on-disk superblock feature bit field will be updated to reflect this format being in use. .sp The default behavior is determined by the on-disk feature bit indicating that attr2 behavior is active. If either mount option it set, then that becomes the new default used by the filesystem. .sp CRC enabled filesystems always use the attr2 format, and so will reject the noattr2 mount option if it is set. .TP .BR discard | nodiscard Enable/disable the issuing of commands to let the block device reclaim space freed by the filesystem. This is useful for SSD devices, thinly provisioned LUNs and virtual machine images, but may have a performance impact. .sp Note: It is currently recommended that you use the fstrim application to discard unused blocks rather than the discard mount option because the performance impact of this option is quite severe. For this reason, nodiscard is the default. .TP .BR grpid | bsdgroups | nogrpid | sysvgroups These options define what group ID a newly created file gets. When grpid is set, it takes the group ID of the directory in which it is created; otherwise it takes the fsgid of the current process, unless the directory has the setgid bit set, in which case it takes the gid from the parent directory, and also gets the setgid bit set if it is a directory itself. .TP .B filestreams Make the data allocator use the filestreams allocation mode across the entire filesystem rather than just on directories configured to use it. .TP .BR ikeep | noikeep When ikeep is specified, XFS does not delete empty inode clusters and keeps them around on disk. When noikeep is specified, empty inode clusters are returned to the free space pool. noikeep is the default. .TP .BR inode32 | inode64 When inode32 is specified, it indicates that XFS limits inode creation to locations which will not result in inode numbers with more than 32 bits of significance. .sp When inode64 is specified, it indicates that XFS is allowed to create inodes at any location in the filesystem, including those which will result in inode numbers occupying more than 32 bits of significance. .sp inode32 is provided for backwards compatibility with older systems and applications, since 64 bits inode numbers might cause problems for some applications that cannot handle large inode numbers. If applications are in use which do not handle inode numbers bigger than 32 bits, the inode32 option should be specified. .sp For kernel v3.7 and later, inode64 is the default. .TP .BR largeio | nolargeio If "nolargeio" is specified, the optimal I/O reported in st_blksize by stat(2) will be as small as possible to allow user applications to avoid inefficient read/modify/write I/O. This is typically the page size of the machine, as this is the granularity of the page cache. .sp If "largeio" specified, a filesystem that was created with a "swidth" specified will return the "swidth" value (in bytes) in st_blksize. If the filesystem does not have a "swidth" specified but does specify an "allocsize" then "allocsize" (in bytes) will be returned instead. Otherwise the behavior is the same as if "nolargeio" was specified. nolargeio is the default. .TP .B logbufs=value Set the number of in-memory log buffers. Valid numbers range from 2\(en8 inclusive. .sp The default value is 8 buffers. .sp If the memory cost of 8 log buffers is too high on small systems, then it may be reduced at some cost to performance on metadata intensive workloads. The logbsize option below controls the size of each buffer and so is also relevant to this case. .TP .B logbsize=value Set the size of each in-memory log buffer. The size may be specified in bytes, or in kibibytes (KiB) with a "k" suffix. Valid sizes for version 1 and version 2 logs are 16384 (value=16k) and 32768 (value=32k). Valid sizes for version 2 logs also include 65536 (value=64k), 131072 (value=128k) and 262144 (value=256k). The logbsize must be an integer multiple of the log stripe unit configured at mkfs time. .sp The default value for version 1 logs is 32768, while the default value for version 2 logs is max(32768, log_sunit). .TP .BR logdev=device " and " rtdev=device Use an external log (metadata journal) and/or real-time device. An XFS filesystem has up to three parts: a data section, a log section, and a real-time section. The real-time section is optional, and the log section can be separate from the data section or contained within it. .TP .B noalign Data allocations will not be aligned at stripe unit boundaries. This is only relevant to filesystems created with non-zero data alignment parameters (sunit, swidth) by mkfs. .TP .B norecovery The filesystem will be mounted without running log recovery. If the filesystem was not cleanly unmounted, it is likely to be inconsistent when mounted in "norecovery" mode. Some files or directories may not be accessible because of this. Filesystems mounted "norecovery" must be mounted read-only or the mount will fail. .TP .B nouuid Don't check for double mounted file systems using the file system uuid. This is useful to mount LVM snapshot volumes, and often used in combination with "norecovery" for mounting read-only snapshots. .TP .B noquota Forcibly turns off all quota accounting and enforcement within the filesystem. .TP .B uquota/usrquota/quota/uqnoenforce/qnoenforce User disk quota accounting enabled, and limits (optionally) enforced. Refer to xfs_quota(8) for further details. .TP .B gquota/grpquota/gqnoenforce Group disk quota accounting enabled and limits (optionally) enforced. Refer to xfs_quota(8) for further details. .TP .B pquota/prjquota/pqnoenforce Project disk quota accounting enabled and limits (optionally) enforced. Refer to xfs_quota(8) for further details. .TP .BR sunit=value " and " swidth=value Used to specify the stripe unit and width for a RAID device or a stripe volume. "value" must be specified in 512-byte block units. These options are only relevant to filesystems that were created with non-zero data alignment parameters. .sp The sunit and swidth parameters specified must be compatible with the existing filesystem alignment characteristics. In general, that means the only valid changes to sunit are increasing it by a power-of-2 multiple. Valid swidth values are any integer multiple of a valid sunit value. .sp Typically the only time these mount options are necessary if after an underlying RAID device has had it's geometry modified, such as adding a new disk to a RAID5 lun and reshaping it. .TP .B swalloc Data allocations will be rounded up to stripe width boundaries when the current end of file is being extended and the file size is larger than the stripe width size. .TP .B wsync When specified, all filesystem namespace operations are executed synchronously. This ensures that when the namespace operation (create, unlink, etc) completes, the change to the namespace is on stable storage. This is useful in HA setups where failover must not result in clients seeing inconsistent namespace presentation during or after a failover event. .SH REMOVED MOUNT OPTIONS The following mount options have been removed from the kernel, and will yield mount failures if specified. Mount options are deprecated for a significant period time prior to removal. .TS tab(@); lbl. Name@Removed ----@------- delaylog/nodelaylog@v4.0 ihashsize@v4.0 irixsgid@v4.0 osyncisdsync/osyncisosync@v4.0 barrier/nobarrier@v4.19 .TE .SH FILE ATTRIBUTES The XFS filesystem supports setting the following file attributes on Linux systems using the .BR chattr (1) utility: .sp .BR a " - append only" .sp .BR A " - no atime updates" .sp .BR d " - no dump" .sp .BR i " - immutable" .sp .BR S " - synchronous updates" .sp For descriptions of these attribute flags, please refer to the .BR chattr (1) man page. .SH SEE ALSO .BR chattr (1), .BR xfsctl (3), .BR mount (8), .BR mkfs.xfs (8), .BR xfs_info (8), .BR xfs_admin (8), .BR xfsdump (8), .BR xfsrestore (8). xfsprogs-5.3.0/man/man8/Makefile0000644000175000017500000000076613435336037016342 0ustar nathansnathans# # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = ../.. include $(TOPDIR)/include/builddefs MAN_SECTION = 8 ifneq ("$(ENABLE_SCRUB)","yes") MAN_PAGES = $(filter-out xfs_scrub%,$(shell echo *.$(MAN_SECTION))) else MAN_PAGES = $(shell echo *.$(MAN_SECTION)) endif MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) default : $(MAN_PAGES) include $(BUILDRULES) install : default $(INSTALL) -m 755 -d $(MAN_DEST) $(INSTALL_MAN) install-dev : xfsprogs-5.3.0/man/man8/fsck.xfs.80000644000175000017500000000146313435336037016513 0ustar nathansnathans.TH fsck.xfs 8 .SH NAME fsck.xfs \- do nothing, successfully .SH SYNOPSIS .B fsck.xfs [ .I filesys \&... ] .SH DESCRIPTION .B fsck.xfs is called by the generic Linux .BR fsck (8) program at startup to check and repair an XFS filesystem. XFS is a journaling filesystem and performs recovery at .BR mount (8) time if necessary, so .B fsck.xfs simply exits with a zero exit status. .PP If you wish to check the consistency of an XFS filesystem, or repair a damaged or corrupt XFS filesystem, see .BR xfs_repair (8). .PP However, the system administrator can force .B fsck.xfs to run .BR xfs_repair (8) at boot time by creating a /forcefsck file or booting the system with "fsck.mode=force" on the kernel command line. . .SH FILES .IR /etc/fstab . .SH SEE ALSO .BR fsck (8), .BR fstab (5), .BR xfs (5), .BR xfs_repair (8). xfsprogs-5.3.0/man/man8/mkfs.xfs.80000644000175000017500000007074413570057155016536 0ustar nathansnathans.TH mkfs.xfs 8 .SH NAME mkfs.xfs \- construct an XFS filesystem .SH SYNOPSIS .B mkfs.xfs [ .B \-b .I block_size_options ] [ .B \-m .I global_metadata_options ] [ .B \-d .I data_section_options ] [ .B \-f ] [ .B \-i .I inode_options ] [ .B \-l .I log_section_options ] [ .B \-n .I naming_options ] [ .B \-p .I protofile ] [ .B \-q ] [ .B \-r .I realtime_section_options ] [ .B \-s .I sector_size_options ] [ .B \-L .I label ] [ .B \-N ] [ .B \-K ] .I device .br .B mkfs.xfs \-V .SH DESCRIPTION .B mkfs.xfs constructs an XFS filesystem by writing on a special file using the values found in the arguments of the command line. It is invoked automatically by .BR mkfs (8) when it is given the .B \-t xfs option. .PP In its simplest (and most commonly used form), the size of the filesystem is determined from the disk driver. As an example, to make a filesystem with an internal log on the first partition on the first SCSI disk, use: .IP .B mkfs.xfs /dev/sda1 .PP The metadata log can be placed on another device to reduce the number of disk seeks. To create a filesystem on the first partition on the first SCSI disk with a 10MiB log located on the first partition on the second SCSI disk, use: .RS .HP .B mkfs.xfs\ \-l\ logdev=/dev/sdb1,size=10m /dev/sda1 .RE .PP Each of the .I option elements in the argument list above can be given as multiple comma-separated suboptions if multiple suboptions apply to the same option. Equivalently, each main option can be given multiple times with different suboptions. For example, .B \-l internal,size=10m and .B \-l internal \-l size=10m are equivalent. .PP In the descriptions below, sizes are given in sectors, bytes, blocks, kilobytes, megabytes, gigabytes, etc. Sizes are treated as hexadecimal if prefixed by 0x or 0X, octal if prefixed by 0, or decimal otherwise. The following lists possible multiplication suffixes: .RS .PD 0 .HP .BR s "\ \-\ multiply by sector size (default = 512, see " \-s option below). .HP .BR b "\ \-\ multiply by filesystem block size (default = 4K, see " \-b option below). .HP .BR k "\ \-\ multiply by one kilobyte (1,024 bytes)." .HP .BR m "\ \-\ multiply by one megabyte (1,048,576 bytes)." .HP .BR g "\ \-\ multiply by one gigabyte (1,073,741,824 bytes)." .HP .BR t "\ \-\ multiply by one terabyte (1,099,511,627,776 bytes)." .HP .BR p "\ \-\ multiply by one petabyte (1,024 terabytes)." .HP .BR e "\ \-\ multiply by one exabyte (1,048,576 terabytes)." .PD .RE .PP When specifying parameters in units of sectors or filesystem blocks, the .B \-s option or the .B \-b option may be used to specify the size of the sector or block. If the size of the block or sector is not specified, the default sizes (block: 4KiB, sector: 512B) will be used. .PP Many feature options allow an optional argument of 0 or 1, to explicitly disable or enable the functionality. .SH OPTIONS .TP .BI \-b " block_size_options" This option specifies the fundamental block size of the filesystem. The valid .I block_size_option is: .RS 1.2i .TP .BI size= value The filesystem block size is specified with a .I value in bytes. The default value is 4096 bytes (4 KiB), the minimum is 512, and the maximum is 65536 (64 KiB). .IP Although .B mkfs.xfs will accept any of these values and create a valid filesystem, XFS on Linux can only mount filesystems with pagesize or smaller blocks. .RE .TP .BI \-m " global_metadata_options" These options specify metadata format options that either apply to the entire filesystem or aren't easily characterised by a specific functionality group. The valid .I global_metadata_options are: .RS 1.2i .TP .BI crc= value This is used to create a filesystem which maintains and checks CRC information in all metadata objects on disk. The value is either 0 to disable the feature, or 1 to enable the use of CRCs. .IP CRCs enable enhanced error detection due to hardware issues, whilst the format changes also improves crash recovery algorithms and the ability of various tools to validate and repair metadata corruptions when they are found. The CRC algorithm used is CRC32c, so the overhead is dependent on CPU architecture as some CPUs have hardware acceleration of this algorithm. Typically the overhead of calculating and checking the CRCs is not noticeable in normal operation. .IP By default, .B mkfs.xfs will enable metadata CRCs. .TP .BI finobt= value This option enables the use of a separate free inode btree index in each allocation group. The value is either 0 to disable the feature, or 1 to create a free inode btree in each allocation group. .IP The free inode btree mirrors the existing allocated inode btree index which indexes both used and free inodes. The free inode btree does not index used inodes, allowing faster, more consistent inode allocation performance as filesystems age. .IP By default, .B mkfs.xfs will create free inode btrees for filesystems created with the (default) .B \-m crc=1 option set. When the option .B \-m crc=0 is used, the free inode btree feature is not supported and is disabled. .TP .BI uuid= value Use the given value as the filesystem UUID for the newly created filesystem. The default is to generate a random UUID. .TP .BI rmapbt= value This option enables the creation of a reverse-mapping btree index in each allocation group. The value is either 0 to disable the feature, or 1 to create the btree. .IP The reverse mapping btree maps filesystem blocks to the owner of the filesystem block. Most of the mappings will be to an inode number and an offset, though there will also be mappings to filesystem metadata. This secondary metadata can be used to validate the primary metadata or to pinpoint exactly which data has been lost when a disk error occurs. .IP By default, .B mkfs.xfs will not create reverse mapping btrees. This feature is only available for filesystems created with the (default) .B \-m crc=1 option set. When the option .B \-m crc=0 is used, the reverse mapping btree feature is not supported and is disabled. .TP .BI reflink= value This option enables the use of a separate reference count btree index in each allocation group. The value is either 0 to disable the feature, or 1 to create a reference count btree in each allocation group. .IP The reference count btree enables the sharing of physical extents between the data forks of different files, which is commonly known as "reflink". Unlike traditional Unix filesystems which assume that every inode and logical block pair map to a unique physical block, a reflink-capable XFS filesystem removes the uniqueness requirement, allowing up to four billion arbitrary inode/logical block pairs to map to a physical block. If a program tries to write to a multiply-referenced block in a file, the write will be redirected to a new block, and that file's logical-to-physical mapping will be changed to the new block ("copy on write"). This feature enables the creation of per-file snapshots and deduplication. It is only available for the data forks of regular files. .IP By default, .B mkfs.xfs will create reference count btrees and therefore will enable the reflink feature. This feature is only available for filesystems created with the (default) .B \-m crc=1 option set. When the option .B \-m crc=0 is used, the reference count btree feature is not supported and reflink is disabled. .IP Note: the filesystem DAX mount option ( .B \-o dax ) is incompatible with reflink-enabled XFS filesystems. To use filesystem DAX with XFS, specify the .B \-m reflink=0 option to mkfs.xfs to disable the reflink feature. .RE .TP .BI \-d " data_section_options" These options specify the location, size, and other parameters of the data section of the filesystem. The valid .I data_section_options are: .RS 1.2i .TP .BI agcount= value This is used to specify the number of allocation groups. The data section of the filesystem is divided into allocation groups to improve the performance of XFS. More allocation groups imply that more parallelism can be achieved when allocating blocks and inodes. The minimum allocation group size is 16 MiB; the maximum size is just under 1 TiB. The data section of the filesystem is divided into .I value allocation groups (default value is scaled automatically based on the underlying device size). .TP .BI agsize= value This is an alternative to using the .B agcount suboption. The .I value is the desired size of the allocation group expressed in bytes (usually using the .BR m " or " g suffixes). This value must be a multiple of the filesystem block size, and must be at least 16MiB, and no more than 1TiB, and may be automatically adjusted to properly align with the stripe geometry. The .B agcount and .B agsize suboptions are mutually exclusive. .TP .BI cowextsize= value Set the copy-on-write extent size hint on all inodes created by .BR mkfs.xfs "." The value must be provided in units of filesystem blocks. If the value is zero, the default value (currently 32 blocks) will be used. Directories will pass on this hint to newly created children. .TP .BI name= value This can be used to specify the name of the special file containing the filesystem. In this case, the log section must be specified as .B internal (with a size, see the .B \-l option below) and there can be no real-time section. .TP .BI file[= value ] This is used to specify that the file given by the .B name suboption is a regular file. The .I value is either 0 or 1, with 1 signifying that the file is regular. This suboption is used only to make a filesystem image. If the .I value is omitted then 1 is assumed. .TP .BI size= value This is used to specify the size of the data section. This suboption is required if .B \-d file[=1] is given. Otherwise, it is only needed if the filesystem should occupy less space than the size of the special file. .TP .BI sunit= value This is used to specify the stripe unit for a RAID device or a logical volume. The .I value has to be specified in 512-byte block units. Use the .B su suboption to specify the stripe unit size in bytes. This suboption ensures that data allocations will be stripe unit aligned when the current end of file is being extended and the file size is larger than 512KiB. Also inode allocations and the internal log will be stripe unit aligned. .TP .BI su= value This is an alternative to using .B sunit. The .B su suboption is used to specify the stripe unit for a RAID device or a striped logical volume. The .I value has to be specified in bytes, (usually using the .BR m " or " g suffixes). This .I value must be a multiple of the filesystem block size. .TP .BI swidth= value This is used to specify the stripe width for a RAID device or a striped logical volume. The .I value has to be specified in 512-byte block units. Use the .B sw suboption to specify the stripe width size in bytes. This suboption is required if .B \-d sunit has been specified and it has to be a multiple of the .B \-d sunit suboption. .TP .BI sw= value suboption is an alternative to using .B swidth. The .B sw suboption is used to specify the stripe width for a RAID device or striped logical volume. The .I value is expressed as a multiplier of the stripe unit, usually the same as the number of stripe members in the logical volume configuration, or data disks in a RAID device. .IP When a filesystem is created on a logical volume device, .B mkfs.xfs will automatically query the logical volume for appropriate .B sunit and .B swidth values. .TP .BI noalign This option disables automatic geometry detection and creates the filesystem without stripe geometry alignment even if the underlying storage device provides this information. .TP .BI rtinherit= value If set, all inodes created by .B mkfs.xfs will be created with the realtime flag set. Directories will pass on this flag to newly created children. .TP .BI projinherit= value All inodes created by .B mkfs.xfs will be assigned this project quota id. Directories will pass on the project id to newly created children. .TP .BI extszinherit= value All inodes created by .B mkfs.xfs will have this extent size hint applied. The value must be provided in units of filesystem blocks. Directories will pass on this hint to newly created children. .RE .TP .B \-f Force overwrite when an existing filesystem is detected on the device. By default, .B mkfs.xfs will not write to the device if it suspects that there is a filesystem or partition table on the device already. .TP .BI \-i " inode_options" This option specifies the inode size of the filesystem, and other inode allocation parameters. The XFS inode contains a fixed-size part and a variable-size part. The variable-size part, whose size is affected by this option, can contain: directory data, for small directories; attribute data, for small attribute sets; symbolic link data, for small symbolic links; the extent list for the file, for files with a small number of extents; and the root of a tree describing the location of extents for the file, for files with a large number of extents. .IP The valid .I inode_options are: .RS 1.2i .TP .BI size= value " | perblock=" value The inode size is specified either as a .I value in bytes with .BR size= or as the number fitting in a filesystem block with .BR perblock= . The minimum (and default) .I value is 256 bytes without crc, 512 bytes with crc enabled. The maximum .I value is 2048 (2 KiB) subject to the restriction that the inode size cannot exceed one half of the filesystem block size. .IP XFS uses 64-bit inode numbers internally; however, the number of significant bits in an inode number is affected by filesystem geometry. In practice, filesystem size and inode size are the predominant factors. The Linux kernel (on 32 bit hardware platforms) and most applications cannot currently handle inode numbers greater than 32 significant bits, so if no inode size is given on the command line, .B mkfs.xfs will attempt to choose a size such that inode numbers will be < 32 bits. If an inode size is specified, or if a filesystem is sufficiently large, .B mkfs.xfs will warn if this will create inode numbers > 32 significant bits. .TP .BI maxpct= value This specifies the maximum percentage of space in the filesystem that can be allocated to inodes. The default .I value is 25% for filesystems under 1TB, 5% for filesystems under 50TB and 1% for filesystems over 50TB. .IP In the default inode allocation mode, inode blocks are chosen such that inode numbers will not exceed 32 bits, which restricts the inode blocks to the lower portion of the filesystem. The data block allocator will avoid these low blocks to accommodate the specified maxpct, so a high value may result in a filesystem with nothing but inodes in a significant portion of the lower blocks of the filesystem. (This restriction is not present when the filesystem is mounted with the .I "inode64" option on 64-bit platforms). .IP Setting the value to 0 means that essentially all of the filesystem can become inode blocks, subject to inode32 restrictions. .IP This value can be modified with .IR xfs_growfs(8) . .TP .BI align[= value ] This is used to specify that inode allocation is or is not aligned. The .I value is either 0 or 1, with 1 signifying that inodes are allocated aligned. If the .I value is omitted, 1 is assumed. The default is that inodes are aligned. Aligned inode access is normally more efficient than unaligned access; alignment must be established at the time the filesystem is created, since inodes are allocated at that time. This option can be used to turn off inode alignment when the filesystem needs to be mountable by a version of IRIX that does not have the inode alignment feature (any release of IRIX before 6.2, and IRIX 6.2 without XFS patches). .TP .BI attr= value This is used to specify the version of extended attribute inline allocation policy to be used. By default, this is 2, which uses an efficient algorithm for managing the available inline inode space between attribute and extent data. .IP The previous version 1, which has fixed regions for attribute and extent data, is kept for backwards compatibility with kernels older than version 2.6.16. .TP .BI projid32bit[= value ] This is used to enable 32bit quota project identifiers. The .I value is either 0 or 1, with 1 signifying that 32bit projid are to be enabled. If the value is omitted, 1 is assumed. (This default changed in release version 3.2.0.) .TP .BI sparse[= value ] Enable sparse inode chunk allocation. The .I value is either 0 or 1, with 1 signifying that sparse allocation is enabled. If the value is omitted, 1 is assumed. Sparse inode allocation is disabled by default. This feature is only available for filesystems formatted with .B \-m crc=1. .IP When enabled, sparse inode allocation allows the filesystem to allocate smaller than the standard 64-inode chunk when free space is severely limited. This feature is useful for filesystems that might fragment free space over time such that no free extents are large enough to accommodate a chunk of 64 inodes. Without this feature enabled, inode allocations can fail with out of space errors under severe fragmented free space conditions. .RE .TP .BI \-l " log_section_options" These options specify the location, size, and other parameters of the log section of the filesystem. The valid .I log_section_options are: .RS 1.2i .TP .BI agnum= value If the log is internal, allocate it in this AG. .TP .BI internal[= value ] This is used to specify that the log section is a piece of the data section instead of being another device or logical volume. The .I value is either 0 or 1, with 1 signifying that the log is internal. If the .I value is omitted, 1 is assumed. .TP .BI logdev= device This is used to specify that the log section should reside on the .I device separate from the data section. The .B internal=1 and .B logdev options are mutually exclusive. .TP .BI size= value This is used to specify the size of the log section. .IP If the log is contained within the data section and .B size isn't specified, .B mkfs.xfs will try to select a suitable log size depending on the size of the filesystem. The actual logsize depends on the filesystem block size and the directory block size. .IP Otherwise, the .B size suboption is only needed if the log section of the filesystem should occupy less space than the size of the special file. The .I value is specified in bytes or blocks, with a .B b suffix meaning multiplication by the filesystem block size, as described above. The overriding minimum value for size is 512 blocks. With some combinations of filesystem block size, inode size, and directory block size, the minimum log size is larger than 512 blocks. .TP .BI version= value This specifies the version of the log. The current default is 2, which allows for larger log buffer sizes, as well as supporting stripe-aligned log writes (see the sunit and su options, below). .IP The previous version 1, which is limited to 32k log buffers and does not support stripe-aligned writes, is kept for backwards compatibility with very old 2.4 kernels. .TP .BI sunit= value This specifies the alignment to be used for log writes. The .I value has to be specified in 512-byte block units. Use the .B su suboption to specify the log stripe unit size in bytes. Log writes will be aligned on this boundary, and rounded up to this boundary. This gives major improvements in performance on some configurations such as software RAID5 when the .B sunit is specified as the filesystem block size. The equivalent byte value must be a multiple of the filesystem block size. Version 2 logs are automatically selected if the log .B sunit suboption is specified. .IP The .B su suboption is an alternative to using .B sunit. .TP .BI su= value This is used to specify the log stripe. The .I value has to be specified in bytes, (usually using the .BR s " or " b suffixes). This value must be a multiple of the filesystem block size. Version 2 logs are automatically selected if the log .B su suboption is specified. .TP .BI lazy-count= value This changes the method of logging various persistent counters in the superblock. Under metadata intensive workloads, these counters are updated and logged frequently enough that the superblock updates become a serialization point in the filesystem. The .I value can be either 0 or 1. .IP With .BR lazy-count=1 , the superblock is not modified or logged on every change of the persistent counters. Instead, enough information is kept in other parts of the filesystem to be able to maintain the persistent counter values without needed to keep them in the superblock. This gives significant improvements in performance on some configurations. The default .I value is 1 (on) so you must specify .B lazy-count=0 if you want to disable this feature for older kernels which don't support it. .RE .TP .BI \-n " naming_options" These options specify the version and size parameters for the naming (directory) area of the filesystem. The valid .I naming_options are: .RS 1.2i .TP .BI size= value The directory block size is specified with a .I value in bytes. The block size must be a power of 2 and cannot be less than the filesystem block size. The default size .I value for version 2 directories is 4096 bytes (4 KiB), unless the filesystem block size is larger than 4096, in which case the default .I value is the filesystem block size. For version 1 directories the block size is the same as the filesystem block size. .TP .BI version= value The naming (directory) version .I value can be either 2 or 'ci', defaulting to 2 if unspecified. With version 2 directories, the directory block size can be any power of 2 size from the filesystem block size up to 65536. .IP The .B version=ci option enables ASCII only case-insensitive filename lookup and version 2 directories. Filenames are case-preserving, that is, the names are stored in directories using the case they were created with. .IP Note: Version 1 directories are not supported. .TP .BI ftype= value This feature allows the inode type to be stored in the directory structure so that the .BR readdir (3) and .BR getdents (2) do not need to look up the inode to determine the inode type. The .I value is either 0 or 1, with 1 signifying that filetype information will be stored in the directory structure. The default value is 1. When CRCs are enabled (the default), the ftype functionality is always enabled, and cannot be turned off. .IP .RE .TP .BI \-p " protofile" If the optional .BI \-p " protofile" argument is given, .B mkfs.xfs uses .I protofile as a prototype file and takes its directions from that file. The blocks and inodes specifiers in the .I protofile are provided for backwards compatibility, but are otherwise unused. The syntax of the protofile is defined by a number of tokens separated by spaces or newlines. Note that the line numbers are not part of the syntax but are meant to help you in the following discussion of the file contents. .nf .sp .8v .in +5 \f71 /stand/\f1\f2diskboot\f1\f7 2 4872 110 3 d\-\-777 3 1 4 usr d\-\-777 3 1 5 sh \-\-\-755 3 1 /bin/sh 6 ken d\-\-755 6 1 7 $ 8 b0 b\-\-644 3 1 0 0 9 c0 c\-\-644 3 1 0 0 10 fifo p\-\-644 3 1 11 slink l\-\-644 3 1 /a/symbolic/link 12 : This is a comment line 13 $ 14 $\f1 .in -5 .fi .IP Line 1 is a dummy string. (It was formerly the bootfilename.) It is present for backward compatibility; boot blocks are not used on SGI systems. .IP Note that some string of characters must be present as the first line of the proto file to cause it to be parsed correctly; the value of this string is immaterial since it is ignored. .IP Line 2 contains two numeric values (formerly the numbers of blocks and inodes). These are also merely for backward compatibility: two numeric values must appear at this point for the proto file to be correctly parsed, but their values are immaterial since they are ignored. .IP The lines 3 through 11 specify the files and directories you want to include in this filesystem. Line 3 defines the root directory. Other directories and files that you want in the filesystem are indicated by lines 4 through 6 and lines 8 through 10. Line 11 contains symbolic link syntax. .IP Notice the dollar sign .RB ( $ ) syntax on line 7. This syntax directs the .B mkfs.xfs command to terminate the branch of the filesystem it is currently on and then continue from the directory specified by the next line, in this case line 8. It must be the last character on a line. The colon on line 12 introduces a comment; all characters up until the following newline are ignored. Note that this means you cannot have a file in a prototype file whose name contains a colon. The .B $ on lines 13 and 14 end the process, since no additional specifications follow. .IP File specifications provide the following: .IP * file mode .br * user ID .br * group ID .br * the file's beginning contents .P .IP A 6-character string defines the mode for a file. The first character of this string defines the file type. The character range for this first character is .B \-bcdpl. A file may be a regular file, a block special file, a character special file, directory files, named pipes (first-in, first out files), and symbolic links. The second character of the mode string is used to specify setuserID mode, in which case it is .BR u . If setuserID mode is not specified, the second character is .BR \- . The third character of the mode string is used to specify the setgroupID mode, in which case it is .BR g . If setgroupID mode is not specified, the third character is .BR \- . The remaining characters of the mode string are a three digit octal number. This octal number defines the owner, group, and other read, write, and execute permissions for the file, respectively. For more information on file permissions, see the .BR chmod (1) command. .IP Following the mode character string are two decimal number tokens that specify the user and group IDs of the file's owner. .IP In a regular file, the next token specifies the pathname from which the contents and size of the file are copied. In a block or character special file, the next token are two decimal numbers that specify the major and minor device numbers. When a file is a symbolic link, the next token specifies the contents of the link. When the file is a directory, the .B mkfs.xfs command creates the entries .B dot (.) and .B dot-dot (..) and then reads the list of names and file specifications in a recursive manner for all of the entries in the directory. A scan of the protofile is always terminated with the dollar ( .B $ ) token. .TP .B \-q Quiet option. Normally .B mkfs.xfs prints the parameters of the filesystem to be constructed; the .B \-q flag suppresses this. .TP .BI \-r " realtime_section_options" These options specify the location, size, and other parameters of the real-time section of the filesystem. The valid .I realtime_section_options are: .RS 1.2i .TP .BI rtdev= device This is used to specify the .I device which should contain the real-time section of the filesystem. The suboption value is the name of a block device. .TP .BI extsize= value This is used to specify the size of the blocks in the real-time section of the filesystem. This .I value must be a multiple of the filesystem block size. The minimum allowed size is the filesystem block size or 4 KiB (whichever is larger); the default size is the stripe width for striped volumes or 64 KiB for non-striped volumes; the maximum allowed size is 1 GiB. The real-time extent size should be carefully chosen to match the parameters of the physical media used. .TP .BI size= value This is used to specify the size of the real-time section. This suboption is only needed if the real-time section of the filesystem should occupy less space than the size of the partition or logical volume containing the section. .TP .BI noalign This option disables stripe size detection, enforcing a realtime device with no stripe geometry. .RE .TP .BI \-s " sector_size_options" This option specifies the fundamental sector size of the filesystem. The valid .I sector_size_option is: .RS 1.2i .TP .BI size= value The sector size is specified with a .I value in bytes. The default .I sector_size is 512 bytes. The minimum value for sector size is 512; the maximum is 32768 (32 KiB). The .I sector_size must be a power of 2 size and cannot be made larger than the filesystem block size. .RE .TP .BI \-L " label" Set the filesystem .IR label . XFS filesystem labels can be at most 12 characters long; if .I label is longer than 12 characters, .B mkfs.xfs will not proceed with creating the filesystem. Refer to the .BR mount "(8) and " xfs_admin (8) manual entries for additional information. .TP .B \-N Causes the file system parameters to be printed out without really creating the file system. .TP .B \-K Do not attempt to discard blocks at mkfs time. .TP .B \-V Prints the version number and exits. .SH SEE ALSO .BR xfs (5), .BR mkfs (8), .BR mount (8), .BR xfs_info (8), .BR xfs_admin (8). .SH BUGS With a prototype file, it is not possible to specify hard links. xfsprogs-5.3.0/man/man8/xfs_admin.80000644000175000017500000000607613034246041016731 0ustar nathansnathans.TH xfs_admin 8 .SH NAME xfs_admin \- change parameters of an XFS filesystem .SH SYNOPSIS .B xfs_admin [ .B \-eflpu ] [ .BR "\-c 0" | 1 ] [ .B \-L .I label ] [ .B \-U .I uuid ] .I device .br .B xfs_admin \-V .SH DESCRIPTION .B xfs_admin uses the .BR xfs_db (8) command to modify various parameters of a filesystem. .PP Devices that are mounted cannot be modified. Administrators must unmount filesystems before .BR xfs_admin " or " xfs_db (8) can convert parameters. A number of parameters of a mounted filesystem can be examined and modified using the .BR xfs_growfs (8) command. .SH OPTIONS .TP .B \-e Enables unwritten extent support on a filesystem that does not already have this enabled (for legacy filesystems, it can't be disabled anymore at mkfs time). .TP .B \-f Specifies that the filesystem image to be processed is stored in a regular file at .I device (see the .B mkfs.xfs \-d .I file option). .TP .B \-j Enables version 2 log format (journal format supporting larger log buffers). .TP .B \-l Print the current filesystem label. .TP .B \-p Enable 32bit project identifier support (PROJID32BIT feature). .TP .B \-u Print the current filesystem UUID (Universally Unique IDentifier). .TP .BR "\-c 0" | 1 Enable (1) or disable (0) lazy-counters in the filesystem. .IP Lazy-counters may not be disabled on Version 5 superblock filesystems (i.e. those with metadata CRCs enabled). .IP This operation may take quite a bit of time on large filesystems as the entire filesystem needs to be scanned when this option is changed. .IP With lazy-counters enabled, the superblock is not modified or logged on every change of the free-space and inode counters. Instead, enough information is kept in other parts of the filesystem to be able to maintain the counter values without needing to keep them in the superblock. This gives significant improvements in performance on some configurations and metadata intensive workloads. .TP .BI \-L " label" Set the filesystem label to .IR label . XFS filesystem labels can be at most 12 characters long; if .I label is longer than 12 characters, .B xfs_admin will truncate it and print a warning message. The filesystem label can be cleared using the special "\c .B \-\-\c " value for .IR label . .TP .BI \-U " uuid" Set the UUID of the filesystem to .IR uuid . A sample UUID looks like this: "c1b9d5a2-f162-11cf-9ece-0020afc76f16". The .I uuid may also be .BR nil , which will set the filesystem UUID to the null UUID. The .I uuid may also be .BR generate , which will generate a new UUID for the filesystem. Note that on CRC-enabled filesystems, this will set an incompatible flag such that older kernels will not be able to mount the filesystem. To remove this incompatible flag, use .BR restore , which will restore the original UUID and remove the incompatible feature flag as needed. .TP .B \-V Prints the version number and exits. .PP The .BR mount (8) manual entry describes how to mount a filesystem using its label or UUID, rather than its block special device name. .SH SEE ALSO .BR mkfs.xfs (8), .BR mount (8), .BR xfs_db (8), .BR xfs_growfs (8), .BR xfs_repair (8), .BR xfs (5). xfsprogs-5.3.0/man/man8/xfs_bmap.80000644000175000017500000000473113435336037016566 0ustar nathansnathans.TH xfs_bmap 8 .SH NAME xfs_bmap \- print block mapping for an XFS file .SH SYNOPSIS .B xfs_bmap [ .B \-adelpv ] [ .B \-n .I num_extents ] .I file .br .B xfs_bmap \-V .SH DESCRIPTION .B xfs_bmap prints the map of disk blocks used by files in an XFS filesystem. The map lists each .I extent used by the file, as well as regions in the file that do not have any corresponding blocks (holes). Each line of the listings takes the following form: .PP .RS .IR extent ": [" startoffset .. endoffset "]: " startblock .. endblock .RE .PP Holes are marked by replacing the .IR startblock .. endblock " with " hole . All the file offsets and disk blocks are in units of 512-byte blocks, no matter what the filesystem's block size is. .PP .SH OPTIONS .TP .B \-a If this option is specified, information about the file's attribute fork is printed instead of the default data fork. .TP .B \-d If portions of the file have been migrated offline by a DMAPI application, a DMAPI read event will be generated to bring those portions back online before the disk block map is printed. However if the .B \-d option is used, no DMAPI read event will be generated for a DMAPI file and offline portions will be reported as holes. .TP .B \-e If this option is used, .B xfs_bmap obtains all delayed allocation extents, and does not flush dirty pages to disk before querying extent data. With the .B \-v option, the .I flags column will show which extents have not yet been allocated. .TP .B \-l If this option is used, then .IP .RS 1.2i .RI < nblocks "> blocks" .RE .IP will be appended to each line. .I nblocks is the length of the extent described on the line in units of 512-byte blocks. .IP This flag has no effect if the .B \-v option is used. .TP .BI \-n " num_extents" If this option is given, .B xfs_bmap will display at most .I num_extents extents. In the absence of .BR \-n ", " xfs_bmap will display all extents in the file. .TP .B \-p If this option is used, .B xfs_bmap obtains all unwritten (preallocated) extents that do not contain written data. With the .B \-v option, the .I flags column will show which extents are preallocated/unwritten. .TP .B \-v Shows verbose information. When this flag is specified, additional AG specific information is appended to each line in the following form: .IP .RS 1.2i .IR agno " (" startagoffset .. endagoffset ") " nblocks " " flags .RE .IP A second .B \-v option will print out the .I flags legend. .TP .B \-V Prints the version number and exits. .SH SEE ALSO .BR xfs_fsr (8), .BR xfs (5). xfsprogs-5.3.0/man/man8/xfs_copy.80000644000175000017500000001051513034246041016604 0ustar nathansnathans.TH xfs_copy 8 .SH NAME xfs_copy \- copy the contents of an XFS filesystem .SH SYNOPSIS .B xfs_copy [ .B \-bd ] [ .B \-L .I log ] .I source target1 [ .I target2 \&... ] .br .B xfs_copy \-V .SH DESCRIPTION .B xfs_copy copies an XFS filesystem to one or more targets in parallel (see .BR xfs (5)). The first .RI ( source ) argument must be the pathname of the device or file containing the XFS filesystem. The remaining arguments specify one or more .I target devices or file names. If the pathnames specify devices, a copy of the source XFS filesystem is created on each device. The .I target can also be the name of a regular file, in which case an image of the source XFS filesystem is created in that file. If the file does not exist, .B xfs_copy creates the file. The length of the resulting file is equal to the size of the source filesystem. However, if the file is created on an XFS filesystem, the file consumes roughly the amount of space actually used in the source filesystem by the filesystem and the XFS log. The space saving is because .B xfs_copy seeks over free blocks instead of copying them and the XFS filesystem supports sparse files efficiently. .PP .B xfs_copy should only be used to copy unmounted filesystems, read-only mounted filesystems, or frozen filesystems (see .BR xfs_freeze (8)). Otherwise, the generated filesystem(s) would be inconsistent or corrupt. .PP .B xfs_copy does not alter the source filesystem in any way. Each new (target) filesystem is identical to the original filesystem except that new filesystems each have a new unique filesystem identifier (UUID). Therefore, if both the old and new filesystems will be used as separate distinct filesystems, .B xfs_copy or .BR xfsdump (8)/ xfsrestore (8) should be used to generate the new filesystem(s) instead of .BR dd (1) or other programs that do block-by-block disk copying. .PP .B xfs_copy uses synchronous writes to ensure that write errors are detected. .PP .B xfs_copy uses .BR pthreads (7) to perform simultaneous parallel writes. .B xfs_copy creates one additional thread for each target to be written. All threads die if .B xfs_copy terminates or aborts. .SH OPTIONS .TP .B \-d Create a duplicate (true clone) filesystem. This should be done only if the new filesystem will be used as a replacement for the original filesystem (such as in the case of disk replacement). .TP .B \-b The buffered option can be used to ensure direct IO is not attempted to any of the target files. This is useful when the filesystem holding the target file does not support direct IO. .TP .BI \-L " log" Specifies the location of the .I log if the default location of .I /var/tmp/xfs_copy.log.XXXXXX is not desired. .TP .B \-V Prints the version number and exits. .SH DIAGNOSTICS .B xfs_copy reports errors to both .B stderr and in more detailed form to a generated log file whose name is of the form .I /var/tmp/xfs_copy.log.XXXXXX or a log file specified by the .B \-L option. If .B xfs_copy detects a write error on a target, the copy of that one target is aborted and an error message is issued to both stderr and the log file, but the rest of the copies continue. When .B xfs_copy terminates, all aborted targets are reported to both .B stderr and the log file. .PP If all targets abort or if there is an error reading the source filesystem, .B xfs_copy immediately aborts. .PP .B xfs_copy returns an exit code of 0 if all targets are successfully copied and an exit code of 1 if any target fails. .SH NOTES When moving filesystems from one disk to another, if the original filesystem is significantly smaller than the new filesystem, and will be made larger, we recommend that .BR mkfs.xfs "(8) and " xfsdump (8)/ xfsrestore (8) be used instead of using .B xfs_copy and .BR xfs_growfs (8). The filesystem layout resulting from using .BR xfs_copy / xfs_growfs is almost always worse than the result of using .BR mkfs.xfs / xfsdump / xfsrestore but in the case of small filesystems, the differences can have a significant performance impact. This is due to the way .BR xfs_growfs (8) works, and not due to any shortcoming in .B xfs_copy itself. .SH CAVEATS .B xfs_copy does not copy XFS filesystems that have a real-time section or XFS filesystems with external logs. In both cases, .B xfs_copy aborts with an error message. .SH SEE ALSO .BR mkfs.xfs (8), .BR xfsdump (8), .BR xfsrestore (8), .BR xfs_freeze (8), .BR xfs_growfs (8), .BR xfs (5). xfsprogs-5.3.0/man/man8/xfs_db.80000644000175000017500000014721213435336037016236 0ustar nathansnathans.TH xfs_db 8 .SH NAME xfs_db \- debug an XFS filesystem .SH SYNOPSIS .B xfs_db [ .B \-c .I cmd ] ... [ .BR \-i | r | x | F ] [ .B \-f ] [ .B \-l .I logdev ] [ .B \-p .I progname ] .I device .br .B xfs_db \-V .SH DESCRIPTION .B xfs_db is used to examine an XFS filesystem. Under rare circumstances it can also be used to modify an XFS filesystem, but that task is normally left to .BR xfs_repair (8) or to scripts such as .BR xfs_admin (8) that run .BR xfs_db . .PP .SH OPTIONS .TP .BI \-c " cmd" .B xfs_db commands may be run interactively (the default) or as arguments on the command line. Multiple .B \-c arguments may be given. The commands are run in the sequence given, then the program exits. .TP .B \-f Specifies that the filesystem image to be processed is stored in a regular file at .I device (see the .BR mkfs.xfs "(8) " -d .I file option). This might happen if an image copy of a filesystem has been made into an ordinary file with .BR xfs_copy (8). .TP .B \-F Specifies that we want to continue even if the superblock magic is not correct. For use in .BR xfs_metadump . .TP .B \-i Allows execution on a mounted filesystem, provided it is mounted read-only. Useful for shell scripts which must only operate on filesystems in a guaranteed consistent state (either unmounted or mounted read-only). These semantics are slightly different to that of the .B -r option. .TP .BI \-l " logdev" Specifies the device where the filesystems external log resides. Only for those filesystems which use an external log. See the .BR mkfs.xfs "(8) " \-l option, and refer to .BR xfs (5) for a detailed description of the XFS log. .TP .BI \-p " progname" Set the program name to .I progname for prompts and some error messages, the default value is .BR xfs_db . .TP .B -r Open .I device or .I filename read-only. This option is required if the filesystem is mounted. It is only necessary to omit this flag if a command that changes data .RB ( write ", " blocktrash ", " crc ) is to be used. .TP .B \-x Specifies expert mode. This enables the .RB ( write ", " blocktrash ", " crc invalidate/revalidate) commands. .TP .B \-V Prints the version number and exits. .SH CONCEPTS .B xfs_db commands can be broken up into two classes. Most commands are for the navigation and display of data structures in the filesystem. Other commands are for scanning the filesystem in some way. .PP Commands which are used to navigate the filesystem structure take arguments which reflect the names of filesystem structure fields. There can be multiple field names separated by dots when the underlying structures are nested, as in C. The field names can be indexed (as an array index) if the underlying field is an array. The array indices can be specified as a range, two numbers separated by a dash. .PP .B xfs_db maintains a current address in the filesystem. The granularity of the address is a filesystem structure. This can be a filesystem block, an inode or quota (smaller than a filesystem block), or a directory block (could be larger than a filesystem block). There are a variety of commands to set the current address. Associated with the current address is the current data type, which is the structural type of this data. Commands which follow the structure of the filesystem always set the type as well as the address. Commands which examine pieces of an individual file (inode) need the current inode to be set, this is done with the .B inode command. .PP The current address/type information is actually maintained in a stack that can be explicitly manipulated with the .BR push ", " pop ", and " stack commands. This allows for easy examination of a nested filesystem structure. Also, the last several locations visited are stored in a ring buffer which can be manipulated with the .BR forward ", " back ", and " ring commands. .PP XFS filesystems are divided into a small number of allocation groups. .B xfs_db maintains a notion of the current allocation group which is manipulated by some commands. The initial allocation group is 0. .SH COMMANDS .PP Many commands have extensive online help. Use the .B help command for more details on any command. .TP .B a See the .B addr command. .TP .BI ablock " filoff" Set current address to the offset .I filoff (a filesystem block number) in the attribute area of the current inode. .TP .BI "addr [" field-expression ] Set current address to the value of the .IR field-expression . This is used to "follow" a reference in one structure to the object being referred to. If no argument is given, the current address is printed. .TP .BI "agf [" agno ] Set current address to the AGF block for allocation group .IR agno . If no argument is given, use the current allocation group. .TP .BI "agfl [" agno ] Set current address to the AGFL block for allocation group .IR agno . If no argument is given, use the current allocation group. .TP .BI "agi [" agno ] Set current address to the AGI block for allocation group .IR agno . If no argument is given, use the current allocation group. .TP .B b See the .B back command. .TP .B back Move to the previous location in the position ring. .TP .B blockfree Free block usage information collected by the last execution of the .B blockget command. This must be done before another .B blockget command can be given, presumably with different arguments than the previous one. .TP .BI "blockget [\-npvs] [\-b " bno "] ... [\-i " ino "] ..." Get block usage and check filesystem consistency. The information is saved for use by a subsequent .BR blockuse ", " ncheck ", or " blocktrash command. .RS 1.0i .TP 0.4i .B \-b is used to specify filesystem block numbers about which verbose information should be printed. .TP .B \-i is used to specify inode numbers about which verbose information should be printed. .TP .B \-n is used to save pathnames for inodes visited, this is used to support the .BR xfs_ncheck (8) command. It also means that pathnames will be printed for inodes that have problems. This option uses a lot of memory so is not enabled by default. .TP .B \-p causes error messages to be prefixed with the filesystem name being processed. This is useful if several copies of .B xfs_db are run in parallel. .TP .B \-s restricts output to severe errors only. This is useful if the output is too long otherwise. .TP .B \-v enables verbose output. Messages will be printed for every block and inode processed. .RE .TP .BI "blocktrash [-z] [\-o " offset "] [\-n " count "] [\-x " min "] [\-y " max "] [\-s " seed "] [\-0|1|2|3] [\-t " type "] ..." Trash randomly selected filesystem metadata blocks. Trashing occurs to randomly selected bits in the chosen blocks. This command is available only in debugging versions of .BR xfs_db . It is useful for testing .BR xfs_repair "(8). .RS 1.0i .TP 0.4i .BR \-0 " | " -1 " | " -2 " | " -3 These are used to set the operating mode for .BR blocktrash . Only one can be used: .B \-0 changed bits are cleared; .B \-1 changed bits are set; .B -2 changed bits are inverted; .B -3 changed bits are randomized. .TP .B \-n supplies the .I count of block-trashings to perform (default 1). .TP .B \-o supplies the bit .I offset at which to start trashing the block. If the value is preceded by a '+', the trashing will start at a randomly chosen offset that is larger than the value supplied. The default is to randomly choose an offset anywhere in the block. .TP .B \-s supplies a .I seed to the random processing. .TP .B \-t gives a .I type of blocks to be selected for trashing. Multiple .B \-t options may be given. If no .B \-t options are given then all metadata types can be trashed. .TP .B \-x sets the .I minimum size of bit range to be trashed. The default value is 1. .TP .B \-y sets the .I maximum size of bit range to be trashed. The default value is 1024. .TP .B \-z trashes the block at the top of the stack. It is not necessary to run .BI blockget if this option is supplied. .RE .TP .BI "blockuse [\-n] [\-c " count ] Print usage for current filesystem block(s). For each block, the type and (if any) inode are printed. .RS 1.0i .TP 0.4i .B \-c specifies a .I count of blocks to process. The default value is 1 (the current block only). .TP .B \-n specifies that file names should be printed. The prior .B blockget command must have also specified the .B \-n option. .RE .TP .BI "bmap [\-a] [\-d] [" block " [" len ]] Show the block map for the current inode. The map display can be restricted to an area of the file with the .I block and .I len arguments. If .I block is given and .I len is omitted then 1 is assumed for len. .IP The .B \-a and .B \-d options are used to select the attribute or data area of the inode, if neither option is given then both areas are shown. .TP .B btdump [-a] [-i] If the cursor points to a btree node, dump the btree from that block downward. If instead the cursor points to an inode, dump the data fork block mapping btree if there is one. If the cursor points to a directory or extended attribute btree node, dump that. By default, only records stored in the btree are dumped. .RS 1.0i .TP 0.4i .B \-a If the cursor points at an inode, dump the extended attribute block mapping btree, if present. .TP .B \-i Dump all keys and pointers in intermediate btree nodes, and all records in leaf btree nodes. .RE .TP .B check See the .B blockget command. .TP .BI "convert " "type number" " [" "type number" "] ... " type Convert from one address form to another. The known .IR type s, with alternate names, are: .RS 1.0i .PD 0 .HP .B agblock or .B agbno (filesystem block within an allocation group) .HP .B agino or .B aginode (inode number within an allocation group) .HP .B agnumber or .B agno (allocation group number) .HP .B bboff or .B daddroff (byte offset in a .BR daddr ) .HP .B blkoff or .B fsboff or .B agboff (byte offset in a .B agblock or .BR fsblock ) .HP .B byte or .B fsbyte (byte address in filesystem) .HP .B daddr or .B bb (disk address, 512-byte blocks) .HP .B fsblock or .B fsb or .B fsbno (filesystem block, see the .B fsblock command) .HP .B ino or .B inode (inode number) .HP .B inoidx or .B offset (index of inode in filesystem block) .HP .B inooff or .B inodeoff (byte offset in inode) .PD .RE .IP Only conversions that "make sense" are allowed. The compound form (with more than three arguments) is useful for conversions such as .B convert agno .I ag .B agbno .I agb .BR fsblock . .TP .B crc [\-i|\-r|\-v] Invalidates, revalidates, or validates the CRC (checksum) field of the current structure, if it has one. This command is available only on CRC-enabled filesystems. With no argument, validation is performed. Each command will display the resulting CRC value and state. .RS 1.0i .TP 0.4i .B \-i Invalidate the structure's CRC value (incrementing it by one), and write it to disk. .TP .B \-r Recalculate the current structure's correct CRC value, and write it to disk. .TP .B \-v Validate and display the current value and state of the structure's CRC. .RE .TP .BI "daddr [" d ] Set current address to the daddr (512 byte block) given by .IR d . If no value for .I d is given, the current address is printed, expressed as a daddr. The type is set to .B data (uninterpreted). .TP .BI dblock " filoff" Set current address to the offset .I filoff (a filesystem block number) in the data area of the current inode. .TP .BI "debug [" flagbits ] Set debug option bits. These are used for debugging .BR xfs_db . If no value is given for .IR flagbits , print the current debug option bits. These are for the use of the implementor. .TP .BI "dquot [" \-g | \-p | \-u ] " id" Set current address to a group, project or user quota block for the given ID. Defaults to user quota. .TP .BI "echo [" arg "] ..." Echo the arguments to the output. .TP .B f See the .B forward command. .TP .B forward Move forward to the next entry in the position ring. .TP .B frag [\-adflqRrv] Get file fragmentation data. This prints information about fragmentation of file data in the filesystem (as opposed to fragmentation of freespace, for which see the .B freesp command). Every file in the filesystem is examined to see how far from ideal its extent mappings are. A summary is printed giving the totals. .RS 1.0i .TP 0.4i .B \-v sets verbosity, every inode has information printed for it. The remaining options select which inodes and extents are examined. If no options are given then all are assumed set, otherwise just those given are enabled. .TP .B \-a enables processing of attribute data. .TP .B \-d enables processing of directory data. .TP .B \-f enables processing of regular file data. .TP .B \-l enables processing of symbolic link data. .TP .B \-q enables processing of quota file data. .TP .B \-R enables processing of realtime control file data. .TP .B \-r enables processing of realtime file data. .RE .TP .BI "freesp [\-bcds] [\-A " alignment "] [\-a " ag "] ... [\-e " i "] [\-h " h1 "] ... [\-m " m ] Summarize free space for the filesystem. The free blocks are examined and totalled, and displayed in the form of a histogram, with a count of extents in each range of free extent sizes. .RS 1.0i .TP 0.4i .B \-A reports only free extents with starting blocks aligned to .I alignment blocks. .TP .B \-a adds .I ag to the list of allocation groups to be processed. If no .B \-a options are given then all allocation groups are processed. .TP .B \-b specifies that the histogram buckets are binary-sized, with the starting sizes being the powers of 2. .TP .B \-c specifies that .B freesp will search the by-size (cnt) space Btree instead of the default by-block (bno) space Btree. .TP .B \-d specifies that every free extent will be displayed. .TP .B \-e specifies that the histogram buckets are equal-sized, with the size specified as .IR i . .TP .B \-h specifies a starting block number for a histogram bucket as .IR h1 . Multiple .BR \-h 's are given to specify the complete set of buckets. .TP .B \-m specifies that the histogram starting block numbers are powers of .IR m . This is the general case of .BR \-b . .TP .B \-s specifies that a final summary of total free extents, free blocks, and the average free extent size is printed. .RE .TP .B fsb See the .B fsblock command. .TP .BI "fsblock [" fsb ] Set current address to the fsblock value given by .IR fsb . If no value for .I fsb is given the current address is printed, expressed as an fsb. The type is set to .B data (uninterpreted). XFS filesystem block numbers are computed .RI (( agno " << " agshift ") | " agblock ) where .I agshift depends on the size of an allocation group. Use the .B convert command to convert to and from this form. Block numbers given for file blocks (for instance from the .B bmap command) are in this form. .TP .BI "fsmap [ " start " ] [ " end " ] Prints the mapping of disk blocks used by an XFS filesystem. The map lists each extent used by files, allocation group metadata, journalling logs, and static filesystem metadata, as well as any regions that are unused. All blocks, offsets, and lengths are specified in units of 512-byte blocks, no matter what the filesystem's block size is. .BI "The optional " start " and " end " arguments can be used to constrain the output to a particular range of disk blocks. .TP .BI "fuzz [\-c] [\-d] " "field action" Write garbage into a specific structure field on disk. Expert mode must be enabled to use this command. The operation happens immediately; there is no buffering. .IP The fuzz command can take the following .IR action "s" against a field: .RS 1.0i .TP 0.4i .B zeroes Clears all bits in the field. .TP 0.4i .B ones Sets all bits in the field. .TP 0.4i .B firstbit Flips the first bit in the field. For a scalar value, this is the highest bit. .TP 0.4i .B middlebit Flips the middle bit in the field. .TP 0.4i .B lastbit Flips the last bit in the field. For a scalar value, this is the lowest bit. .TP 0.4i .B add Adds a small value to a scalar field. .TP 0.4i .B sub Subtracts a small value from a scalar field. .TP 0.4i .B random Randomizes the contents of the field. .RE .IP The following switches affect the write behavior: .RS 1.0i .TP 0.4i .B \-c Skip write verifiers and CRC recalculation; allows invalid data to be written to disk. .TP 0.4i .B \-d Skip write verifiers but perform CRC recalculation; allows invalid data to be written to disk to test detection of invalid data. .RE .TP .BI hash " string Prints the hash value of .I string using the hash function of the XFS directory and attribute implementation. .TP .BI "help [" command ] Print help for one or all commands. .TP .B info Displays selected geometry information about the filesystem. The output will have the same format that .BR "mkfs.xfs" "(8)" prints when creating a filesystem or .BR "xfs_info" "(8)" prints when querying a filesystem. .TP .BI "inode [" inode# ] Set the current inode number. If no .I inode# is given, print the current inode number. .TP .BI "label [" label ] Set the filesystem label. The filesystem label can be used by .BR mount (8) instead of using a device special file. The maximum length of an XFS label is 12 characters \- use of a longer .I label will result in truncation and a warning will be issued. If no .I label is given, the current filesystem label is printed. .TP .BI "log [stop | start " filename ] Start logging output to .IR filename , stop logging, or print the current logging status. .TP .B logres Print transaction reservation size information for each transaction type. This makes it easier to find discrepancies in the reservation calculations between xfsprogs and the kernel, which will help when diagnosing minimum log size calculation errors. .TP .BI "metadump [\-egow] " filename Dumps metadata to a file. See .BR xfs_metadump (8) for more information. .TP .BI "ncheck [\-s] [\-i " ino "] ..." Print name-inode pairs. A .B blockget \-n command must be run first to gather the information. .RS 1.0i .TP 0.4i .B \-i specifies an inode number to be printed. If no .B \-i options are given then all inodes are printed. .TP .B \-s specifies that only setuid and setgid files are printed. .RE .TP .B p See the .B print command. .TP .B pop Pop location from the stack. .TP .BI "print [" field-expression "] ..." Print field values. If no argument is given, print all fields in the current structure. .TP .BI "push [" command ] Push location to the stack. If .I command is supplied, set the current location to the results of .I command after pushing the old location. .TP .B q See the .B quit command. .TP .B quit Exit .BR xfs_db . .TP .BI "ring [" index ] Show position ring (if no .I index argument is given), or move to a specific entry in the position ring given by .IR index . .TP .BI "sb [" agno ] Set current address to SB header in allocation group .IR agno . If no .I agno is given, use the current allocation group number. .TP .BI "source " source-file Process commands from .IR source-file . .B source commands can be nested. .TP .B stack View the location stack. .TP .BI "type [" type ] Set the current data type to .IR type . If no argument is given, show the current data type. The possible data types are: .BR agf ", " agfl ", " agi ", " attr ", " bmapbta ", " bmapbtd , .BR bnobt ", " cntbt ", " data ", " dir ", " dir2 ", " dqblk , .BR inobt ", " inode ", " log ", " refcntbt ", " rmapbt ", " rtbitmap , .BR rtsummary ", " sb ", " symlink " and " text . See the TYPES section below for more information on these data types. .TP .BI "uuid [" uuid " | " generate " | " rewrite " | " restore ] Set the filesystem universally unique identifier (UUID). The filesystem UUID can be used by .BR mount (8) instead of using a device special file. The .I uuid can be set directly to the desired UUID, or it can be automatically generated using the .B generate option. These options will both write the UUID into every copy of the superblock in the filesystem. On a CRC-enabled filesystem, this will set an incompatible superblock flag, and the filesystem will not be mountable with older kernels. This can be reverted with the .B restore option, which will copy the original UUID back into place and clear the incompatible flag as needed. .B rewrite copies the current UUID from the primary superblock to all secondary copies of the superblock. If no argument is given, the current filesystem UUID is printed. .TP .BI "version [" feature " | " "versionnum features2" ] Enable selected features for a filesystem (certain features can be enabled on an unmounted filesystem, after .BR mkfs.xfs (8) has created the filesystem). Support for unwritten extents can be enabled using the .B extflg option. Support for version 2 log format can be enabled using the .B log2 option. Support for extended attributes can be enabled using the .B attr1 or .B attr2 option. Once enabled, extended attributes cannot be disabled, but the user may toggle between .B attr1 and .B attr2 at will (older kernels may not support the newer version). .IP If no argument is given, the current version and feature bits are printed. With one argument, this command will write the updated version number into every copy of the superblock in the filesystem. If two arguments are given, they will be used as numeric values for the .I versionnum and .I features2 bits respectively, and their string equivalent reported (but no modifications are made). .TP .BI "write [\-c|\-d] [" "field value" "] ..." Write a value to disk. Specific fields can be set in structures (struct mode), or a block can be set to data values (data mode), or a block can be set to string values (string mode, for symlink blocks). The operation happens immediately: there is no buffering. .IP Struct mode is in effect when the current type is structural, i.e. not data. For struct mode, the syntax is "\c .B write .I field value\c ". .IP Data mode is in effect when the current type is data. In this case the contents of the block can be shifted or rotated left or right, or filled with a sequence, a constant value, or a random value. In this mode .B write with no arguments gives more information on the allowed commands. .RS 1.0i .TP 0.4i .B \-c Skip write verifiers and CRC recalculation; allows invalid data to be written to disk. .TP 0.4i .B \-d Skip write verifiers but perform CRC recalculation. This allows invalid data to be written to disk to test detection of invalid data. (This is not possible for some types.) .RE .SH TYPES This section gives the fields in each structure type and their meanings. Note that some types of block cover multiple actual structures, for instance directory blocks. .TP 1.0i .B agf The AGF block is the header for block allocation information; it is in the second 512-byte block of each allocation group. The following fields are defined: .RS 1.4i .PD 0 .TP 1.2i .B magicnum AGF block magic number, 0x58414746 ('XAGF'). .TP .B versionnum version number, currently 1. .TP .B seqno sequence number starting from 0. .TP .B length size in filesystem blocks of the allocation group. All allocation groups except the last one of the filesystem have the superblock's .B agblocks value here. .TP .B bnoroot block number of the root of the Btree holding free space information sorted by block number. .TP .B cntroot block number of the root of the Btree holding free space information sorted by block count. .TP .B bnolevel number of levels in the by-block-number Btree. .TP .B cntlevel number of levels in the by-block-count Btree. .TP .B flfirst index into the AGFL block of the first active entry. .TP .B fllast index into the AGFL block of the last active entry. .TP .B flcount count of active entries in the AGFL block. .TP .B freeblks count of blocks represented in the freespace Btrees. .TP .B longest longest free space represented in the freespace Btrees. .TP .B btreeblks number of blocks held in the AGF Btrees. .PD .RE .TP .B agfl The AGFL block contains block numbers for use of the block allocator; it is in the fourth 512-byte block of each allocation group. Each entry in the active list is a block number within the allocation group that can be used for any purpose if space runs low. The AGF block fields .BR flfirst ", " fllast ", and " flcount designate which entries are currently active. Entry space is allocated in a circular manner within the AGFL block. Fields defined: .RS 1.4i .PD 0 .TP 1.2i .B bno array of all block numbers. Even those which are not active are printed. .PD .RE .TP .B agi The AGI block is the header for inode allocation information; it is in the third 512-byte block of each allocation group. Fields defined: .RS 1.4i .PD 0 .TP 1.2i .B magicnum AGI block magic number, 0x58414749 ('XAGI'). .TP .B versionnum version number, currently 1. .TP .B seqno sequence number starting from 0. .TP .B length size in filesystem blocks of the allocation group. .TP .B count count of inodes allocated. .TP .B root block number of the root of the Btree holding inode allocation information. .TP .B level number of levels in the inode allocation Btree. .TP .B freecount count of allocated inodes that are not in use. .TP .B newino last inode number allocated. .TP .B dirino unused. .TP .B unlinked an array of inode numbers within the allocation group. The entries in the AGI block are the heads of lists which run through the inode .B next_unlinked field. These inodes are to be unlinked the next time the filesystem is mounted. .PD .RE .TP .B attr An attribute fork is organized as a Btree with the actual data embedded in the leaf blocks. The root of the Btree is found in block 0 of the fork. The index (sort order) of the Btree is the hash value of the attribute name. All the blocks contain a .B blkinfo structure at the beginning, see type .B dir for a description. Nonleaf blocks are identical in format to those for version 1 and version 2 directories, see type .B dir for a description. Leaf blocks can refer to "local" or "remote" attribute values. Local values are stored directly in the leaf block. Leaf blocks contain the following fields: .RS 1.4i .PD 0 .TP 1.2i .B hdr header containing a .B blkinfo structure .B info (magic number 0xfbee), a .B count of active entries, .B usedbytes total bytes of names and values, the .B firstused byte in the name area, .B holes set if the block needs compaction, and array .B freemap as for .B dir leaf blocks. .TP .B entries array of structures containing a .BR hashval , .B nameidx (index into the block of the name), and flags .BR incomplete , .BR root , and .BR local . .TP .B nvlist array of structures describing the attribute names and values. Fields always present: .B valuelen (length of value in bytes), .BR namelen , and .BR name . Fields present for local values: .B value (value string). Fields present for remote values: .B valueblk (fork block number of containing the value). .PD .RE .IP Remote values are stored in an independent block in the attribute fork. Prior to v5, value blocks had no structure, but in v5 they acquired a header structure with the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic attr3 remote block magic number, 0x5841524d ('XARM'). .TP .B offset Byte offset of this data block within the overall attribute value. .TP .B bytes Number of bytes stored in this block. .TP .B crc Checksum of the attribute block contents. .TP .B uuid Filesystem UUID. .TP .B owner Inode that owns this attribute value. .TP .B bno Block offset of this block within the inode's attribute fork. .TP .B lsn Log serial number of the last time this block was logged. .TP .B data The attribute value data. .PD .RE .TP .B bmapbt Files with many extents in their data or attribute fork will have the extents described by the contents of a Btree for that fork, instead of being stored directly in the inode. Each bmap Btree starts with a root block contained within the inode. The other levels of the Btree are stored in filesystem blocks. The blocks are linked to sibling left and right blocks at each level, as well as by pointers from parent to child blocks. Each block contains the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic bmap Btree block magic number, 0x424d4150 ('BMAP'). .TP .B level level of this block above the leaf level. .TP .B numrecs number of records or keys in the block. .TP .B leftsib left (logically lower) sibling block, 0 if none. .TP .B rightsib right (logically higher) sibling block, 0 if none. .TP .B recs [leaf blocks only] array of extent records. Each record contains .BR startoff , .BR startblock , .BR blockcount , and .B extentflag (1 if the extent is unwritten). .TP .B keys [non-leaf blocks only] array of key records. These are the first key value of each block in the level below this one. Each record contains .BR startoff . .TP .B ptrs [non-leaf blocks only] array of child block pointers. Each pointer is a filesystem block number to the next level in the Btree. .PD .RE .TP .B bnobt There is one set of filesystem blocks forming the by-block-number allocation Btree for each allocation group. The root block of this Btree is designated by the .B bnoroot field in the corresponding AGF block. The blocks are linked to sibling left and right blocks at each level, as well as by pointers from parent to child blocks. Each block has the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic BNOBT block magic number, 0x41425442 ('ABTB'). .TP .B level level number of this block, 0 is a leaf. .TP .B numrecs number of data entries in the block. .TP .B leftsib left (logically lower) sibling block, 0 if none. .TP .B rightsib right (logically higher) sibling block, 0 if none. .TP .B recs [leaf blocks only] array of freespace records. Each record contains .B startblock and .BR blockcount . .TP .B keys [non-leaf blocks only] array of key records. These are the first value of each block in the level below this one. Each record contains .B startblock and .BR blockcount . .TP .B ptrs [non-leaf blocks only] array of child block pointers. Each pointer is a block number within the allocation group to the next level in the Btree. .PD .RE .TP .B cntbt There is one set of filesystem blocks forming the by-block-count allocation Btree for each allocation group. The root block of this Btree is designated by the .B cntroot field in the corresponding AGF block. The blocks are linked to sibling left and right blocks at each level, as well as by pointers from parent to child blocks. Each block has the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic CNTBT block magic number, 0x41425443 ('ABTC'). .TP .B level level number of this block, 0 is a leaf. .TP .B numrecs number of data entries in the block. .TP .B leftsib left (logically lower) sibling block, 0 if none. .TP .B rightsib right (logically higher) sibling block, 0 if none. .TP .B recs [leaf blocks only] array of freespace records. Each record contains .B startblock and .BR blockcount . .TP .B keys [non-leaf blocks only] array of key records. These are the first value of each block in the level below this one. Each record contains .B blockcount and .BR startblock . .TP .B ptrs [non-leaf blocks only] array of child block pointers. Each pointer is a block number within the allocation group to the next level in the Btree. .PD .RE .TP .B data User file blocks, and other blocks whose type is unknown, have this type for display purposes in .BR xfs_db . The block data is displayed in hexadecimal format. .TP .B dir A version 1 directory is organized as a Btree with the directory data embedded in the leaf blocks. The root of the Btree is found in block 0 of the file. The index (sort order) of the Btree is the hash value of the entry name. All the blocks contain a .B blkinfo structure at the beginning with the following fields: .RS 1.4i .PD 0 .TP 1.2i .B forw next sibling block. .TP .B back previous sibling block. .TP .B magic magic number for this block type. .RE .IP The non-leaf (node) blocks have the following fields: .RS 1.4i .TP 1.2i .B hdr header containing a .B blkinfo structure .B info (magic number 0xfebe), the .B count of active entries, and the .B level of this block above the leaves. .TP .B btree array of entries containing .B hashval and .B before fields. The .B before value is a block number within the directory file to the child block, the .B hashval is the last hash value in that block. .RE .IP The leaf blocks have the following fields: .RS 1.4i .TP 1.2i .B hdr header containing a .B blkinfo structure .B info (magic number 0xfeeb), the .B count of active entries, .B namebytes (total name string bytes), .B holes flag (block needs compaction), and .B freemap (array of .BR base ", " size entries for free regions). .TP .B entries array of structures containing .BR hashval , .B nameidx (byte index into the block of the name string), and .BR namelen . .TP .B namelist array of structures containing .B inumber and .BR name . .RE .PD .TP .B dir2 A version 2 directory has four kinds of blocks. Data blocks start at offset 0 in the file. There are two kinds of data blocks: single-block directories have the leaf information embedded at the end of the block, data blocks in multi-block directories do not. Node and leaf blocks start at offset 32GiB (with either a single leaf block or the root node block). Freespace blocks start at offset 64GiB. The node and leaf blocks form a Btree, with references to the data in the data blocks. The freespace blocks form an index of longest free spaces within the data blocks. .IP A single-block directory block contains the following fields: .RS 1.4i .PD 0 .TP 1.2i .B bhdr header containing .B magic number 0x58443242 ('XD2B') and an array .B bestfree of the longest 3 free spaces in the block .RB ( offset ", " length ). .TP .B bu array of union structures. Each element is either an entry or a freespace. For entries, there are the following fields: .BR inumber , .BR namelen , .BR name , and .BR tag . For freespace, there are the following fields: .B freetag (0xffff), .BR length , and .BR tag . The .B tag value is the byte offset in the block of the start of the entry it is contained in. .TP .B bleaf array of leaf entries containing .B hashval and .BR address . The .B address is a 64-bit word offset into the file. .TP .B btail tail structure containing the total .B count of leaf entries and .B stale count of unused leaf entries. .RE .IP A data block contains the following fields: .RS 1.4i .TP 1.2i .B dhdr header containing .B magic number 0x58443244 ('XD2D') and an array .B bestfree of the longest 3 free spaces in the block .RB ( offset ", " length ). .TP .B du array of union structures as for .BR bu . .RE .IP Leaf blocks have two possible forms. If the Btree consists of a single leaf then the freespace information is in the leaf block, otherwise it is in separate blocks and the root of the Btree is a node block. A leaf block contains the following fields: .RS 1.4i .TP 1.2i .B lhdr header containing a .B blkinfo structure .B info (magic number 0xd2f1 for the single leaf case, 0xd2ff for the true Btree case), the total .B count of leaf entries, and .B stale count of unused leaf entries. .TP .B lents leaf entries, as for .BR bleaf . .TP .B lbests [single leaf only] array of values which represent the longest freespace in each data block in the directory. .TP .B ltail [single leaf only] tail structure containing .B bestcount count of .BR lbests . .RE .IP A node block is identical to that for types .B attr and .BR dir . A freespace block contains the following fields: .RS 1.4i .TP 1.2i .B fhdr header containing .B magic number 0x58443246 ('XD2F'), .B firstdb first data block number covered by this freespace block, .B nvalid number of valid entries, and .B nused number of entries representing real data blocks. .TP .B fbests array of values as for .BR lbests . .PD .RE .TP .B dqblk The quota information is stored in files referred to by the superblock .B uquotino and .B pquotino fields. Each filesystem block in a quota file contains a constant number of quota entries. The quota entry size is currently 136 bytes, so with a 4KiB filesystem block size there are 30 quota entries per block. The .B dquot command is used to locate these entries in the filesystem. The file entries are indexed by the user or project identifier to determine the block and offset. Each quota entry has the following fields: .RS 1.4i .PD 0 .TP 1.5i .B magic magic number, 0x4451 ('DQ'). .TP .B version version number, currently 1. .TP .B flags flags, values include 0x01 for user quota, 0x02 for project quota. .TP .B id user or project identifier. .TP .B blk_hardlimit absolute limit on blocks in use. .TP .B blk_softlimit preferred limit on blocks in use. .TP .B ino_hardlimit absolute limit on inodes in use. .TP .B ino_softlimit preferred limit on inodes in use. .TP .B bcount blocks actually in use. .TP .B icount inodes actually in use. .TP .B itimer time when service will be refused if soft limit is violated for inodes. .TP .B btimer time when service will be refused if soft limit is violated for blocks. .TP .B iwarns number of warnings issued about inode limit violations. .TP .B bwarns number of warnings issued about block limit violations. .TP .B rtb_hardlimit absolute limit on realtime blocks in use. .TP .B rtb_softlimit preferred limit on realtime blocks in use. .TP .B rtbcount realtime blocks actually in use. .TP .B rtbtimer time when service will be refused if soft limit is violated for realtime blocks. .TP .B rtbwarns number of warnings issued about realtime block limit violations. .PD .RE .TP .B inobt There is one set of filesystem blocks forming the inode allocation Btree for each allocation group. The root block of this Btree is designated by the .B root field in the corresponding AGI block. The blocks are linked to sibling left and right blocks at each level, as well as by pointers from parent to child blocks. Each block has the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic INOBT block magic number, 0x49414254 ('IABT'). .TP .B level level number of this block, 0 is a leaf. .TP .B numrecs number of data entries in the block. .TP .B leftsib left (logically lower) sibling block, 0 if none. .TP .B rightsib right (logically higher) sibling block, 0 if none. .TP .B recs [leaf blocks only] array of inode records. Each record contains .B startino allocation-group relative inode number, .B freecount count of free inodes in this chunk, and .B free bitmap, LSB corresponds to inode 0. .TP .B keys [non-leaf blocks only] array of key records. These are the first value of each block in the level below this one. Each record contains .BR startino . .TP .B ptrs [non-leaf blocks only] array of child block pointers. Each pointer is a block number within the allocation group to the next level in the Btree. .PD .RE .TP .B inode Inodes are allocated in "chunks" of 64 inodes each. Usually a chunk is multiple filesystem blocks, although there are cases with large filesystem blocks where a chunk is less than one block. The inode Btree (see .B inobt above) refers to the inode numbers per allocation group. The inode numbers directly reflect the location of the inode block on disk. Use the .B inode command to point .B xfs_db to a specific inode. Each inode contains four regions: .BR core , .BR next_unlinked , .BR u ", and " .BR a . .B core contains the fixed information. .B next_unlinked is separated from the core due to journaling considerations, see type .B agi field .BR unlinked . .B u is a union structure that is different in size and format depending on the type and representation of the file data ("data fork"). .B a is an optional union structure to describe attribute data, that is different in size, format, and location depending on the presence and representation of attribute data, and the size of the .B u data ("attribute fork"). .B xfs_db automatically selects the proper union members based on information in the inode. .IP The following are fields in the inode core: .RS 1.4i .PD 0 .TP 1.2i .B magic inode magic number, 0x494e ('IN'). .TP .B mode mode and type of file, as described in .BR chmod (2), .BR mknod (2), and .BR stat (2). .TP .B version inode version, 1 or 2. .TP .B format format of .B u union data (0: xfs_dev_t, 1: local file \- in-inode directory or symlink, 2: extent list, 3: Btree root, 4: unique id [unused]). .TP .B nlinkv1 number of links to the file in a version 1 inode. .TP .B nlinkv2 number of links to the file in a version 2 inode. .TP .B projid_lo owner's project id (low word; version 2 inode only). .B projid_hi owner's project id (high word; version 2 inode only). .TP .B uid owner's user id. .TP .B gid owner's group id. .TP .B atime time last accessed (seconds and nanoseconds). .TP .B mtime time last modified. .TP .B ctime time created or inode last modified. .TP .B size number of bytes in the file. .TP .B nblocks total number of blocks in the file including indirect and attribute. .TP .B extsize basic/minimum extent size for the file. .TP .B nextents number of extents in the data fork. .TP .B naextents number of extents in the attribute fork. .TP .B forkoff attribute fork offset in the inode, in 64-bit words from the start of .BR u . .TP .B aformat format of .B a data (1: local attribute data, 2: extent list, 3: Btree root). .TP .B dmevmask DMAPI event mask. .TP .B dmstate DMAPI state information. .TP .B newrtbm file is the realtime bitmap and is "new" format. .TP .B prealloc file has preallocated data space after EOF. .TP .B realtime file data is in the realtime subvolume. .TP .B gen inode generation number. .RE .IP The following fields are in the .B u data fork union: .RS 1.4i .TP 1.2i .B bmbt bmap Btree root. This looks like a .B bmapbtd block with redundant information removed. .TP .B bmx array of extent descriptors. .TP .B dev dev_t for the block or character device. .TP .B sfdir shortform (in-inode) version 1 directory. This consists of a .B hdr containing the .B parent inode number and a .B count of active entries in the directory, followed by an array .B list of .B hdr.count entries. Each such entry contains .BR inumber , .BR namelen , and .B name string. .TP .B sfdir2 shortform (in-inode) version 2 directory. This consists of a .B hdr containing a .B count of active entries in the directory, an .B i8count of entries with inumbers that don't fit in a 32-bit value, and the .B parent inode number, followed by an array .B list of .B hdr.count entries. Each such entry contains .BR namelen , a saved .B offset used when the directory is converted to a larger form, a .B name string, and the .BR inumber . .TP .B symlink symbolic link string value. .RE .IP The following fields are in the .B a attribute fork union if it exists: .RS 1.4i .TP 1.2i .B bmbt bmap Btree root, as above. .TP .B bmx array of extent descriptors. .TP .B sfattr shortform (in-inode) attribute values. This consists of a .B hdr containing a .B totsize (total size in bytes) and a .B count of active entries, followed by an array .B list of .B hdr.count entries. Each such entry contains .BR namelen , .BR valuelen , .BR root flag, .BR name , and .BR value . .PD .RE .TP .B log Log blocks contain the journal entries for XFS. It's not useful to examine these with .BR xfs_db , use .BR xfs_logprint (8) instead. .TP .B refcntbt There is one set of filesystem blocks forming the reference count Btree for each allocation group. The root block of this Btree is designated by the .B refcntroot field in the corresponding AGF block. The blocks are linked to sibling left and right blocks at each level, as well as by pointers from parent to child blocks. Each block has the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic REFC block magic number, 0x52334643 ('R3FC'). .TP .B level level number of this block, 0 is a leaf. .TP .B numrecs number of data entries in the block. .TP .B leftsib left (logically lower) sibling block, 0 if none. .TP .B rightsib right (logically higher) sibling block, 0 if none. .TP .B recs [leaf blocks only] array of reference count records. Each record contains .BR startblock , .BR blockcount , and .BR refcount . .TP .B keys [non-leaf blocks only] array of key records. These are the first value of each block in the level below this one. Each record contains .BR startblock . .TP .B ptrs [non-leaf blocks only] array of child block pointers. Each pointer is a block number within the allocation group to the next level in the Btree. .PD .RE .TP .B rmapbt There is one set of filesystem blocks forming the reverse mapping Btree for each allocation group. The root block of this Btree is designated by the .B rmaproot field in the corresponding AGF block. The blocks are linked to sibling left and right blocks at each level, as well as by pointers from parent to child blocks. Each block has the following fields: .RS 1.4i .PD 0 .TP 1.2i .B magic RMAP block magic number, 0x524d4233 ('RMB3'). .TP .B level level number of this block, 0 is a leaf. .TP .B numrecs number of data entries in the block. .TP .B leftsib left (logically lower) sibling block, 0 if none. .TP .B rightsib right (logically higher) sibling block, 0 if none. .TP .B recs [leaf blocks only] array of reference count records. Each record contains .BR startblock , .BR blockcount , .BR owner , .BR offset , .BR attr_fork , .BR bmbt_block , and .BR unwritten . .TP .B keys [non-leaf blocks only] array of double-key records. The first ("low") key contains the first value of each block in the level below this one. The second ("high") key contains the largest key that can be used to identify any record in the subtree. Each record contains .BR startblock , .BR owner , .BR offset , .BR attr_fork , and .BR bmbt_block . .TP .B ptrs [non-leaf blocks only] array of child block pointers. Each pointer is a block number within the allocation group to the next level in the Btree. .PD .RE .TP .B rtbitmap If the filesystem has a realtime subvolume, then the .B rbmino field in the superblock refers to a file that contains the realtime bitmap. Each bit in the bitmap file controls the allocation of a single realtime extent (set == free). The bitmap is processed in 32-bit words, the LSB of a word is used for the first extent controlled by that bitmap word. The .B atime field of the realtime bitmap inode contains a counter that is used to control where the next new realtime file will start. .TP .B rtsummary If the filesystem has a realtime subvolume, then the .B rsumino field in the superblock refers to a file that contains the realtime summary data. The summary file contains a two-dimensional array of 16-bit values. Each value counts the number of free extent runs (consecutive free realtime extents) of a given range of sizes that starts in a given bitmap block. The size ranges are binary buckets (low size in the bucket is a power of 2). There are as many size ranges as are necessary given the size of the realtime subvolume. The first dimension is the size range, the second dimension is the starting bitmap block number (adjacent entries are for the same size, adjacent bitmap blocks). .TP .B sb There is one sb (superblock) structure per allocation group. It is the first disk block in the allocation group. Only the first one (block 0 of the filesystem) is actually used; the other blocks are redundant information for .BR xfs_repair (8) to use if the first superblock is damaged. Fields defined: .RS 1.4i .PD 0 .TP 1.2i .B magicnum superblock magic number, 0x58465342 ('XFSB'). .TP .B blocksize filesystem block size in bytes. .TP .B dblocks number of filesystem blocks present in the data subvolume. .TP .B rblocks number of filesystem blocks present in the realtime subvolume. .TP .B rextents number of realtime extents that .B rblocks contain. .TP .B uuid unique identifier of the filesystem. .TP .B logstart starting filesystem block number of the log (journal). If this value is 0 the log is "external". .TP .B rootino root inode number. .TP .B rbmino realtime bitmap inode number. .TP .B rsumino realtime summary data inode number. .TP .B rextsize realtime extent size in filesystem blocks. .TP .B agblocks size of an allocation group in filesystem blocks. .TP .B agcount number of allocation groups. .TP .B rbmblocks number of realtime bitmap blocks. .TP .B logblocks number of log blocks (filesystem blocks). .TP .B versionnum filesystem version information. This value is currently 1, 2, 3, or 4 in the low 4 bits. If the low bits are 4 then the other bits have additional meanings. 1 is the original value. 2 means that attributes were used. 3 means that version 2 inodes (large link counts) were used. 4 is the bitmask version of the version number. In this case, the other bits are used as flags (0x0010: attributes were used, 0x0020: version 2 inodes were used, 0x0040: quotas were used, 0x0080: inode cluster alignment is in force, 0x0100: data stripe alignment is in force, 0x0200: the .B shared_vn field is used, 0x1000: unwritten extent tracking is on, 0x2000: version 2 directories are in use). .TP .B sectsize sector size in bytes, currently always 512. This is the size of the superblock and the other header blocks. .TP .B inodesize inode size in bytes. .TP .B inopblock number of inodes per filesystem block. .TP .B fname obsolete, filesystem name. .TP .B fpack obsolete, filesystem pack name. .TP .B blocklog log2 of .BR blocksize . .TP .B sectlog log2 of .BR sectsize . .TP .B inodelog log2 of .BR inodesize . .TP .B inopblog log2 of .BR inopblock . .TP .B agblklog log2 of .B agblocks (rounded up). .TP .B rextslog log2 of .BR rextents . .TP .B inprogress .BR mkfs.xfs (8) or .BR xfs_copy (8) aborted before completing this filesystem. .TP .B imax_pct maximum percentage of filesystem space used for inode blocks. .TP .B icount number of allocated inodes. .TP .B ifree number of allocated inodes that are not in use. .TP .B fdblocks number of free data blocks. .TP .B frextents number of free realtime extents. .TP .B uquotino user quota inode number. .TP .B pquotino project quota inode number; this is currently unused. .TP .B qflags quota status flags (0x01: user quota accounting is on, 0x02: user quota limits are enforced, 0x04: quotacheck has been run on user quotas, 0x08: project quota accounting is on, 0x10: project quota limits are enforced, 0x20: quotacheck has been run on project quotas). .TP .B flags random flags. 0x01: only read-only mounts are allowed. .TP .B shared_vn shared version number (shared readonly filesystems). .TP .B inoalignmt inode chunk alignment in filesystem blocks. .TP .B unit stripe or RAID unit. .TP .B width stripe or RAID width. .TP .B dirblklog log2 of directory block size (filesystem blocks). .PD .RE .TP .B symlink Symbolic link blocks are used only when the symbolic link value does not fit inside the inode. The block content is just the string value. Bytes past the logical end of the symbolic link value have arbitrary values. .TP .B text User file blocks, and other blocks whose type is unknown, have this type for display purposes in .BR xfs_db . The block data is displayed in two columns: Hexadecimal format and printable ASCII chars. .SH DIAGNOSTICS Many messages can come from the .B check .RB ( blockget ) command. If the filesystem is completely corrupt, a core dump might be produced instead of the message .RS .I device .B is not a valid filesystem .RE .PP If the filesystem is very large (has many files) then .B check might run out of memory. In this case the message .RS .B out of memory .RE is printed. .PP The following is a description of the most likely problems and the associated messages. Most of the diagnostics produced are only meaningful with an understanding of the structure of the filesystem. .TP .BI "agf_freeblks " n ", counted " m " in ag " a The freeblocks count in the allocation group header for allocation group .I a doesn't match the number of blocks counted free. .TP .BI "agf_longest " n ", counted " m " in ag " a The longest free extent in the allocation group header for allocation group .I a doesn't match the longest free extent found in the allocation group. .TP .BI "agi_count " n ", counted " m " in ag " a The allocated inode count in the allocation group header for allocation group .I a doesn't match the number of inodes counted in the allocation group. .TP .BI "agi_freecount " n ", counted " m " in ag " a The free inode count in the allocation group header for allocation group .I a doesn't match the number of inodes counted free in the allocation group. .TP .BI "block " a/b " expected inum 0 got " i The block number is specified as a pair (allocation group number, block in the allocation group). The block is used multiple times (shared), between multiple inodes. This message usually follows a message of the next type. .TP .BI "block " a/b " expected type unknown got " y The block is used multiple times (shared). .TP .BI "block " a/b " type unknown not expected .SH SEE ALSO .BR mkfs.xfs (8), .BR xfs_admin (8), .BR xfs_copy (8), .BR xfs_logprint (8), .BR xfs_metadump (8), .BR xfs_ncheck (8), .BR xfs_repair (8), .BR mount (8), .BR chmod (2), .BR mknod (2), .BR stat (2), .BR xfs (5). xfsprogs-5.3.0/man/man8/xfs_estimate.80000644000175000017500000000430113034246041017441 0ustar nathansnathans.TH xfs_estimate 8 .SH NAME xfs_estimate \- estimate the space that an XFS filesystem will take .SH SYNOPSIS .nf \f3xfs_estimate\f1 [ \f3\-h\f1 ] [ \f3\-b\f1 blocksize ] [ \f3\-i\f1 logsize ] [ \f3\-e\f1 logsize ] [ \f3\-v\f1 ] directory ... .br .B xfs_estimate \-V .fi .SH DESCRIPTION For each \f2directory\f1 argument, .I xfs_estimate estimates the space that directory would take if it were copied to an XFS filesystem. .I xfs_estimate does not cross mount points. The following definitions are used: .PD 0 .IP KB = *1024 .IP MB = *1024*1024 .IP GB = *1024*1024*1024 .PD .PP The .I xfs_estimate options are: .TP \f3\-b\f1 \f2blocksize\f1 Use .I blocksize instead of the default blocksize of 4096 bytes. The modifier .B k can be used after the number to indicate multiplication by 1024. For example, .sp .8v .RS \f4xfs_estimate \-b 64k /\f1 .RE .IP requests an estimate of the space required by the directory / on an XFS filesystem using a blocksize of 64K (65536) bytes. .TP .B \-v Display more information, formatted. .TP .B \-h Display usage message. .TP \f3\-i, \-e\f1 \f2logsize\f1 Use .I logsize instead of the default log size of 1000 blocks. .B \-i refers to an internal log, while .B \-e refers to an external log. The modifiers .B k or .B m can be used after the number to indicate multiplication by 1024 or 1048576, respectively. .IP For example, .sp .8v .RS \f4xfs_estimate \-i 1m /\f1 .RE .IP requests an estimate of the space required by the directory / on an XFS filesystem using an internal log of 1 megabyte. .TP .B \-V Print the version number and exits. .SH EXAMPLES .nf .sp 8v % \f4xfs_estimate \-e 10m /var/tmp\f1\f7 /var/tmp will take about 4.2 megabytes with the external log using 2560 blocks or about 10.0 megabytes .fi .nf .sp .8v % \f4xfs_estimate \-v \-e 10m /var/tmp\f1\f7 directory bsize blocks megabytes logsize /var/tmp 4096 792 4.0MB 10485760 .fi .nf .sp .8v % \f4xfs_estimate \-v /var/tmp\f1\f7 directory bsize blocks megabytes logsize /var/tmp 4096 3352 14.0MB 10485760 .fi .nf .sp .8v % \f4xfs_estimate /var/tmp\f1\f7 /var/tmp will take about 14.0 megabytes .fi xfsprogs-5.3.0/man/man8/xfs_freeze.80000644000175000017500000000415613034246041017116 0ustar nathansnathans.TH xfs_freeze 8 .SH NAME xfs_freeze \- suspend access to an XFS filesystem .SH SYNOPSIS .B xfs_freeze [ .B \-f | .B \-u ] .I mount-point .br .B xfs_freeze \-V .fi .SH DESCRIPTION .B xfs_freeze suspends and resumes access to an XFS filesystem (see .BR xfs (5)). .PP .B xfs_freeze halts new access to the filesystem and creates a stable image on disk. .B xfs_freeze is intended to be used with volume managers and hardware RAID devices that support the creation of snapshots. .PP The .I mount-point argument is the pathname of the directory where the filesystem is mounted. The filesystem must be mounted to be frozen (see .BR mount (8)). .PP .PP The .B \-f flag requests the specified XFS filesystem to be frozen from new modifications. When this is selected, all ongoing transactions in the filesystem are allowed to complete, new write system calls are halted, other calls which modify the filesystem are halted, and all dirty data, metadata, and log information are written to disk. Any process attempting to write to the frozen filesystem will block waiting for the filesystem to be unfrozen. .PP Note that even after freezing, the on-disk filesystem can contain information on files that are still in the process of unlinking. These files will not be unlinked until the filesystem is unfrozen or a clean mount of the snapshot is complete. .PP The .B \-u flag is used to un-freeze the filesystem and allow operations to continue. Any filesystem modifications that were blocked by the freeze are unblocked and allowed to complete. .PP The .B \-V flag prints the version number and exits. .PP Unless .B \-V is specified, one of .B \-f or .B \-u must be supplied to .BR xfs_freeze . .SH NOTES A copy of a frozen XFS filesystem will usually have the same universally unique identifier (UUID) as the original, and thus may be prevented from being mounted. The XFS .B nouuid mount option can be used to circumvent this issue. .PP In Linux kernel version 2.6.29, the interface which XFS uses to freeze and unfreeze was elevated to the VFS, so that this tool can now be used on many other Linux filesystems. .SH SEE ALSO .BR xfs (5), .BR lvm (8), .BR mount (8). xfsprogs-5.3.0/man/man8/xfs_fsr.80000644000175000017500000001210013034246041016414 0ustar nathansnathans.TH xfs_fsr 8 .SH NAME xfs_fsr \- filesystem reorganizer for XFS .SH SYNOPSIS .nf \f3xfs_fsr\f1 [\f3\-vdg\f1] \c [\f3\-t\f1 seconds] [\f3\-p\f1 passes] [\f3\-f\f1 leftoff] [\f3\-m\f1 mtab] \f3xfs_fsr\f1 [\f3\-vdg\f1] \c [xfsdev | file] ... .br .B xfs_fsr \-V .fi .SH DESCRIPTION .I xfs_fsr is applicable only to XFS filesystems. .PP .I xfs_fsr improves the organization of mounted filesystems. The reorganization algorithm operates on one file at a time, compacting or otherwise improving the layout of the file extents (contiguous blocks of file data). .PP The following options are accepted by .IR xfs_fsr . The .BR \-m , .BR \-t , and .B \-f options have no meaning if any filesystems or files are specified on the command line. .TP 13 .BI \-m " mtab" Use this file for the list of filesystems to reorganize. The default is to use .IR /etc/mtab . .TP .BI \-t " seconds" How long to reorganize. The default is 7200 seconds (2 hours). .TP .BI \-p " passes" Number of passes before terminating global re-org. The default is 10 passes. .TP .BI \-f " leftoff" Use this file instead of .I /var/tmp/.fsrlast to read the state of where to start and as the file to store the state of where reorganization left off. .TP .B \-v Verbose. Print cryptic information about each file being reorganized. .TP .B \-d Debug. Print even more cryptic information. .TP .B \-g Print to syslog (default if stdout not a tty). .TP .B \-V Prints the version number and exits. .PP When invoked with no arguments .I xfs_fsr reorganizes all regular files in all mounted filesystems. .I xfs_fsr makes many cycles over .I /etc/mtab each time making a single pass over each XFS filesystem. Each pass goes through and selects files that have the largest number of extents. It attempts to defragment the top 10% of these files on each pass. .PP It runs for up to two hours after which it records the filesystem where it left off, so it can start there the next time. This information is stored in the file .I /var/tmp/.fsrlast_xfs. If the information found here is somehow inconsistent or out of date it is ignored and reorganization starts at the beginning of the first filesystem found in .IR /etc/mtab . .PP .I xfs_fsr can be called with one or more arguments naming filesystems (block device name), and files to reorganize. In this mode .I xfs_fsr does not read or write .I /var/tmp/.fsrlast_xfs nor does it run for a fixed time interval. It makes one pass through each specified regular file and all regular files in each specified filesystem. A command line name referring to a symbolic link (except to a file system device), FIFO, or UNIX domain socket generates a warning message, but is otherwise ignored. While traversing the filesystem these types of files are silently skipped. .SH FILES .PD 0 .TP 21 /etc/mtab contains default list of filesystems to reorganize. .TP 21 /var/tmp/.fsrlast_xfs records the state where reorganization left off. .PD .SH "SEE ALSO" xfs_fsr(8), mkfs.xfs(8), xfs_ncheck(8), xfs(5). .SH "NOTES" .I xfs_fsr improves the layout of extents for each file by copying the entire file to a temporary location and then interchanging the data extents of the target and temporary files in an atomic manner. This method requires that enough free disk space be available to copy any given file and that the space be less fragmented than the original file. It also requires the owner of the file to have enough remaining filespace quota to do the copy on systems running quotas. .I xfs_fsr generates a warning message if space is not sufficient to improve the target file. .PP A temporary file used in improving a file given on the command line is created in the same parent directory of the target file and is prefixed by the string '\f3.fsr\f1'. The temporary files used in improving an entire XFS device are stored in a directory at the root of the target device and use the same naming scheme. The temporary files are unlinked upon creation so data will not be readable by any other process. .PP .I xfs_fsr does not operate on files that are currently mapped in memory. A 'file busy' error can be seen for these files if the verbose flag (\f3-v\f1) is set. .PP Files marked as no\-defrag will be skipped. The .IR xfs_io (8) chattr command with the f attribute can be used to set or clear this flag. Files and directories created in a directory with the no\-defrag flag will inherit the attribute. .PP An entry in .I /etc/mtab or the file specified using the .B \-m option must have the .B rw option specified for read and write access. If this option is not present, then .I xfs_fsr skips the filesystem described by that line. See the .IR fstab (5) reference page for more details. .PP In general we do not foresee the need to run .I xfs_fsr on system partitions such as .IR / , .I /boot and .I /usr as in general these will not suffer from fragmentation. There are also issues with defragmenting files .IR lilo (8) uses to boot your system. It is recommended that these files should be flagged as no\-defrag with the .IR xfs_io (8) chattr command. Should these files be moved by .I xfs_fsr then you must rerun .I lilo before you reboot or you may have an unbootable system. xfsprogs-5.3.0/man/man8/xfs_growfs.80000644000175000017500000000737313570057155017164 0ustar nathansnathans.\" Verbatim blocks taken from openssl req manpage content .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .TH xfs_growfs 8 .SH NAME xfs_growfs \- expand an XFS filesystem .SH SYNOPSIS .B xfs_growfs [ .B \-dilnrx ] [ .B \-D .I size ] [ .B \-e .I rtextsize ] [ .B \-L .I size ] [ .B \-m .I maxpct ] [ .B \-t .I mtab ] [ .B \-R .I size ] [ .I mount-point | .I block-device ] .br .B xfs_growfs \-V .SH DESCRIPTION .B xfs_growfs expands an existing XFS filesystem (see .BR xfs (5)). The .I mount-point argument is the pathname of the directory where the filesystem is mounted. The .I block-device argument is the device name of a mounted XFS filesystem. The filesystem must be mounted to be grown (see .BR mount (8)). The existing contents of the filesystem are undisturbed, and the added space becomes available for additional file storage. .SH OPTIONS .TP .BI "\-d | \-D " size Specifies that the data section of the filesystem should be grown. If the .B \-D .I size option is given, the data section is grown to that .IR size , otherwise the data section is grown to the largest size possible with the .B \-d option. The size is expressed in filesystem blocks. .TP .B \-e Allows the real-time extent size to be specified. In .BR mkfs.xfs (8) this is specified with .B \-r extsize=\c .IR nnnn . .TP .B \-i The new log is an internal log (inside the data section). .B [NOTE: This option is not implemented] .TP .BI "\-l | \-L " size Specifies that the log section of the filesystem should be grown, shrunk, or moved. If the .B \-L .I size option is given, the log section is changed to be that .IR size , if possible. The size is expressed in filesystem blocks. The size of an internal log must be smaller than the size of an allocation group (this value is printed at .BR mkfs (8) time). If neither .B \-i nor .B \-x is given with .BR \-l , the log continues to be internal or external as it was before. .B [NOTE: These options are not implemented] .TP .B \-m Specify a new value for the maximum percentage of space in the filesystem that can be allocated as inodes. In .BR mkfs.xfs (8) this is specified with .B -i maxpct=\c .IR nn . .TP .B \-n Specifies that no change to the filesystem is to be made. The filesystem geometry is printed, and argument checking is performed, but no growth occurs. .B See output examples below. .TP .BI "\-r | \-R " size Specifies that the real-time section of the filesystem should be grown. If the .B \-R .I size option is given, the real-time section is grown to that size, otherwise the real-time section is grown to the largest size possible with the .B \-r option. The size is expressed in filesystem blocks. The filesystem does not need to have contained a real-time section before the .B xfs_growfs operation. .TP .B \-t Specifies an alternate mount table file (default is .I /proc/mounts if it exists, else .IR /etc/mtab ). This is used when working with filesystems mounted without writing to .I /etc/mtab file - refer to .BR mount (8) for further details. .TP .B \-V Prints the version number and exits. The .I mount-point argument is not required with .BR \-V . .PP .B xfs_growfs is most often used in conjunction with logical volumes (see .BR md (4) and .BR lvm (8) on Linux). However, it can also be used on a regular disk partition, for example if a partition has been enlarged while retaining the same starting block. .SH PRACTICAL USE Filesystems normally occupy all of the space on the device where they reside. In order to grow a filesystem, it is necessary to provide added space for it to occupy. Therefore there must be at least one spare new disk partition available. Adding the space is often done through the use of a logical volume manager. .SH SEE ALSO .BR mkfs.xfs (8), .BR xfs_info (8), .BR md (4), .BR lvm (8), .BR mount (8). xfsprogs-5.3.0/man/man8/xfs_info.80000644000175000017500000000455713435336037016610 0ustar nathansnathans.\" Verbatim blocks taken from openssl req manpage content .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .TH xfs_info 8 .SH NAME xfs_info \- display XFS filesystem geometry information .SH SYNOPSIS .B xfs_info [ .B \-t .I mtab ] [ .I mount-point | .I block-device | .I file-image ] .br .B xfs_info \-V .SH DESCRIPTION .B xfs_info displays geometry information about an existing XFS filesystem. The .I mount-point argument is the pathname of a directory where the filesystem is mounted. The .I block-device or .I file-image contain a raw XFS filesystem. The existing contents of the filesystem are undisturbed. .SH OPTIONS .TP .B \-t Specifies an alternate mount table file (default is .I /proc/mounts if it exists, else .IR /etc/mtab ). This is used when working with filesystems mounted without writing to .I /etc/mtab file - refer to .BR mount (8) for further details. This option has no effect with the .IR block-device " or " file-image parameters. .TP .B \-V Prints the version number and exits. The .I mount-point argument is not required with .BR \-V . .SH "EXAMPLES" Understanding xfs_info output. .PP Suppose one has the following "xfs_info /dev/sda" output: .PP .RS 2 .Vb \&meta-data=/dev/pmem0 isize=512 agcount=8, agsize=5974144 blks \& = sectsz=512 attr=2, projid32bit=1 \& = crc=1 finobt=1, sparse=1, rmapbt=1 \& = reflink=1 \&data = bsize=4096 blocks=47793152, imaxpct=25 \& = sunit=32 swidth=128 blks \&naming =version 2 bsize=4096 ascii-ci=0, ftype=1 \&log =internal log bsize=4096 blocks=23336, version=2 \& = sectsz=512 sunit=0 blks, lazy-count=1 \&realtime =none extsz=4096 blocks=0, rtextents=0 .Ve .RE .PP Here, the data section of the output indicates "bsize=4096", meaning the data block size for this filesystem is 4096 bytes. This section also shows "sunit=32 swidth=128 blks", which means the stripe unit is 32*4096 bytes = 128 kibibytes and the stripe width is 128*4096 bytes = 512 kibibytes. A single stripe of this filesystem therefore consists of four stripe units (128 blocks / 32 blocks per unit). .SH SEE ALSO .BR mkfs.xfs (8), .BR md (4), .BR lvm (8), .BR mount (8). xfsprogs-5.3.0/man/man8/xfs_io.80000644000175000017500000011115413570057155016255 0ustar nathansnathans.TH xfs_io 8 .SH NAME xfs_io \- debug the I/O path of an XFS filesystem .SH SYNOPSIS .B xfs_io [ .B \-adfimrRstxT ] [ .B \-c .I cmd ] ... [ .B \-C .I cmd ] ... [ .B \-p .I prog ] .I [ file ] .br .B xfs_io \-V .SH DESCRIPTION .B xfs_io is a debugging tool like .BR xfs_db (8), but is aimed at examining the regular file I/O paths rather than the raw XFS volume itself. These code paths include not only the obvious read/write/mmap interfaces for manipulating files, but also cover all of the XFS extensions (such as space preallocation, additional inode flags, etc). .SH OPTIONS .B xfs_io commands may be run interactively (the default) or as arguments on the command line. Interactive mode always runs commands on the current open file, whilst commands run from the command line may be repeated on all open files rather than just the current open file. In general, open file iteration will occur for commands that operate on file content or state. In contrast, commands that operate on filesystem or system-wide state will only be run on the current file regardless of how many files are currently open. Multiple arguments may be given on the command line and they are run in the sequence given. The program exits one all commands have been run. .TP 1.0i .BI \-c " cmd" Run the specified command on all currently open files. To maintain compatibility with historical usage, commands that can not be run on all open files will still be run but only execute once on the current open file. Multiple .B \-c arguments may be given and may be interleaved on the command line in any order with .B \-C commands. .TP .BI \-C " cmd" Run the specified command only on the current open file. Multiple .B \-C arguments may be given and may be interleaved on the command line in any order with .B \-c commands. .TP .BI \-p " prog" Set the program name for prompts and some error messages, the default value is .BR xfs_io . .TP .B \-f Create .I file if it does not already exist. .TP .B \-r Open .I file read-only, initially. This is required if .I file is immutable or append-only. .TP .B \-i Start an idle thread. The purpose of this idle thread is to test io from a multi threaded process. With single threaded process, the file table is not shared and file structs are not reference counted. Spawning an idle thread can help detecting file struct reference leaks. .TP .B \-x Expert mode. Dangerous commands are only available in this mode. These commands also tend to require additional privileges. .TP .B \-V Prints the version number and exits. .PP The other .BR open (2) options described below are also available from the command line. .SH CONCEPTS .B xfs_io maintains a number of open files and memory mappings. Files can be initially opened on the command line (optionally), and additional files can also be opened later. .PP .B xfs_io commands can be broken up into three groups. Some commands are aimed at doing regular file I/O - read, write, sync, space preallocation, etc. .PP The second set of commands exist for manipulating memory mapped regions of a file - mapping, accessing, storing, unmapping, flushing, etc. .PP The remaining commands are for the navigation and display of data structures relating to the open files, mappings, and the filesystems where they reside. .PP Many commands have extensive online help. Use the .B help command for more details on any command. .SH FILE I/O COMMANDS .TP .BI "file [ " N " ]" Display a list of all open files and (optionally) switch to an alternate current open file. .TP .BI "open [[ \-acdfrstRTPL ] " path " ]" Closes the current file, and opens the file specified by .I path instead. Without any arguments, displays statistics about the current file \- see the .B stat command. .RS 1.0i .PD 0 .TP 0.4i .B \-a opens append-only (O_APPEND). .TP .B \-d opens for direct I/O (O_DIRECT). .TP .B \-f creates the file if it doesn't already exist (O_CREAT). .TP .B \-r opens read-only (O_RDONLY). .TP .B \-s opens for synchronous I/O (O_SYNC). .TP .B \-t truncates on open (O_TRUNC). .TP .B \-n opens in non-blocking mode if possible (O_NONBLOCK). .TP .B \-T create a temporary file not linked into the filesystem namespace (O_TMPFILE). The pathname passed must refer to a directory which is treated as virtual parent for the newly created invisible file. Can not be used together with the .B \-r option. .TP .B \-R marks the file as a realtime XFS file after opening it, if it is not already marked as such. .TP .B \-P opens the path as a referent only (O_PATH). This is incompatible with other flags specifying other O_xxx flags apart from .BR \-L . .TP .B \-L doesn't follow symlinks (O_NOFOLLOW). This is incompatible with other flags specifying other O_xxx flags apart from .BR \-P . .PD .RE .TP .B o See the .B open command. .TP .B close Closes the current open file, marking the next open file as current (if one exists). .TP .B c See the .B close command. .TP .B chmod \-r | \-w Change the mode of the currently open file. The .B \-r option will set the file permissions to read-only (0444), whilst the .B \-w option will set the file permissions to read-write (0644). This allows xfs_io to set up mismatches between the file permissions and the open file descriptor read/write mode to exercise permission checks inside various syscalls. .TP .BI "pread [ \-b " bsize " ] [ \-v ] [ \-FBR [ \-Z " seed " ] ] [ \-V " vectors " ] " "offset length" Reads a range of bytes in a specified blocksize from the given .IR offset . .RS 1.0i .PD 0 .TP 0.4i .B \-b can be used to set the blocksize into which the .BR read (2) requests will be split. The default blocksize is 4096 bytes. .TP .B \-v dump the contents of the buffer after reading, by default only the count of bytes actually read is dumped. .TP .B \-F read the buffers in a forwards sequential direction. .TP .B \-B read the buffers in a reserve sequential direction. .TP .B \-R read the buffers in the give range in a random order. .TP .B \-Z seed specify the random number seed used for random reads. .TP .B \-V vectors Use the vectored IO read syscall .BR preadv (2) with a number of blocksize length iovecs. The number of iovecs is set by the .I vectors parameter. .PD .RE .TP .B r See the .B pread command. .TP .BI "pwrite [ \-i " file " ] [ \-dDwNOW ] [ \-s " skip " ] [ \-b " size " ] [ \-S " seed " ] [ \-FBR [ \-Z " zeed " ] ] [ \-V " vectors " ] " "offset length" Writes a range of bytes in a specified blocksize from the given .IR offset . The bytes written can be either a set pattern or read in from another file before writing. .RS 1.0i .PD 0 .TP 0.4i .B \-i allows an input .I file to be specified as the source of the data to be written. .TP .B \-d causes direct I/O, rather than the usual buffered I/O, to be used when reading the input file. .TP .B \-w call .BR fdatasync (2) once all writes are complete (included in timing results) .TP .B \-N Perform the .BR pwritev2 (2) call with .IR RWF_NOWAIT . .TP .B \-D Perform the .BR pwritev2 (2) call with .IR RWF_DSYNC . .TP .B \-O perform pwrite once and return the (maybe partial) bytes written. .TP .B \-W call .BR fsync (2) once all writes are complete (included in timing results) .TP .B \-s specifies the number of bytes to .I skip from the start of the input file before starting to read. .TP .B \-b used to set the blocksize into which the .BR write (2) requests will be split. The default blocksize is 4096 bytes. .TP .B \-S used to set the (repeated) fill pattern which is used when the data to write is not coming from a file. The default buffer fill pattern value is 0xcdcdcdcd. .TP .B \-F write the buffers in a forwards sequential direction. .TP .B \-B write the buffers in a reserve sequential direction. .TP .B \-R write the buffers in the give range in a random order. .TP .B \-Z seed specify the random number seed used for random write .TP .B \-V vectors Use the vectored IO write syscall .BR pwritev (2) with a number of blocksize length iovecs. The number of iovecs is set by the .I vectors parameter. .RE .PD .TP .B w See the .B pwrite command. .TP .BI "bmap [ \-adelpv ] [ \-n " nx " ]" Prints the block mapping for the current open file. Refer to the .BR xfs_bmap (8) manual page for complete documentation. .TP .BI "fiemap [ \-alv ] [ \-n " nx " ] [ " offset " [ " len " ]]" Prints the block mapping for the current open file using the fiemap ioctl. Options behave as described in the .BR xfs_bmap (8) manual page. .PP .RS Optionally, this command also supports passing the start offset from where to begin the mapping and the length of that region. The kernel will return any full extents which intersect with the requested range, and the .B fiemap command will print them in their entirety. If the requested range starts or ends in a hole, .B fiemap will print the hole, truncated to the requested range. .RE .TP .BI "extsize [ \-R | \-D ] [ " value " ]" Display and/or modify the preferred extent size used when allocating space for the currently open file. If the .B \-R option is specified, a recursive descent is performed for all directory entries below the currently open file .RB ( \-D can be used to restrict the output to directories only). If the target file is a directory, then the inherited extent size is set for that directory (new files created in that directory inherit that extent size). The .I value should be specified in bytes, or using one of the usual units suffixes (k, m, g, b, etc). The extent size is always reported in units of bytes. .TP .BI "cowextsize [ \-R | \-D ] [ " value " ]" Display and/or modify the preferred copy-on-write extent size used when allocating space for the currently open file. If the .B \-R option is specified, a recursive descent is performed for all directory entries below the currently open file .RB ( \-D can be used to restrict the output to directories only). If the target file is a directory, then the inherited CoW extent size is set for that directory (new files created in that directory inherit that CoW extent size). The .I value should be specified in bytes, or using one of the usual units suffixes (k, m, g, b, etc). The extent size is always reported in units of bytes. .TP .BI "allocsp " size " 0" Sets the size of the file to .I size and zeroes any additional space allocated using the XFS_IOC_ALLOCSP/XFS_IOC_FREESP system call described in the .BR xfsctl (3) manual page. .B allocsp and .B freesp do exactly the same thing. .TP .BI "freesp " size " 0" See the .B allocsp command. .TP .BI "fadvise [ \-r | \-s | [[ \-d | \-n | \-w ] " "offset length " ]] On platforms which support it, allows hints be given to the system regarding the expected I/O patterns on the file. The range arguments are required by some advise commands ([*] below), and the others must have no range arguments. With no arguments, the POSIX_FADV_NORMAL advice is implied (default readahead). .RS 1.0i .PD 0 .TP 0.4i .B \-d the data will not be accessed again in the near future (POSIX_FADV_DONTNEED[*]). .TP .B \-n data will be accessed once and not be reused (POSIX_FADV_NOREUSE[*]). .TP .B \-r expect access to data in random order (POSIX_FADV_RANDOM), which sets readahead to zero. .TP .B \-s expect access to data in sequential order (POSIX_FADV_SEQUENTIAL), which doubles the default readahead on the file. .TP .B \-w advises the specified data will be needed again (POSIX_FADV_WILLNEED[*]) which forces the maximum readahead. .RE .PD .TP .B fdatasync Calls .BR fdatasync (2) to flush the file's in-core data to disk. .TP .B fsync Calls .BR fsync (2) to flush all in-core file state to disk. .TP .B s See the .B fsync command. .TP .BI "sync_range [ \-a | \-b | \-w ] offset length " On platforms which support it, allows control of syncing a range of the file to disk. With no options, SYNC_FILE_RANGE_WRITE is implied on the range supplied. .RS 1.0i .PD 0 .TP 0.4i .B \-a wait for IO in the given range to finish after writing (SYNC_FILE_RANGE_WAIT_AFTER). .TP .B \-b wait for IO in the given range to finish before writing (SYNC_FILE_RANGE_WAIT_BEFORE). .TP .B \-w start writeback of dirty data in the given range (SYNC_FILE_RANGE_WRITE). .RE .PD .TP .B sync Calls .BR sync (2) to flush all filesystems' in-core data to disk. .TP .B syncfs Calls .BR syncfs (2) to flush this filesystem's in-core data to disk. .TP .BI resvsp " offset length" Allocates reserved, unwritten space for part of a file using the XFS_IOC_RESVSP system call described in the .BR xfsctl (3) manual page. .TP .BI unresvsp " offset length" Frees reserved space for part of a file using the XFS_IOC_UNRESVSP system call described in the .BR xfsctl (3) manual page. .TP .BI "falloc [ \-k ]" " offset length" Allocates reserved, unwritten space for part of a file using the fallocate routine as described in the .BR fallocate (2) manual page. .RS 1.0i .PD 0 .TP 0.4i .B \-k will set the FALLOC_FL_KEEP_SIZE flag as described in .BR fallocate (2). .PD .RE .TP .BI fcollapse " offset length" Call fallocate with FALLOC_FL_COLLAPSE_RANGE flag as described in the .BR fallocate (2) manual page to de-allocates blocks and eliminates the hole created in this process by shifting data blocks into the hole. .TP .BI finsert " offset length" Call fallocate with FALLOC_FL_INSERT_RANGE flag as described in the .BR fallocate (2) manual page to create the hole by shifting data blocks. .TP .BI fpunch " offset length" Punches (de-allocates) blocks in the file by calling fallocate with the FALLOC_FL_PUNCH_HOLE flag as described in the .BR fallocate (2) manual page. .TP .BI funshare " offset length" Call fallocate with FALLOC_FL_UNSHARE_RANGE flag as described in the .BR fallocate (2) manual page to unshare all shared blocks within the range. .TP .BI "fzero [ \-k ]" " offset length" Call fallocate with FALLOC_FL_ZERO_RANGE flag as described in the .BR fallocate (2) manual page to allocate and zero blocks within the range. With the .B -k option, use the FALLOC_FL_KEEP_SIZE flag as well. .TP .BI zero " offset length" Call xfsctl with .B XFS_IOC_ZERO_RANGE as described in the .BR xfsctl (3) manual page to allocate and zero blocks within the range. .TP .BI truncate " offset" Truncates the current file at the given offset using .BR ftruncate (2). .TP .BI "sendfile \-i " srcfile " | \-f " N " [ " "offset length " ] On platforms which support it, allows a direct in-kernel copy between two file descriptors. The current open file is the target, the source must be specified as another open file .RB ( \-f ) or by path .RB ( \-i ). .TP .BI "readdir [ -v ] [ -o " offset " ] [ -l " length " ] " Read a range of directory entries from a given offset of a directory. .RS 1.0i .PD 0 .TP 0.4i .B \-v verbose mode - dump dirent content as defined in .BR readdir (3) .TP .B \-o specify starting .I offset .TP .B \-l specify total .I length to read (in bytes) .RE .PD .TP .BI "seek \-a | \-d | \-h [ \-r ] [ \-s ] offset" On platforms that support the .BR lseek (2) .B SEEK_DATA and .B SEEK_HOLE options, display the offsets of the specified segments. .RS 1.0i .PD 0 .TP 0.4i .B \-a Display both .B data and .B hole segments starting at the specified .B offset. .TP .B \-d Display the .B data segment starting at the specified .B offset. .TP .B \-h Display the .B hole segment starting at the specified .B offset. .TP .B \-r Recursively display all the specified segments starting at the specified .B offset. .TP .B \-s Display the starting lseek(2) offset. This offset will be a calculated value when both data and holes are displayed together or performing a recusively display. .RE .PD .TP .BI "reflink [ \-C ] [ \-q ] src_file [src_offset dst_offset length]" On filesystems that support the .B FICLONERANGE or .B BTRFS_IOC_CLONE_RANGE ioctls, map .I length bytes at offset .I dst_offset in the open file to the same physical blocks that are mapped at offset .I src_offset in the file .I src_file , replacing any contents that may already have been there. If a program writes into a reflinked block range of either file, the dirty blocks will be cloned, written to, and remapped ("copy on write") in the affected file, leaving the other file(s) unchanged. If src_offset, dst_offset, and length are omitted, all contents of src_file will be reflinked into the open file. .RS 1.0i .PD 0 .TP 0.4i .B \-C Print timing statistics in a condensed format. .TP .B \-q Do not print timing statistics at all. .RE .PD .TP .BI "dedupe [ \-C ] [ \-q ] src_file src_offset dst_offset length" On filesystems that support the .B FIDEDUPERANGE or .B BTRFS_IOC_FILE_EXTENT_SAME ioctls, map .I length bytes at offset .I dst_offset in the open file to the same physical blocks that are mapped at offset .I src_offset in the file .I src_file , but only if the contents of both ranges are identical. This is known as block-based deduplication. If a program writes into a reflinked block range of either file, the dirty blocks will be cloned, written to, and remapped ("copy on write") in the affected file, leaving the other file(s) unchanged. .RS 1.0i .PD 0 .TP 0.4i .B \-C Print timing statistics in a condensed format. .TP .B \-q Do not print timing statistics at all. .RE .PD .TP .BI "copy_range [ -s " src_offset " ] [ -d " dst_offset " ] [ -l " length " ] src_file | \-f " N On filesystems that support the .BR copy_file_range (2) system call, copies data from the source file into the current open file. The source must be specified either by path .RB ( src_file ) or as another open file .RB ( \-f ). If .I length is not specified, this command copies data from .I src_offset to the end of .BI src_file into the dst_file at .IR dst_offset . .RS 1.0i .PD 0 .TP 0.4i .B \-s Copy data from .I src_file beginning from .IR src_offset . .TP .B \-d Copy data into the open file beginning at .IR dst_offset . .TP .B \-l Copy up to .I length bytes of data. .RE .PD .TP .BI swapext " donor_file " Swaps extent forks between files. The current open file is the target. The donor file is specified by path. Note that file data is not copied (file content moves with the fork(s)). .TP .BI "set_encpolicy [ \-c " mode " ] [ \-n " mode " ] [ \-f " flags " ] [ \-v " version " ] [ " keyspec " ]" On filesystems that support encryption, assign an encryption policy to the current file. .I keyspec is a hex string which specifies the encryption key to use. For v1 encryption policies, .I keyspec must be a 16-character hex string (8 bytes). For v2 policies, .I keyspec must be a 32-character hex string (16 bytes). If unspecified, an all-zeroes value is used. .RS 1.0i .PD 0 .TP 0.4i .BI \-c " mode" contents encryption mode (e.g. AES-256-XTS) .TP .BI \-n " mode" filenames encryption mode (e.g. AES-256-CTS) .TP .BI \-f " flags" policy flags (numeric) .TP .BI \-v " version" policy version. Defaults to 1 or 2 depending on the length of .IR keyspec ; or to 1 if .I keyspec is unspecified. .RE .PD .TP .BI "get_encpolicy [ \-1 ] [ \-t ]" On filesystems that support encryption, display the encryption policy of the current file. .RS 1.0i .PD 0 .TP 0.4i .BI \-1 Use only the old ioctl to get the encryption policy. This only works if the file has a v1 encryption policy. .TP .BI \-t Test whether v2 encryption policies are supported. Prints "supported", "unsupported", or an error message. .RE .PD .TP .BI "add_enckey [ \-d " descriptor " ]" On filesystems that support encryption, add an encryption key to the filesystem containing the currently open file. The key in binary (typically 64 bytes long) is read from standard input. .RS 1.0i .PD 0 .TP 0.4i .BI \-d " descriptor" key descriptor, as a 16-character hex string (8 bytes). If given, the key will be available for use by v1 encryption policies that use this descriptor. Otherwise, the key is added as a v2 policy key, and on success the resulting "key identifier" will be printed. .RE .PD .TP .BI "rm_enckey [ -a ] " keyspec On filesystems that support encryption, remove an encryption key from the filesystem containing the currently open file. .I keyspec is a hex string specifying the key to remove, as a 16-character "key descriptor" or a 32-character "key identifier". .RS 1.0i .PD 0 .TP 0.4i .BI \-a Remove the key for all users who have added it, not just the current user. This is a privileged operation. .RE .PD .TP .BI "enckey_status " keyspec On filesystems that support encryption, display the status of an encryption key. .I keyspec is a hex string specifying the key for which to display the status, as a 16-character "key descriptor" or a 32-character "key identifier". .TP .BR lsattr " [ " \-R " | " \-D " | " \-a " | " \-v " ]" List extended inode flags on the currently open file. If the .B \-R option is specified, a recursive descent is performed for all directory entries below the currently open file .RB ( \-D can be used to restrict the output to directories only). This is a depth first descent, it does not follow symlinks and it also does not cross mount points. .TP .BR chattr " [ " \-R " | " \-D " ] [ " + / \-riasAdtPneEfSxC " ]" Change extended inode flags on the currently open file. The .B \-R and .B \-D options have the same meaning as above. The mapping between each letter and the inode flags (refer to .BR xfsctl (3) for the full list) is available via the .B help command. .TP .BI "flink " path Link the currently open file descriptor into the filesystem namespace. .TP .BR stat " [ " \-v "|" \-r " ]" Selected statistics from .BR stat (2) and the XFS_IOC_GETXATTR system call on the current file. If the .B \-v option is specified, the atime (last access), mtime (last modify), and ctime (last change) timestamps are also displayed. The .B \-r option dumps raw fields from the stat structure. .TP .BI "statx [ \-v|\-r ][ \-m " basic " | \-m " all " | -m " " ][ \-FD ]" Selected statistics from .BR stat (2) and the XFS_IOC_GETXATTR system call on the current file. .RS 1.0i .PD 0 .TP 0.4i .B \-v Show timestamps. .TP .B \-r Dump raw statx structure values. .TP .B \-m basic Set the field mask for the statx call to STATX_BASIC_STATS. .TP .B \-m all Set the the field mask for the statx call to STATX_ALL (default). .TP .B \-m Specify a numeric field mask for the statx call. .TP .B \-F Force the attributes to be synced with the server. .TP .B \-D Don't sync attributes with the server. .PD .RE .TP .BR chproj " [ " \-R | \-D " ]" Modifies the project identifier associated with the current path. The .B \-R option will recursively descend if the current path is a directory. The .B \-D option will also recursively descend, only setting modifying projects on subdirectories. See the .BR xfs_quota (8) manual page for more information about project identifiers. .TP .BR lsproj " [ " \-R | \-D " ]" Displays the project identifier associated with the current path. The .B \-R and .B \-D options behave as described above, in .B chproj. .TP .BR parent " [ " \-cpv " ]" By default this command prints out the parent inode numbers, inode generation numbers and basenames of all the hardlinks which point to the inode of the current file. .RS 1.0i .PD 0 .TP 0.4i .B \-p the output is similar to the default output except pathnames up to the mount-point are printed out instead of the component name. .TP .B \-c the file's filesystem will check all the parent attributes for consistency. .TP .B \-v verbose output will be printed. .RE .IP .B [NOTE: Not currently operational on Linux.] .RE .PD .TP .BI utimes " atime_sec atime_nsec mtime_sec mtime_nsec" The utimes command changes the atime and mtime of the current file. sec uses UNIX timestamp notation and is the seconds elapsed since 1970-01-01 00:00:00 UTC. nsec is the nanoseconds since the sec. This value needs to be in the range 0-999999999 with UTIME_NOW and UTIME_OMIT being exceptions. Each (sec, nsec) pair constitutes a single timestamp value. .SH MEMORY MAPPED I/O COMMANDS .TP .BI "mmap [ " N " | [[ \-rwxS ] [\-s " size " ] " "offset length " ]] With no arguments, .B mmap shows the current mappings. Specifying a single numeric argument .I N sets the current mapping. If two arguments are specified (a range specified by .I offset and .IR length ), a new mapping is created spanning the range, and the protection mode can be given as a combination of PROT_READ .RB ( \-r ), PROT_WRITE .RB ( \-w ), and PROT_EXEC .RB ( \-x ). The mapping will be created with the MAP_SHARED flag by default, or with the Linux specific (MAP_SYNC | MAP_SHARED_VALIDATE) flags if .B -S is given. .BI \-s " size" is used to do a mmap(size) && munmap(size) operation at first, try to reserve some extendible free memory space, if .I size is bigger than .I length parameter. But there's not guarantee that the memory after .I length ( up to .I size ) will stay free. .B e.g. "mmap -rw -s 8192 1024" will mmap 0 ~ 1024 bytes memory, but try to reserve 1024 ~ 8192 free space(no guarantee). This free space will helpful for "mremap 8192" without MREMAP_MAYMOVE flag. .TP .B mm See the .B mmap command. .TP .BI "mremap [ \-f ] [ \-m ] " new_length Changes the current mapping size to .IR new_length . Whether the mapping may be moved is controlled by the flags passed; MREMAP_FIXED .RB ( \-f ), or MREMAP_MAYMOVE .RB ( \-m ). .IR new_length specifies a page-aligned address to which the mapping must be moved. It can be set to 139946004389888, 4096k or 1g etc. .TP .B mrm See the .B mremap command. .TP .B munmap Unmaps the current memory mapping. .TP .B mu See the .B munmap command. .TP .BI "mread [ \-f | \-v ] [ \-r ] [" " offset length " ] Accesses a segment of the current memory mapping, optionally dumping it to the standard output stream (with .B \-v or .B \-f option) for inspection. The accesses are performed sequentially from the start .I offset by default, but can also be done from the end backwards through the mapping if the .B \-r option in specified. The two verbose modes differ only in the relative offsets they display, the .B \-f option is relative to file start, whereas .B \-v shows offsets relative to the start of the mapping. .TP .B mr See the .B mread command. .TP .BI "mwrite [ \-r ] [ \-S " seed " ] [ " "offset length " ] Stores a byte into memory for a range within a mapping. The default stored value is 'X', repeated to fill the range specified, but this can be changed using the .B \-S option. The memory stores are performed sequentially from the start offset by default, but can also be done from the end backwards through the mapping if the .B \-r option in specified. .TP .B mw See the .B mwrite command. .TP .BI "msync [ \-i ] [ \-a | \-s ] [ " "offset length " ] Writes all modified copies of pages over the specified range (or entire mapping if no range specified) to their backing storage locations. Also, optionally invalidates .RB ( \-i ) so that subsequent references to the pages will be obtained from their backing storage locations (instead of cached copies). The flush can be done synchronously .RB ( \-s) or asynchronously .RB ( \-a ). .TP .B ms See the .B msync command. .TP .BI "madvise [ \-d | \-r | \-s | \-w ] [ " "offset length " ] Modifies page cache behavior when operating on the current mapping. The range arguments are required by some advise commands ([*] below). With no arguments, the POSIX_MADV_NORMAL advice is implied (default readahead). .RS 1.0i .PD 0 .TP 0.4i .B \-d the pages will not be needed (POSIX_MADV_DONTNEED[*]). .TP .B \-r expect random page references (POSIX_MADV_RANDOM), which sets readahead to zero. .TP .B \-s expect sequential page references (POSIX_MADV_SEQUENTIAL), which doubles the default readahead on the file. .TP .B \-w advises the specified pages will be needed again (POSIX_MADV_WILLNEED[*]) which forces the maximum readahead. .RE .PD .TP .B mincore Dumps a list of pages or ranges of pages that are currently in core, for the current memory mapping. .SH FILESYSTEM COMMANDS .TP .BI "bulkstat [ \-a " agno " ] [ \-d ] [ \-e " endino " ] [ \-n " batchsize " ] [ \-s " startino " ] [ \-v " version" ] Display raw stat information about a bunch of inodes in an XFS filesystem. Options are as follows: .RS 1.0i .PD 0 .TP .BI \-a " agno" Display only results from the given allocation group. If not specified, all results returned will be displayed. .TP .BI \-d Print debugging information about call results. .TP .BI \-e " endino" Stop displaying records when this inode number is reached. Defaults to stopping when the system call stops returning results. .TP .BI \-n " batchsize" Retrieve at most this many records per call. Defaults to 4,096. .TP .BI \-s " startino" Display inode allocation records starting with this inode. Defaults to the first inode in the filesystem. If the given inode is not allocated, results will begin with the next allocated inode in the filesystem. .TP .BI \-v " version" Use a particular version of the kernel interface. Currently supported versions are 1 and 5. .RE .PD .TP .BI "bulkstat_single [ \-d ] [ \-v " version " ] [ " inum... " | " special... " ] Display raw stat information about individual inodes in an XFS filesystem. The .B \-d and .B \-v options are the same as the .B bulkstat command. Arguments must be inode numbers or any of the special values: .RS 1.0i .PD 0 .TP .B root Display information about the root directory inode. .RE .PD .TP .B freeze Suspend all write I/O requests to the filesystem of the current file. Only available in expert mode and requires privileges. .TP .B thaw Undo the effects of a filesystem freeze operation. Only available in expert mode and requires privileges. .TP .BI "inject [ " tag " ]" Inject errors into a filesystem to observe filesystem behavior at specific points under adverse conditions. Without the .I tag argument, displays the list of error tags available. Only available in expert mode and requires privileges. .TP .BI "resblks [ " blocks " ]" Get and/or set count of reserved filesystem blocks using the XFS_IOC_GET_RESBLKS or XFS_IOC_SET_RESBLKS system calls. Note \-\- this can be useful for exercising out of space behavior. Only available in expert mode and requires privileges. .TP .BR shutdown " [ " \-f " ]" Force the filesystem to shut down, preventing any further IO. XFS and other filesystems implement this functionality, although implementation details may differ slightly. Only available in expert mode and requires privileges. .PP .RS By default, the filesystem will not attempt to flush completed transactions to disk before shutting down the filesystem. This simulates a disk failure or crash. .RE .RS 1.0i .PD 0 .TP 0.4i .B \-f Force the filesystem to flush all completed transactions to disk before shutting down, matching XFS behavior when critical corruption is encountered. .PD .RE .TP .B statfs Selected statistics from .BR statfs (2) and the XFS_IOC_FSGEOMETRY system call on the filesystem where the current file resides. .TP .BI "inode [ [ -n ] " number " ] [ -v ]" The inode command queries physical information about an inode. With no arguments, it will return 1 or 0, indicating whether or not any inode numbers greater than 32 bits are currently in use in the filesystem. If given an inode .I number as an argument, the command will return the same inode .I number if it is in use, or 0 if not. With .BI \-n " number" , the next used inode number after this .I number will be returned, or zero if the supplied inode number is the highest one in use. With .B \-v the command will also report the number of bits (32 or 64) used by the inode .I number printed in the result; if no inode .I number was specified on the command line, the maximum possible inode number in the system will be printed along with its size. .PD .TP .BI "inumbers [ \-a " agno " ] [ \-d ] [ \-e " endino " ] [ \-n " batchsize " ] [ \-s " startino " ] [ \-v " version " ] Prints allocation information about groups of inodes in an XFS filesystem. Callers can use this information to figure out which inodes are allocated. Options are as follows: .RS 1.0i .PD 0 .TP .BI \-a " agno" Display only results from the given allocation group. If not specified, all results returned will be displayed. .TP .BI \-d Print debugging information about call results. .TP .BI \-e " endino" Stop displaying records when this inode number is reached. Defaults to stopping when the system call stops returning results. .TP .BI \-n " batchsize" Retrieve at most this many records per call. Defaults to 4,096. .TP .BI \-s " startino" Display inode allocation records starting with this inode. Defaults to the first inode in the filesystem. If the given inode is not allocated, results will begin with the next allocated inode in the filesystem. .TP .BI \-v " version" Use a particular version of the kernel interface. Currently supported versions are 1 and 5. .RE .PD .TP .BI "scrub " type " [ " agnumber " | " "ino" " " "gen" " ]" Scrub internal XFS filesystem metadata. The .BI type parameter specifies which type of metadata to scrub. For AG metadata, one AG number must be specified. For file metadata, the scrub is applied to the open file unless the inode number and generation number are specified. .RE .PD .TP .BI "repair " type " [ " agnumber " | " "ino" " " "gen" " ]" Repair internal XFS filesystem metadata. The .BI type parameter specifies which type of metadata to repair. For AG metadata, one AG number must be specified. For file metadata, the repair is applied to the open file unless the inode number and generation number are specified. .TP .BI "label" " " "[ -c | -s " label " ] " On filesystems that support online label manipulation, get, set, or clear the filesystem label. With no options, print the current filesystem label. The .B \-c option clears the filesystem label by setting it to the null string. The .BI "\-s " label option sets the filesystem label to .IR label . If the label is longer than the filesystem will accept, .B xfs_io will print an error message. XFS filesystem labels can be at most 12 characters long. .TP .BI "fsmap [ \-d | \-l | \-r ] [ \-m | \-v ] [ \-n " nx " ] [ " start " ] [ " end " ] Prints the mapping of disk blocks used by the filesystem hosting the current file. The map lists each extent used by files, allocation group metadata, journalling logs, and static filesystem metadata, as well as any regions that are unused. Each line of the listings takes the following form: .PP .RS .IR extent ": " major ":" minor " [" startblock .. endblock "]: " owner " " startoffset .. endoffset " " length .PP Static filesystem metadata, allocation group metadata, btrees, journalling logs, and free space are marked by replacing the .IR startoffset .. endoffset with the appropriate marker. All blocks, offsets, and lengths are specified in units of 512-byte blocks, no matter what the filesystem's block size is. The optional .I start and .I end arguments can be used to constrain the output to a particular range of disk blocks. If these two options are specified, exactly one of .BR "-d" ", " "-l" ", or " "-r" must also be set. .RE .RS 1.0i .PD 0 .TP .BI \-d Display only extents from the data device. This option only applies for XFS filesystems. .TP .BI \-l Display only extents from the external log device. This option only applies to XFS filesystems. .TP .BI \-r Display only extents from the realtime device. This option only applies to XFS filesystems. .TP .BI \-m Display results in a machine readable format (CSV). This option is not compatible with the .B \-v flag. The columns of the output are: extent number, device major, device minor, physical start, physical end, owner, offset start, offset end, length. The start, end, and length numbers are provided in units of 512b. The owner field is a special string that takes the form: .RS 1.0i .PD 0 .TP 0.4i .I inode_%lld_data for inode data. .TP .I inode_%lld_data_bmbt for inode data extent maps. .TP .I inode_%lld_attr for inode extended attribute data. .TP .I inode_%lld_attr_bmbt for inode extended attribute extent maps. .TP .I special_%u:%u for other filesystem metadata. .PD .RE .TP .BI \-n " num_extents" If this option is given, .B fsmap obtains the extent list of the file in groups of .I num_extents extents. In the absence of .BR "-n" ", " "fsmap" queries the system for extents in groups of 131,072 records. .TP .B \-v Shows verbose information. When this flag is specified, additional AG specific information is appended to each line in the following form: .IP .RS 1.2i .IR agno " (" startagblock .. endagblock ") " nblocks " " flags .RE .IP A second .B \-v option will print out the .I flags legend. This option is not compatible with the .B \-m flag. .RE .PD .SH OTHER COMMANDS .TP .BR "help [ " command " ]" Display a brief description of one or all commands. .TP .B print Display a list of all open files and memory mapped regions. The current file and current mapping are distinguishable from any others. .TP .B p See the .B print command. .TP .B quit Exit .BR xfs_io . .TP .B q See the .B quit command. .TP .BI "log_writes \-d " device " \-m " mark Create a mark named .I mark in the dm-log-writes log specified by .I device. This is intended to be equivalent to the shell command: .B dmsetup message .I device .B 0 mark .I mark .PD .RE .TP .B lw See the .B log_writes command. .TP .B crc32cselftest Test the internal crc32c implementation to make sure that it computes results correctly. .SH SEE ALSO .BR mkfs.xfs (8), .BR xfsctl (3), .BR xfs_bmap (8), .BR xfs_db (8), .BR xfs (5), .BR fdatasync (2), .BR fstat (2), .BR fstatfs (2), .BR fsync (2), .BR ftruncate (2), .BR futimens (3), .BR mmap (2), .BR msync (2), .BR open (2), .BR pread (2), .BR pwrite (2), .BR readdir (3), .BR dmsetup (8). xfsprogs-5.3.0/man/man8/xfs_logprint.80000644000175000017500000000555713034246041017502 0ustar nathansnathans.TH xfs_logprint 8 .SH NAME xfs_logprint \- print the log of an XFS filesystem .SH SYNOPSIS .B xfs_logprint [ .I options ] .I device .SH DESCRIPTION .B xfs_logprint prints the log of an XFS filesystem (see .BR xfs (5)). The .I device argument is the pathname of the partition or logical volume containing the filesystem. The .I device can be a regular file if the .B \-f option is used. The contents of the filesystem remain undisturbed. There are two major modes of operation in .BR xfs_logprint . .PP One mode is better for filesystem operation debugging. It is called the transactional view and is enabled through the .B \-t option. The transactional view prints only the portion of the log that pertains to recovery. In other words, it prints out complete transactions between the tail and the head. This view tries to display each transaction without regard to how they are split across log records. .PP The second mode starts printing out information from the beginning of the log. Some error blocks might print out in the beginning because the last log record usually overlaps the oldest log record. A message is printed when the physical end of the log is reached and when the logical end of the log is reached. A log record view is displayed one record at a time. Transactions that span log records may not be decoded fully. .SH OPTIONS .TP .B \-b Extract and print buffer information. Only used in transactional view. .TP .B \-c Attempt to continue when an error is detected. .TP .BI \-C " filename" Copy the log from the filesystem to the file .IR filename . The log itself is not printed. .TP .B \-d Dump the log from front to end, printing where each log record is located on disk. .TP .B \-D Do not decode anything; just print data. .TP .B \-e Exit when an error is found in the log. Normally, .B xfs_logprint tries to continue and unwind from bad logs. However, sometimes it just dies in bad ways. Using this option prevents core dumps. .TP .B \-f Specifies that the filesystem image to be processed is stored in a regular file at .I device (see the .BR mkfs.xfs "(8) " -d .I file option). This might happen if an image copy of a filesystem has been made into an ordinary file with .BR xfs_copy (8). .TP .BI \-l " logdev" External log device. Only for those filesystems which use an external log. .TP .B \-i Extract and print inode information. Only used in transactional view. .TP .B \-q Extract and print quota information. Only used in transactional view. .TP .B \-n Do not try and interpret log data; just interpret log header information. .TP .B \-o Also print buffer data in hex. Normally, buffer data is just decoded, so better information can be printed. .TP .BI \-s " start-block" Override any notion of where to start printing. .TP .B \-t Print out the transactional view. .TP .B \-v Print "overwrite" data. .TP .B \-V Prints the version number and exits. .SH SEE ALSO .BR mkfs.xfs (8), .BR mount (8). xfsprogs-5.3.0/man/man8/xfs_mdrestore.80000644000175000017500000000264013242461543017645 0ustar nathansnathans.TH xfs_mdrestore 8 .SH NAME xfs_mdrestore \- restores an XFS metadump image to a filesystem image .SH SYNOPSIS .B xfs_mdrestore [ .B \-gi ] .I source .I target .br .B xfs_mdrestore .B \-i .I source .br .B xfs_mdrestore \-V .SH DESCRIPTION .B xfs_mdrestore is a debugging tool that restores a metadata image generated by .BR xfs_metadump (8) to a filesystem. The .I source argument specifies the location of the metadump image and the .I target argument specifies the destination for the filesystem image. If the .I source is \-, then the metadata image is read from stdin. This allows the output of be another program such as a compression application to be redirected to .BR xfs_mdrestore . The .I target can be either a file or a device. .PP .B xfs_mdrestore should not be used to restore metadata onto an existing filesystem unless you are completely certain the .I target can be destroyed. .PP .SH OPTIONS .TP .B \-g Shows restore progress on stdout. .TP .B \-i Shows metadump information on stdout. If no .I target is specified, exits after displaying information. Older metadumps man not include any descriptive information. .TP .B \-V Prints the version number and exits. .SH DIAGNOSTICS .B xfs_mdrestore returns an exit code of 0 if all the metadata is successfully restored or 1 if an error occurs. .SH SEE ALSO .BR xfs_metadump (8), .BR xfs_repair (8), .BR xfs (5) .SH BUGS Email bug reports to .BR linux-xfs@vger.kernel.org . xfsprogs-5.3.0/man/man8/xfs_metadump.80000644000175000017500000001171013242461543017453 0ustar nathansnathans.TH xfs_metadump 8 .SH NAME xfs_metadump \- copy XFS filesystem metadata to a file .SH SYNOPSIS .B xfs_metadump [ .B \-aefFgow ] [ .B \-m .I max_extents ] ] [ .B \-l .I logdev ] .I source .I target .br .B xfs_metadump \-V .SH DESCRIPTION .B xfs_metadump is a debugging tool that copies the metadata from an XFS filesystem to a file. The .I source argument must be the pathname of the device or file containing the XFS filesystem and the .I target argument specifies the destination file name. If .I target is \-, then the output is sent to stdout. This allows the output to be redirected to another program such as a compression application. .PP .B xfs_metadump may only be used to copy unmounted filesystems, or read-only mounted filesystems. .PP .B xfs_metadump does not alter the source filesystem in any way. The .I target image is a contiguous (non-sparse) file containing all the filesystem's metadata and indexes to where the blocks were copied from. .PP By default, .B xfs_metadump obfuscates most file (regular file, directory and symbolic link) names and extended attribute names to allow the dumps to be sent without revealing confidential information. Extended attribute values are zeroed and no data is copied. The only exceptions are file or attribute names that are 4 or less characters in length. Also file names that span extents (this can only occur with the .BR mkfs.xfs (8) options where .B \-n .I size > .B \-b .IR size ) are not obfuscated. Names between 5 and 8 characters in length inclusively are partially obfuscated. .PP .B xfs_metadump cannot obfuscate metadata in the filesystem log. Log recovery of an obfuscated metadump image may expose clear-text metadata and/or cause filesystem corruption in the restored image. It is recommended that the source filesystem first be mounted and unmounted, if possible, to ensure that the log is clean. A subsequent invocation of .B xfs_metadump will capture a clean log and obfuscate all metadata correctly. .PP If a metadump must be produced from a filesystem with a dirty log, it is recommended that obfuscation be turned off with -o option, if metadata such as filenames is not considered sensitive. If obfuscation is required on a metadump with a dirty log, please inform the recipient of the metadump image about this situation. .PP .B xfs_metadump should not be used for any purposes other than for debugging and reporting filesystem problems. The most common usage scenario for this tool is when .BR xfs_repair (8) fails to repair a filesystem and a metadump image can be sent for analysis. .PP The file generated by .B xfs_metadump can be restored to filesystem image (minus the data) using the .BR xfs_mdrestore (8) tool. .PP .SH OPTIONS .TP .B \-a Copies entire metadata blocks. Normally, .B xfs_metadump will zero any stale bytes interspersed with in-use metadata. Use this option to copy full metadata blocks, to provide more debugging information for a corrupted filesystem. Note that the extra data will be unobfuscated. .TP .B \-e Stops the dump on a read error. Normally, it will ignore read errors and copy all the metadata that is accessible. .TP .B \-f Specifies that the filesystem image to be processed is stored in a regular file (see the .B mkfs.xfs -d file option). This can also happen if an image copy of a filesystem has been made into an ordinary file with .BR xfs_copy (8). .TP .B \-F Specifies that we want to continue even if the superblock magic is not correct. If the source is truly not an XFS filesystem, the resulting image will be useless, and xfs_metadump may crash. .TP .B \-g Shows dump progress. This is sent to stdout if the .I target is a file or to stderr if the .I target is stdout. .TP .BI \-l " logdev" For filesystems which use an external log, this specifies the device where the external log resides. The external log is not copied, only internal logs are copied. .TP .B \-m Set the maximum size of an allowed metadata extent. Extremely large metadata extents are likely to be corrupt, and will be skipped if they exceed this value. The default size is 2097151 blocks. .TP .B \-o Disables obfuscation of file names and extended attributes. .TP .B \-w Prints warnings of inconsistent metadata encountered to stderr. Bad metadata is still copied. .TP .B \-V Prints the version number and exits. .SH DIAGNOSTICS .B xfs_metadump returns an exit code of 0 if all readable metadata is successfully copied or 1 if a write error occurs or a read error occurs and the .B \-e option used. .SH NOTES As .B xfs_metadump copies metadata only, it does not matter if the .I source filesystem has a realtime section or not. If the filesystem has an external log, it is not copied. Internal logs are copied and any outstanding log transactions are not obfuscated if they contain names. .PP .B xfs_metadump is a shell wrapper around the .BR xfs_db (8) .B metadump command. .SH SEE ALSO .BR xfs_repair (8), .BR xfs_mdrestore (8), .BR xfs_freeze (8), .BR xfs_db (8), .BR xfs_copy (8), .BR xfs (5) .SH BUGS Email bug reports to .BR linux-xfs@vger.kernel.org . xfsprogs-5.3.0/man/man8/xfs_mkfile.80000644000175000017500000000146513034246041017105 0ustar nathansnathans.TH xfs_mkfile 8 .SH NAME xfs_mkfile \- create an XFS file .SH SYNOPSIS .B xfs_mkfile [ .B \-v ] [ .B \-n ] [ .B \-p ] .I size\c .RB [ k | b | m | g ] .IR filename " ..." .br .B xfs_mkfile \-V .SH DESCRIPTION .B xfs_mkfile creates one or more files. The file is padded with zeroes by default. The default size is in bytes, but it can be flagged as kilobytes, blocks, megabytes, or gigabytes with the .BR k , .BR b , .BR m , or .B g suffixes, respectively. .SH OPTIONS .TP .B \-v Verbose. Report the names and sizes of created files. .TP .B \-n No bytes. Create a holey file - that is, do not write out any data, just seek to end of file and write a block. .TP .B \-p Preallocate. The file is preallocated, then overwritten with zeroes, then truncated to the desired size. .TP .B \-V Prints the version number and exits. xfsprogs-5.3.0/man/man8/xfs_ncheck.80000644000175000017500000000334713034246041017072 0ustar nathansnathans.TH xfs_ncheck 8 .SH NAME xfs_ncheck \- generate pathnames from i-numbers for XFS .SH SYNOPSIS .B xfs_ncheck [ .B \-i .I ino ] ... [ .B \-f ] [ .B \-s ] [ .B \-l .I logdev ] .I device .br .B xfs_ncheck \-V .SH DESCRIPTION .B xfs_ncheck with no .B \-i arguments generates an inode number and pathname list of all files on the given filesystem. Names of directory files are followed by .BR /. . The output is not sorted in any particular order. The filesystem to be examined is specified by the .I device argument, which should be the disk or volume device for the filesystem. Filesystems stored in files can also be checked, using the .B \-f flag. .SH OPTIONS .TP 0.9i .B \-f Specifies that the filesystem image to be processed is stored in a regular file at .I device (see the .B mkfs.xfs \-d .I \f2file\f1 option). This might happen if an image copy of a filesystem has been made into an ordinary file. .TP .BI \-l " logdev" Specifies the device where the filesystem's external log resides. Only for those filesystems which use an external log. See the .B mkfs.xfs \-l option, and refer to .BR xfs (5) for a detailed description of the XFS log. .TP .B \-s Limits the report to special files and files with setuserid mode. This option may be used to detect violations of security policy. .TP .BI \-i " ino" Limits the report to only those files whose inode numbers follow. May be given multiple times to select multiple inode numbers. .TP .B \-V Prints the version number and exits. .PP If the filesystem is seriously corrupted, or very busy and looks like it is corrupt, a message of the form that would be generated by the .BR xfs_db (8) "check" command may appear. .PP .B xfs_ncheck is only useful with XFS filesystems. .SH SEE ALSO .BR mkfs.xfs (8), .BR xfs (5). xfsprogs-5.3.0/man/man8/xfs_quota.80000644000175000017500000004674113435336037017007 0ustar nathansnathans.TH xfs_quota 8 .SH NAME xfs_quota \- manage use of quota on XFS filesystems .SH SYNOPSIS .B xfs_quota [ .B \-x ] [ .B \-f ] [ .B \-p .I prog ] [ .B \-c .I cmd ] ... [ .B \-d .I project ] ... [ .B \-D .I projects_file ] [ .B \-P .I projid_file ] [ .IR path " ... ]" .br .B xfs_quota \-V .SH DESCRIPTION .B xfs_quota is a utility for reporting and editing various aspects of filesystem quota. .PP The options to .B xfs_quota are: .TP 1.0i .BI \-c " cmd" .B xfs_quota commands may be run interactively (the default) or as arguments on the command line. Multiple .B \-c arguments may be given. The commands are run in the sequence given, then the program exits. .TP .BI \-p " prog" Set the program name for prompts and some error messages, the default value is .BR xfs_quota . .TP .B \-x Enable expert mode. All of the administrative commands (see the ADMINISTRATOR COMMANDS section below) which allow modifications to the quota system are available only in expert mode. .TP .B \-f Enable foreign filesystem mode. A limited number of user and administrative commands are available for use on some foreign (non-XFS) filesystems. .TP .BI \-d " project" Project names or numeric identifiers may be specified with this option, which restricts the output of the individual .B xfs_quota commands to the set of projects specified. Multiple .B \-d arguments may be given. .TP .BI \-D " projects_file" Specify a file containing the mapping of numeric project identifiers to directory trees. .I /etc/projects as default, if this option is none. .TP .BI \-P " projid_file" Specify a file containing the mapping of numeric project identifiers to project names. .I /etc/projid as default, if this option is none. .TP .B \-V Prints the version number and exits. .PP The optional .I path argument(s) can be used to specify mount points or device files which identify XFS filesystems. The output of the individual .B xfs_quota commands will then be restricted to the set of filesystems specified. .PP This manual page is divided into two sections \- firstly, information for users of filesystems with quota enabled, and the .B xfs_quota commands of interest to such users; and then information which is useful only to administrators of XFS filesystems using quota and the quota commands which allow modifications to the quota system. .PP Note that common to almost all of the individual commands described below are the options for specifying which quota types are of interest \- user quota .RB ( \-u ), group quota .RB ( \-g ), and/or project quota .RB ( \-p ). Also, several commands provide options to operate on "blocks used" .RB ( \-b ), "inodes used" .RB ( \-i ), and/or "realtime blocks used" .RB ( \-r ). .PP Many commands also have extensive online help. Use the .B help command for more details on any command. .SH QUOTA OVERVIEW .PP In most computing environments, disk space is not infinite. The quota subsystem provides a mechanism to control usage of disk space. Quotas can be set for each individual user on any/all of the local filesystems. The quota subsystem warns users when they exceed their allotted limit, but allows some extra space for current work (hard limit/soft limit). In addition, XFS filesystems with limit enforcement turned off can be used as an effective disk usage accounting system. .SS Users' View of Disk Quotas To most users, disk quotas are either of no concern or a fact of life that cannot be avoided. There are two possible quotas that can be imposed \- a limit can be set on the amount of space a user can occupy, and there may be a limit on the number of files (inodes) he can own. .PP The .B quota command provides information on the quotas that have been set by the system administrators and current usage. .PP There are four numbers for each limit: current usage, soft limit (quota), hard limit, and time limit. The soft limit is the number of 1K-blocks (or files) that the user is expected to remain below. The hard limit cannot be exceeded. If a user's usage reaches the hard limit, further requests for space (or attempts to create a file) fail with the "Quota exceeded" (EDQUOT) error. .PP When a user exceeds the soft limit, the timer is enabled. Any time the quota drops below the soft limits, the timer is disabled. If the timer pops, the particular limit that has been exceeded is treated as if the hard limit has been reached, and no more resources are allocated to the user. The only way to reset this condition, short of turning off limit enforcement or increasing the limit, is to reduce usage below quota. Only the superuser (i.e. a sufficiently capable process) can set the time limits and this is done on a per filesystem basis. .SS Surviving When the Quota Limit Is Reached In most cases, the only way for a user to recover from over-quota conditions is to abort whatever activity is in progress on the filesystem that has reached its limit, remove sufficient files to bring the limit back below quota, and retry the failed program. .br However, if a user is in the editor and a write fails because of an over quota situation, that is not a suitable course of action. It is most likely that initially attempting to write the file has truncated its previous contents, so if the editor is aborted without correctly writing the file, not only are the recent changes lost, but possibly much, or even all, of the contents that previously existed. .br There are several possible safe exits for a user caught in this situation. He can use the editor shell escape command to examine his file space and remove surplus files. Alternatively, using .BR sh (1), he can suspend the editor, remove some files, then resume it. A third possibility is to write the file to some other filesystem (perhaps to a file on .IR /tmp ) where the user's quota has not been exceeded. Then after rectifying the quota situation, the file can be moved back to the filesystem it belongs on. .SH USER COMMANDS .TP .B print Lists all paths with devices/project identifiers. The path list can come from several places \- the command line, the mount table, and the .I /etc/projects file. .TP .B df See the .B free command. .HP .B quota [ .BR \-g " | " \-p " | " \-u ] [ .B \-bir ] [ .B \-hnNv ] [ .B \-f .I file ] [ .I ID | .I name ] ... .br Show individual usage and limits, for a single user .I name or numeric user .IR ID . The .B \-h option reports in a "human-readable" format similar to the .BR df (1) command. The .B \-n option reports the numeric IDs rather than the name. The .B \-N option omits the header. The .B \-v option outputs verbose information. The .B \-f option sends the output to .I file instead of stdout. .HP .B free [ .B \-bir ] [ .B \-hN ] [ .B \-f .I file ] .br Reports filesystem usage, much like the .BR df (1) utility. It can show usage for .BR b locks, .BR i node, and/or .BR r ealtime block space, and shows used, free, and total available. If project quota are in use (see the DIRECTORY TREE QUOTA section below), it will also report utilisation for those projects (directory trees). The .B \-h option reports in a "human-readable" format. The .B \-N option omits the header. The .B \-f option outputs the report to .I file instead of stdout. .HP .B help [ .I command ] .br Online help for all commands, or one specific .IR command . .TP .B quit Exit .BR xfs_quota . .TP .B q See the .B quit command. .SH QUOTA ADMINISTRATION The XFS quota system differs to that of other filesystems in a number of ways. Most importantly, XFS considers quota information as filesystem metadata and uses journaling to provide a higher level guarantee of consistency. As such, it is administered differently, in particular: .IP 1. The .B quotacheck command has no effect on XFS filesystems. The first time quota accounting is turned on (at mount time), XFS does an automatic quotacheck internally; afterwards, the quota system will always be completely consistent until quotas are manually turned off. .IP 2. There is no need for quota file(s) in the root of the XFS filesystem. .IP 3. XFS distinguishes between quota accounting and limit enforcement. Quota accounting must be turned on at the time of mounting the XFS filesystem. However, it is possible to turn on/off limit enforcement any time quota accounting is turned on. The "quota" option to the .B mount command turns on both (user) quota accounting and enforcement. The "uqnoenforce" option must be used to turn on user accounting with limit enforcement disabled. .IP 4. Turning on quotas on the root filesystem is slightly different from the above. For Linux XFS, the quota mount flags must be passed in with the "rootflags=" boot parameter. .IP 5. It is useful to use the .B state to monitor the XFS quota subsystem at various stages \- it can be used to see if quotas are turned on, and also to monitor the space occupied by the quota system itself.. .IP 6. There is a mechanism built into .B xfsdump that allows quota limit information to be backed up for later restoration, should the need arise. .IP 7. Quota limits cannot be set before turning on quotas on. .IP 8. XFS filesystems keep quota accounting on the superuser (user ID zero), and the tool will display the superuser's usage information. However, limits are never enforced on the superuser (nor are they enforced for group and project ID zero). .IP 9. XFS filesystems perform quota accounting whether the user has quota limits or not. .IP 10. XFS supports the notion of project quota, which can be used to implement a form of directory tree quota (i.e. to restrict a directory tree to only being able to use up a component of the filesystems available space; or simply to keep track of the amount of space used, or number of inodes, within the tree). .SH ADMINISTRATOR COMMANDS .HP .B path [ .I N ] .br Lists all paths with devices/project identifiers or set the current path to the .IR N th list entry (the current path is used by many of the commands described here, it identifies the filesystem toward which a command is directed). The path list can come from several places \- the command line, the mount table, and the .I /etc/projects file. .HP .B report [ .B \-gpu ] [ .B \-bir ] [ .B \-ahntlLNU ] [ .B \-f .I file ] .br Report filesystem quota information. This reports all quota usage for a filesystem, for the specified quota type .RB ( u / g / p and/or .BR b locks/ i nodes/ r ealtime). It reports blocks in 1KB units by default. The .B \-h option reports in a "human-readable" format similar to the .BR df (1) command. The .B \-f option outputs the report to .I file instead of stdout. The .B \-a option reports on all filesystems. By default, outputs the name of the user/group/project. If no name is defined for a given ID, outputs the numeric ID instead. The .B \-n option outputs the numeric ID instead of the name. The .B \-L and .B \-U options specify lower and upper ID bounds to report on. If upper/lower bounds are specified, then by default only the IDs will be displayed in output; with the .B \-l option, a lookup will be performed to translate these IDs to names. The .B \-N option reports information without the header line. The .B \-t option performs a terse report. .HP .B state [ .B \-gpu ] [ .B \-av ] [ .B \-f .I file ] .br Report overall quota state information. This reports on the state of quota accounting, quota enforcement, and the number of extents being used by quota metadata within the filesystem. The .B \-f option outputs state information to .I file instead of stdout. The .B \-a option reports state on all filesystems and not just the current path. .HP .B limit [ .BR \-g " | " \-p " | " \-u ] .BI bsoft= N | .BI bhard= N | .BI isoft= N | .BI ihard= N | .BI rtbsoft= N | .BI rtbhard= N .B \-d | .I id | .I name .br Set quota block limits (bhard/bsoft), inode count limits (ihard/isoft) and/or realtime block limits (rtbhard/rtbsoft). The .B \-d option (defaults) can be used to set the default value that will be used, otherwise a specific .BR u ser/ g roup/ p roject .I name or numeric .IR id entifier must be specified. .HP .B timer [ .BR \-g " | " \-p " | " \-u ] [ .B \-bir ] .I value .br Allows the quota enforcement timeout (i.e. the amount of time allowed to pass before the soft limits are enforced as the hard limits) to be modified. The current timeout setting can be displayed using the .B state command. The value argument is a number of seconds, but units of \&'minutes', 'hours', 'days', and 'weeks' are also understood (as are their abbreviations 'm', 'h', 'd', and 'w'). .HP .B warn [ .BR \-g " | " \-p " | " \-u ] [ .B \-bir ] .I value .B -d | .I id | .I name .br Allows the quota warnings limit (i.e. the number of times a warning will be send to someone over quota) to be viewed and modified. The .B \-d option (defaults) can be used to set the default time that will be used, otherwise a specific .BR u ser/ g roup/ p roject .I name or numeric .IR id entifier must be specified. .B NOTE: this feature is not currently implemented. .TP .BR enable " [ " \-gpu " ] [ " \-v " ]" Switches on quota enforcement for the filesystem identified by the current path. This requires the filesystem to have been mounted with quota enabled, and for accounting to be currently active. The .B \-v option (verbose) displays the state after the operation has completed. .TP .BR disable " [ " \-gpu " ] [ " \-v " ]" Disables quota enforcement, while leaving quota accounting active. The .B \-v option (verbose) displays the state after the operation has completed. .TP .BR off " [ " \-gpu " ] [ " \-v " ]" Permanently switches quota off for the filesystem identified by the current path. Quota can only be switched back on subsequently by unmounting and then mounting again. .TP .BR remove " [ " \-gpu " ] [ " \-v " ]" Remove any space allocated to quota metadata from the filesystem identified by the current path. Quota must not be enabled on the filesystem, else this operation will report an error. .HP .B dump [ .BR \-g " | " \-p " | " \-u ] [ .B \-f .I file ] .br Dump out quota limit information for backup utilities, either to standard output (default) or to a .IR file . This is only the limits, not the usage information, of course. .HP .B restore [ .BR \-g " | " \-p " | " \-u ] [ .B \-f .I file ] .br Restore quota limits from a backup .IR file . The file must be in the format produced by the .B dump command. .HP .B quot [ .BR \-g " | " \-p " | " \-u ] [ .B \-bir ] [ .B \-acnv ] [ .B \-f .I file ] .br Summarize filesystem ownership, by user, group or project. This command uses a special XFS "bulkstat" interface to quickly scan an entire filesystem and report usage information. This command can be used even when filesystem quota are not enabled, as it is a full-filesystem scan (it may also take a long time...). The .B \-a option displays information on all filesystems. The .B \-c option displays a histogram instead of a report. The .B \-n option displays numeric IDs rather than names. The .B \-v option displays verbose information. The .B \-f option send the output to .I file instead of stdout. .HP .B project [ .B \-cCs [ .B \-d .I depth ] [ .B \-p .I path ] .I id | .I name ] .br The .BR \-c , .BR \-C , and .B \-s options allow the directory tree quota mechanism to be maintained. .BR \-d allows one to limit recursion level when processing project directories and .BR \-p allows one to specify project paths at command line ( instead of .I /etc/projects ). All options are discussed in detail below. .SH DIRECTORY TREE QUOTA The project quota mechanism in XFS can be used to implement a form of directory tree quota, where a specified directory and all of the files and subdirectories below it (i.e. a tree) can be restricted to using a subset of the available space in the filesystem. .PP A managed tree must be setup initially using the .B \-s option to the .B project command. The specified project name or identifier is matched to one or more trees defined in .IR /etc/projects , and these trees are then recursively descended to mark the affected inodes as being part of that tree. This process sets an inode flag and the project identifier on every file in the affected tree. Once this has been done, new files created in the tree will automatically be accounted to the tree based on their project identifier. An attempt to create a hard link to a file in the tree will only succeed if the project identifier matches the project identifier for the tree. The .B xfs_io utility can be used to set the project ID for an arbitrary file, but this can only be done by a privileged user. .PP A previously setup tree can be cleared from project quota control through use of the .B project \-C option, which will recursively descend the tree, clearing the affected inodes from project quota control. .PP Finally, the .B project \-c option can be used to check whether a tree is setup, it reports nothing if the tree is correct, otherwise it reports the paths of inodes which do not have the project ID of the rest of the tree, or if the inode flag is not set. .PP Option .B \-d can be used to limit recursion level (\-1 is infinite, 0 is top level only, 1 is first level ... ). Option .B \-p adds possibility to specify project paths in command line without a need for .I /etc/projects to exist. Note that if projects file exists then it is also used. .SH EXAMPLES Enabling quota enforcement on an XFS filesystem (restrict a user to a set amount of space). .nf .sp .in +5 # mount \-o uquota /dev/xvm/home /home # xfs_quota \-x \-c 'limit bsoft=500m bhard=550m tanya' /home # xfs_quota \-x \-c report /home .in -5 .fi .PP Enabling project quota on an XFS filesystem (restrict files in log file directories to only using 1 gigabyte of space). .nf .sp .in +5 # mount \-o prjquota /dev/xvm/var /var # echo 42:/var/log >> /etc/projects # echo logfiles:42 >> /etc/projid # xfs_quota \-x \-c 'project \-s logfiles' /var # xfs_quota \-x \-c 'limit \-p bhard=1g logfiles' /var .in -5 .fi .PP Same as above without a need for configuration files. .nf .sp .in +5 # rm \-f /etc/projects /etc/projid # mount \-o prjquota /dev/xvm/var /var # xfs_quota \-x \-c 'project \-s \-p /var/log 42' /var # xfs_quota \-x \-c 'limit \-p bhard=1g 42' /var .in -5 .fi .SH CAVEATS XFS implements delayed allocation (aka. allocate-on-flush) and this has implications for the quota subsystem. Since quota accounting can only be done when blocks are actually allocated, it is possible to issue (buffered) writes into a file and not see the usage immediately updated. Only when the data is actually written out, either via one of the kernels flushing mechanisms, or via a manual .BR sync (2), will the usage reported reflect what has actually been written. .PP In addition, the XFS allocation mechanism will always reserve the maximum amount of space required before proceeding with an allocation. If insufficient space for this reservation is available, due to the block quota limit being reached for example, this may result in the allocation failing even though there is sufficient space. Quota enforcement can thus sometimes happen in situations where the user is under quota and the end result of some operation would still have left the user under quota had the operation been allowed to run its course. This additional overhead is typically in the range of tens of blocks. .PP Both of these properties are unavoidable side effects of the way XFS operates, so should be kept in mind when assigning block limits. .SH BUGS Quota support for filesystems with realtime subvolumes is not yet implemented, nor is the quota warning mechanism (the Linux .BR warnquota (8) tool can be used to provide similar functionality on that platform). .SH FILES .PD 0 .TP 20 .I /etc/projects Mapping of numeric project identifiers to directories trees. .TP .I /etc/projid Mapping of numeric project identifiers to project names. .PD .SH SEE ALSO .BR df (1), .BR mount (1), .BR sync (2), .BR projid (5), .BR projects (5). .BR xfs (5). .BR warnquota (8), xfsprogs-5.3.0/man/man8/xfs_repair.80000644000175000017500000004145713435336037017137 0ustar nathansnathans.TH xfs_repair 8 .SH NAME xfs_repair \- repair an XFS filesystem .SH SYNOPSIS .B xfs_repair [ .B \-dfLPv ] [ .BR \-n " | " -e ] [ .B \-m .I maxmem ] [ .BI \-c " subopt" = value ] [ .B \-o .I subopt\c [\c .B =\c .IR value ] ] [ .B \-t .I interval ] [ .B \-l .I logdev ] [ .B \-r .I rtdev ] .I device .br .B xfs_repair \-V .SH DESCRIPTION .B xfs_repair repairs corrupt or damaged XFS filesystems (see .BR xfs (5)). The filesystem is specified using the .I device argument which should be the device name of the disk partition or volume containing the filesystem. If given the name of a block device, .B xfs_repair will attempt to find the raw device associated with the specified block device and will use the raw device instead. .PP Regardless, the filesystem to be repaired must be unmounted, otherwise, the resulting filesystem may be inconsistent or corrupt. .SH OPTIONS .TP .B \-f Specifies that the filesystem image to be processed is stored in a regular file at .I device (see the .B mkfs.xfs \-d .I file option). This might happen if an image copy of a filesystem has been copied or written into an ordinary file. This option implies that any external log or realtime section is also in an ordinary file. .TP .B \-L Force Log Zeroing. Forces .B xfs_repair to zero the log even if it is dirty (contains metadata changes). When using this option the filesystem will likely appear to be corrupt, and can cause the loss of user files and/or data. See the .B "DIRTY LOGS" section for more information. .TP .BI \-l " logdev" Specifies the device special file where the filesystem's external log resides. Only for those filesystems which use an external log. See the .B mkfs.xfs \-l option, and refer to .BR xfs (5) for a detailed description of the XFS log. .TP .BI \-r " rtdev" Specifies the device special file where the filesystem's realtime section resides. Only for those filesystems which use a realtime section. See the .B mkfs.xfs \-r option, and refer to .BR xfs (5) for a detailed description of the XFS realtime section. .TP .B \-n No modify mode. Specifies that .B xfs_repair should not modify the filesystem but should only scan the filesystem and indicate what repairs would have been made. This option cannot be used together with .BR \-e . .TP .B \-P Disable prefetching of inode and directory blocks. Use this option if you find .B xfs_repair gets stuck and stops proceeding. Interrupting a stuck .B xfs_repair is safe. .TP .BI \-m " maxmem" Specifies the approximate maximum amount of memory, in megabytes, to use for .BR xfs_repair . .B xfs_repair has its own internal block cache which will scale out up to the lesser of the process's virtual address limit or about 75% of the system's physical RAM. This option overrides these limits. .IP .B NOTE: These memory limits are only approximate and may use more than the specified limit. .TP .BI \-c " subopt" = value Change filesystem parameters. Refer to .BR xfs_admin (8) for information on changing filesystem parameters. .HP .B \-o .I subopt\c [\c .B =\c .IR value ] .br Override what the program might conclude about the filesystem if left to its own devices. .IP The .IR subopt ions supported are: .RS 1.0i .TP .BI bhash= bhashsize overrides the default buffer cache hash size. The total number of buffer cache entries are limited to 8 times this amount. The default size is set to use up the remainder of 75% of the system's physical RAM size. .TP .BI ag_stride= ags_per_concat_unit This creates additional processing threads to parallel process AGs that span multiple concat units. This can significantly reduce repair times on concat based filesystems. .TP .BI force_geometry Check the filesystem even if geometry information could not be validated. Geometry information can not be validated if only a single allocation group exists and thus we do not have a backup superblock available, or if there are two allocation groups and the two superblocks do not agree on the filesystem geometry. Only use this option if you validated the geometry yourself and know what you are doing. If In doubt run in no modify mode first. .RE .TP .B \-t " interval" Modify reporting interval, specified in seconds. During long runs .B xfs_repair outputs its progress every 15 minutes. Reporting is only activated when ag_stride is enabled. .TP .B \-v Verbose output. May be specified multiple times to increase verbosity. .TP .B \-d Repair dangerously. Allow .B xfs_repair to repair an XFS filesystem mounted read only. This is typically done on a root filesystem from single user mode, immediately followed by a reboot. .TP .B \-e If any metadata corruption was repaired, the status returned is 4 instead of the usual 0. This option cannot be used together with .BR \-n . .TP .B \-V Prints the version number and exits. .SS Checks Performed Inconsistencies corrected include the following: .IP 1. Inode and inode blockmap (addressing) checks: bad magic number in inode, bad magic numbers in inode blockmap blocks, extents out of order, incorrect number of records in inode blockmap blocks, blocks claimed that are not in a legal data area of the filesystem, blocks that are claimed by more than one inode. .IP 2. Inode allocation map checks: bad magic number in inode map blocks, inode state as indicated by map (free or in-use) inconsistent with state indicated by the inode, inodes referenced by the filesystem that do not appear in the inode allocation map, inode allocation map referencing blocks that do not appear to contain inodes. .IP 3. Size checks: number of blocks claimed by inode inconsistent with inode size, directory size not block aligned, inode size not consistent with inode format. .IP 4. Directory checks: bad magic numbers in directory blocks, incorrect number of entries in a directory block, bad freespace information in a directory leaf block, entry pointing to an unallocated (free) or out of range inode, overlapping entries, missing or incorrect dot and dotdot entries, entries out of hashvalue order, incorrect internal directory pointers, directory type not consistent with inode format and size. .IP 5. Pathname checks: files or directories not referenced by a pathname starting from the filesystem root, illegal pathname components. .IP 6. Link count checks: link counts that do not agree with the number of directory references to the inode. .IP 7. Freemap checks: blocks claimed free by the freemap but also claimed by an inode, blocks unclaimed by any inode but not appearing in the freemap. .IP 8. Super Block checks: total free block and/or free i-node count incorrect, filesystem geometry inconsistent, secondary and primary superblocks contradictory. .PP Orphaned files and directories (allocated, in-use but unreferenced) are reconnected by placing them in the .I lost+found directory. The name assigned is the inode number. .SS Disk Errors .B xfs_repair aborts on most disk I/O errors. Therefore, if you are trying to repair a filesystem that was damaged due to a disk drive failure, steps should be taken to ensure that all blocks in the filesystem are readable and writable before attempting to use .B xfs_repair to repair the filesystem. A possible method is using .BR dd (8) to copy the data onto a good disk. .SS lost+found The directory .I lost+found does not have to already exist in the filesystem being repaired. If the directory does not exist, it is automatically created if required. If it already exists, it will be checked for consistency and if valid will be used for additional orphaned files. Invalid .I lost+found directories are removed and recreated. Existing files in a valid .I lost+found are not removed or renamed. .SS Corrupted Superblocks XFS has both primary and secondary superblocks. .B xfs_repair uses information in the primary superblock to automatically find and validate the primary superblock against the secondary superblocks before proceeding. Should the primary be too corrupted to be useful in locating the secondary superblocks, the program scans the filesystem until it finds and validates some secondary superblocks. At that point, it generates a primary superblock. .SS Quotas If quotas are in use, it is possible that .B xfs_repair will clear some or all of the filesystem quota information. If so, the program issues a warning just before it terminates. If all quota information is lost, quotas are disabled and the program issues a warning to that effect. .PP Note that .B xfs_repair does not check the validity of quota limits. It is recommended that you check the quota limit information manually after .BR xfs_repair . Also, space usage information is automatically regenerated the next time the filesystem is mounted with quotas turned on, so the next quota mount of the filesystem may take some time. .SH DIAGNOSTICS .B xfs_repair issues informative messages as it proceeds indicating what it has found that is abnormal or any corrective action that it has taken. Most of the messages are completely understandable only to those who are knowledgeable about the structure of the filesystem. Some of the more common messages are explained here. Note that the language of the messages is slightly different if .B xfs_repair is run in no-modify mode because the program is not changing anything on disk. No-modify mode indicates what it would do to repair the filesystem if run without the no-modify flag. .PP .B disconnected inode .IB ino , .B moving to lost+found .IP An inode numbered .I ino was not connected to the filesystem directory tree and was reconnected to the .I lost+found directory. The inode is assigned the name of its inode number .RI ( ino ). If a .I lost+found directory does not exist, it is automatically created. .PP .B disconnected dir inode .IB ino , .B moving to lost+found .IP As above only the inode is a directory inode. If a directory inode is attached to .IR lost+found , all of its children (if any) stay attached to the directory and therefore get automatically reconnected when the directory is reconnected. .PP .B imap claims in-use inode .I ino .B is free, correcting imap .IP The inode allocation map thinks that inode .I ino is free whereas examination of the inode indicates that the inode may be in use (although it may be disconnected). The program updates the inode allocation map. .PP .B imap claims free inode .I ino .B is in use, correcting imap .IP The inode allocation map thinks that inode .I ino is in use whereas examination of the inode indicates that the inode is not in use and therefore is free. The program updates the inode allocation map. .PP .B resetting inode .I ino .B nlinks from .I x .B to .I y .IP The program detected a mismatch between the number of valid directory entries referencing inode .I ino and the number of references recorded in the inode and corrected the the number in the inode. .PP .I fork-type .B fork in ino .I ino .B claims used block .I bno .IP Inode .I ino claims a block .I bno that is used (claimed) by either another inode or the filesystem itself for metadata storage. The .I fork-type is either .B data or .B attr indicating whether the problem lies in the portion of the inode that tracks regular data or the portion of the inode that stores XFS attributes. If the inode is a real-time (rt) inode, the message says so. Any inode that claims blocks used by the filesystem is deleted. If two or more inodes claim the same block, they are both deleted. .PP .I fork-type .B fork in ino .I ino .B claims dup extent ... .IP Inode .I ino claims a block in an extent known to be claimed more than once. The offset in the inode, start and length of the extent is given. The message is slightly different if the inode is a real-time (rt) inode and the extent is therefore a real-time (rt) extent. .PP .B inode .I ino .B \- bad extent ... .IP An extent record in the blockmap of inode .I ino claims blocks that are out of the legal range of the filesystem. The message supplies the start, end, and file offset of the extent. The message is slightly different if the extent is a real-time (rt) extent. .PP .B bad .I fork-type .B fork in inode .I ino .IP There was something structurally wrong or inconsistent with the data structures that map offsets to filesystem blocks. .PP .B cleared inode .I ino .IP There was something wrong with the inode that was uncorrectable so the program freed the inode. This usually happens because the inode claims blocks that are used by something else or the inode itself is badly corrupted. Typically, this message is preceded by one or more messages indicating why the inode needed to be cleared. .PP .B bad attribute fork in inode .IR ino , .B clearing attr fork .IP There was something wrong with the portion of the inode that stores XFS attributes (the attribute fork) so the program reset the attribute fork. As a result of this, all attributes on that inode are lost. .PP .B correcting nextents for inode .IR ino , .B was .I x .B \- counted .I y .IP The program found that the number of extents used to store the data in the inode is wrong and corrected the number. The message refers to nextents if the count is wrong on the number of extents used to store attribute information. .PP .B entry .I name .B in dir .I dir_ino .B not consistent with .. value .BI ( xxxx ) .B in dir ino .IB ino , .B junking entry .I name .B in directory inode .I dir_ino .IP The entry .I name in directory inode .I dir_ino references a directory inode .IR ino . However, the ..\& entry in directory .I ino does not point back to directory .IR dir_ino , so the program deletes the entry .I name in directory inode .IR dir_ino . If the directory inode .I ino winds up becoming a disconnected inode as a result of this, it is moved to .I lost+found later. .PP .B entry .I name .B in dir .I dir_ino .B references already connected dir ino .IB ino , .B junking entry .I name .B in directory inode .I dir_ino .IP The entry .I name in directory inode .I dir_ino points to a directory inode .I ino that is known to be a child of another directory. Therefore, the entry is invalid and is deleted. This message refers to an entry in a small directory. If this were a large directory, the last phrase would read "will clear entry". .PP .B entry references free inode .I ino .B in directory .IB dir_ino , .B will clear entry .IP An entry in directory inode .I dir_ino references an inode .I ino that is known to be free. The entry is therefore invalid and is deleted. This message refers to a large directory. If the directory were small, the message would read "junking entry ...". .SH EXIT STATUS .B xfs_repair \-n (no modify mode) will return a status of 1 if filesystem corruption was detected and 0 if no filesystem corruption was detected. .B xfs_repair run without the \-n option will always return a status code of 0 if it completes without problems, unless the flag .B -e is used. If it is used, then status 4 is reported when any issue with the filesystem was found, but could be fixed. If a runtime error is encountered during operation, it will return a status of 1. In this case, .B xfs_repair should be restarted. If .B xfs_repair is unable to proceed due to a dirty log, it will return a status of 2. See below. .SH DIRTY LOGS Due to the design of the XFS log, a dirty log can only be replayed by the kernel, on a machine having the same CPU architecture as the machine which was writing to the log. .B xfs_repair cannot replay a dirty log and will exit with a status code of 2 when it detects a dirty log. .PP In this situation, the log can be replayed by mounting and immediately unmounting the filesystem on the same class of machine that crashed. Please make sure that the machine's hardware is reliable before replaying to avoid compounding the problems. .PP If mounting fails, the log can be erased by running .B xfs_repair with the -L option. All metadata updates in progress at the time of the crash will be lost, which may cause significant filesystem damage. This should .B only be used as a last resort. .SH BUGS The filesystem to be checked and repaired must have been unmounted cleanly using normal system administration procedures (the .BR umount (8) command or system shutdown), not as a result of a crash or system reset. If the filesystem has not been unmounted cleanly, mount it and unmount it cleanly before running .BR xfs_repair . .PP .B xfs_repair does not do a thorough job on XFS extended attributes. The structure of the attribute fork will be consistent, but only the contents of attribute forks that will fit into an inode are checked. This limitation will be fixed in the future. .PP The no-modify mode .RB ( \-n option) is not completely accurate. It does not catch inconsistencies in the freespace and inode maps, particularly lost blocks or subtly corrupted maps (trees). .PP The no-modify mode can generate repeated warnings about the same problems because it cannot fix the problems as they are encountered. .PP If a filesystem fails to be repaired, a metadump image can be generated with .BR xfs_metadump (8) and be sent to an XFS maintainer to be analysed and .B xfs_repair fixed and/or improved. .SH SEE ALSO .BR dd (1), .BR mkfs.xfs (8), .BR umount (8), .BR xfs_admin (8), .BR xfs_metadump (8), .BR xfs (5). xfsprogs-5.3.0/man/man8/xfs_rtcp.80000644000175000017500000000230713034246041016602 0ustar nathansnathans.TH xfs_rtcp 8 .SH NAME xfs_rtcp \- XFS realtime copy command .SH SYNOPSIS .B xfs_rtcp [ .B \-e .I extsize ] [ .B -p ] .IR source " ... " target .br .B xfs_rtcp \-V .SH DESCRIPTION .B xfs_rtcp copies a file to the realtime partition on an XFS filesystem. If there is more than one .I source and .IR target , the final argument (the .IR target ) must be a directory which already exists. .SH OPTIONS .TP .BI \-e " extsize" Sets the extent size of the destination realtime file. .TP .B \-p Use if the size of the source file is not an even multiple of the block size of the destination filesystem. When .B \-p is specified .B xfs_rtcp will pad the destination file to a size which is an even multiple of the filesystem block size. This is necessary since the realtime file is created using direct I/O and the minimum I/O is the filesystem block size. .TP .B \-V Prints the version number and exits. .SH SEE ALSO .BR xfs (5), .BR mkfs.xfs (8), .BR mount (8). .SH CAVEATS Currently, realtime partitions are not supported under the Linux version of XFS, and use of a realtime partition .B WILL CAUSE CORRUPTION on the data partition. As such, this command is made available for curious .B DEVELOPERS ONLY at this point in time. xfsprogs-5.3.0/man/man8/xfs_scrub.80000644000175000017500000001257613570057155016774 0ustar nathansnathans.TH xfs_scrub 8 .SH NAME xfs_scrub \- check and repair the contents of a mounted XFS filesystem .SH SYNOPSIS .B xfs_scrub [ .B \-abCemnTvx ] .I mount-point .br .B xfs_scrub \-V .SH DESCRIPTION .B xfs_scrub attempts to check and repair all metadata in a mounted XFS filesystem. .PP .B WARNING! This program is .BR EXPERIMENTAL "," which means that its behavior and interface could change at any time! .PP .B xfs_scrub asks the kernel to scrub all metadata objects in the filesystem. Metadata records are scanned for obviously bad values and then cross-referenced against other metadata. The goal is to establish a reasonable confidence about the consistency of the overall filesystem by examining the consistency of individual metadata records against the other metadata in the filesystem. Damaged metadata can be rebuilt from other metadata if there exists redundant data structures which are intact. .PP Filesystem corruption and optimization opportunities will be logged to the standard error stream. Enabling verbose mode will increase the amount of status information sent to the output. .PP If the kernel scrub reports that metadata needs repairs or optimizations and the user does not pass .B -n on the command line, this program will ask the kernel to make the repairs and to perform the optimizations. See the sections about optimizations and repairs for a list of optimizations and repairs known to this program. The kernel may not support repairing or optimizing the filesystem. If this is the case, the filesystem must be unmounted and .BR xfs_repair (8) run on the filesystem to fix the problems. .SH OPTIONS .TP .BI \-a " errors" Abort if more than this many errors are found on the filesystem. .TP .B \-b Run in background mode. If the option is specified once, only run a single scrubbing thread at a time. If given more than once, an artificial delay of 100us is added to each scrub call to reduce CPU overhead even further. .TP .BI \-C " fd" This option causes xfs_scrub to write progress information to the specified file description so that the progress of the filesystem check can be monitored. If the file description is a tty, a fancy progress bar is rendered. Otherwise, a simple numeric status dump compatible with the .B fsck -C format is output. .TP .B \-e Specifies what happens when errors are detected. If .IR shutdown is given, the filesystem will be taken offline if errors are found. If .IR continue is given, no action is taken if errors are found; this is the default behavior. .TP .B \-k Do not call TRIM on the free space. .TP .BI \-m " file" Search this file for mounted filesystems instead of /etc/mtab. .TP .B \-n Only check filesystem metadata. Do not repair or optimize anything. .TP .BI \-T Print timing and memory usage information for each phase. .TP .B \-v Enable verbose mode, which prints periodic status updates. .TP .B \-V Prints the version number and exits. .TP .B \-x Read all file data extents to look for disk errors. .B xfs_scrub will issue O_DIRECT reads to the block device directly. If the block device is a SCSI disk, it will instead issue READ VERIFY commands directly to the disk. If media errors are found, the error report will include the disk offset, in bytes. If the media errors affect a file, the report will also include the inode number and file offset, in bytes. These actions will confirm that all file data blocks can be read from storage. .SH OPTIMIZATIONS Optimizations supported by this program include, but are not limited to: .IP \[bu] 2 Instructing the underlying storage to discard unused extents via the .B TRIM ioctl. .IP \[bu] Updating secondary superblocks to match the primary superblock. .IP \[bu] Turning off shared block write checks for files that no longer share blocks. .SH REPAIRS Repairs are performed by calling into the kernel. This limits the scope of repair activities to rebuilding primary data structures from secondary data structures, or secondary structures from primary structures. The existence of secondary data structures may require features that can only be turned on from .BR mkfs.xfs (8). If errors cannot be repaired, the filesystem must be unmounted and .BR xfs_repair (8) run. Repairs supported by the kernel include, but are not limited to: .IP \[bu] 2 Reconstructing extent allocation data. .IP \[bu] Rebuilding free space information. .IP \[bu] Rebuilding inode indexes. .IP \[bu] Fixing minor corruptions of inode records. .IP \[bu] Recalculating reference count information. .IP \[bu] Reconstructing reverse mapping data from primary extent allocation data. .IP \[bu] Scheduling a quotacheck for the next mount. .PP If corrupt metadata is successfully repaired, this program will log that a repair has succeeded instead of a corruption report. .SH EXIT CODE The exit code returned by .B xfs_scrub is the sum of the following conditions: .br \ 0\ \-\ No errors .br \ 1\ \-\ File system errors left uncorrected .br \ 2\ \-\ File system optimizations possible .br \ 4\ \-\ Operational error .br \ 8\ \-\ Usage or syntax error .br .SH CAVEATS .B xfs_scrub is an immature utility! Do not run this program unless you have backups of your data! This program takes advantage of in-kernel scrubbing to verify a given data structure with locks held and can keep the filesystem busy for a long time. The kernel must be new enough to support the SCRUB_METADATA ioctl. .PP If errors are found and cannot be repaired, the filesystem must be unmounted and repaired. .SH SEE ALSO .BR xfs_repair (8). xfsprogs-5.3.0/man/man8/xfs_scrub_all.80000644000175000017500000000170413435336037017612 0ustar nathansnathans.TH xfs_scrub_all 8 .SH NAME xfs_scrub_all \- scrub all mounted XFS filesystems .SH SYNOPSIS .B xfs_scrub_all [ .B \-hV ] .SH DESCRIPTION .B xfs_scrub_all attempts to read and check all the metadata on all mounted XFS filesystems. The online scrub is performed via the .B xfs_scrub tool, either by running it directly or by using systemd to start it in a restricted fashion. Mounted filesystems are mapped to physical storage devices so that scrub operations can be run in parallel so long as no two scrubbers access the same device simultaneously. .SH OPTIONS .TP .B \-h Display help. .TP .B \-V Prints the version number and exits. .SH EXIT CODE The exit code returned by .B xfs_scrub_all is the sum of the following conditions: .br \ 0\ \-\ No errors .br \ 4\ \-\ File system errors left uncorrected .br \ 8\ \-\ Operational error .br \ 16\ \-\ Usage or syntax error .TP These are the same error codes returned by xfs_scrub. .br .SH SEE ALSO .BR xfs_scrub (8). xfsprogs-5.3.0/man/man8/xfs_spaceman.80000644000175000017500000001172713570057155017442 0ustar nathansnathans.TH xfs_spaceman 8 .SH NAME xfs_spaceman \- show free space information about an XFS filesystem .SH SYNOPSIS .B xfs_spaceman [ .B \-c .I cmd ] .I file .br .B xfs_spaceman \-V .SH DESCRIPTION .B xfs_spaceman reports and controls free space usage in an XFS filesystem. .SH OPTIONS .TP 1.0i .BI \-c " cmd" .B xfs_spaceman commands may be run interactively (the default) or as arguments on the command line. Multiple .B \-c arguments may be given. The commands are run in the sequence given, then the program exits. .SH COMMANDS .TP .BI "freesp [ \-dgrs ] [-a agno]... [ \-b | \-e bsize | \-h bsize | \-m factor ]" With no arguments, .B freesp shows a histogram of all free space extents in the filesystem. The command takes the following options: .RS 1.0i .PD 0 .TP 0.4i .B \-a agno Collect free space information from this allocation group. This option can be specified multiple times to collect from multiple groups. .TP .B \-b This argument establishes that the histogram bin sizes are successive powers of two. This is the default, and is mutually exclusive with the .BR "-e" ", " "-h" ", and " "-m" " options." .TP .B \-d Print debugging information such as the raw free space extent information. .TP .B \-g Print the free space block and extent counts for each AG. .TP .B \-e bsize Set all histogram bin sizes to a specific value. This option is mutually exclusive with the .BR "-b" ", " "-h" ", and " "-m" " options." .TP .B \-h bsize Create a histogram bin with a lower bound of this value. The upper bound of this bin will be one less than the lower bound of the next highest histogram bin. This option can be given multiple times to control the exact bin sizes. This option is mutually exclusive with the .BR "-b" ", " "-e" ", and " "-m" " options." .TP .B \-m factor Create each histogram bin with a size that is this many times the size of the prvious bin created. This option is mutually exclusive with the .BR "-b" ", " "-e" ", and " "-h" " options." .TP .B \-r Query the realtime device for free space information. .TP .B \-s Display a summary of the free space information found. .PD .RE .TP .B info Displays selected geometry information about the filesystem. The opened file must be a mount point of a XFS filesystem. The output will have the same format that .BR "xfs_info" "(8)" prints when querying a filesystem. .TP .BI "health [ \-a agno] [ \-c ] [ \-f ] [ \-i inum ] [ \-q ] [ paths ]" Reports the health of the given group of filesystem metadata. .RS 1.0i .PD 0 .TP 0.4i .B \-a agno Report on the health of the given allocation group. .TP .B \-c Scan all inodes in the filesystem and report each file's health status. If the .B \-a option is given, scan only the inodes in that AG. .TP .B \-f Report on the health of metadata that affect the entire filesystem. .TP .B \-i inum Report on the health of a specific inode. .TP .B \-q Report only unhealthy metadata. .TP .B paths Report on the health of the files at the given path. .PD .RE .TP .BR "help [ " command " ]" Display a brief description of one or all commands. .TP .BI "prealloc [ \-u id ] [ \-g id ] [ -p id ] [ \-m minlen ] [ \-s ]" Removes speculative preallocation. If no .BR "-u" ", " "-g" ", or " "-p" options are given, this command acts on all files. The command takes the following options: .RS 1.0i .PD 0 .TP 0.4i .B \-u uid Clear all speculative preallocations for files with this user id. This option can be given in combination with the .B "-g" " and " "-p" options. .TP .B \-g gid Clear all speculative preallocations for files with this group id. This option can be given in combination with the .B "-u" " and " "-p" options. .TP .B \-p pid Clear all speculative preallocations for files with this project id. This option can be given in combination with the .B "-u" " and " "-g" options. .TP .B \-m minlen Ignore all files smaller than this size. Units can be supplied for this argument. .TP .B \-s Wait for removal to complete. .PD .RE .TP .B print Display a list of all open files. .TP .B quit Exit .BR xfs_spaceman . .TP .BI "trim ( \-a agno | \-f | " "offset" " " "length" " ) [ -m minlen ]" Instructs the underlying storage device to release all storage that may be backing free space in the filesystem. The command takes the following options: (One of .BR -a ", " -f ", or the " .IR offset / length pair are required.) .RS 1.0i .PD 0 .TP 0.4i .B \-a agno Trim free space extents in the given allocation group. This option is mutually exclusive with the .BR "-f" " option and the " .IR "offset" "/" "length" " options." .TP .B \-f Trim all free space in the filesystem. This option is mutually exclusive with the .BR "-a" " option and the " .IR "offset" "/" "length" " options." .TP .IR "option" ", " "length" Trim all free space within the physical range defined by the .I offset and .I length from this filesystem. Units can be appended to these arguments. This option is mutually exclusive with the .BR "-a" " and " "-f" " options." .TP .B \-m minlen Do not trim free space extents shorter than this length. Units can be appended to this argument. .PD .RE xfsprogs-5.3.0/mdrestore/Makefile0000644000175000017500000000100213435336037016710 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_mdrestore CFILES = xfs_mdrestore.c LLDLIBS = $(LIBXFS) $(LIBFROG) $(LIBRT) $(LIBPTHREAD) $(LIBUUID) LTDEPENDENCIES = $(LIBXFS) $(LIBFROG) LLDFLAGS = -static default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/mdrestore/xfs_mdrestore.c0000644000175000017500000001664513435336037020323 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2007 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "xfs_metadump.h" char *progname; static int show_progress = 0; static int show_info = 0; static int progress_since_warning = 0; static void fatal(const char *msg, ...) { va_list args; va_start(args, msg); fprintf(stderr, "%s: ", progname); vfprintf(stderr, msg, args); exit(1); } static void print_progress(const char *fmt, ...) { char buf[60]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); buf[sizeof(buf)-1] = '\0'; printf("\r%-59s", buf); fflush(stdout); progress_since_warning = 1; } /* * perform_restore() -- do the actual work to restore the metadump * * @src_f: A FILE pointer to the source metadump * @dst_fd: the file descriptor for the target file * @is_target_file: designates whether the target is a regular file * @mbp: pointer to metadump's first xfs_metablock, read and verified by the caller * * src_f should be positioned just past a read the previously validated metablock */ static void perform_restore( FILE *src_f, int dst_fd, int is_target_file, const struct xfs_metablock *mbp) { struct xfs_metablock *metablock; /* header + index + blocks */ __be64 *block_index; char *block_buffer; int block_size; int max_indices; int cur_index; int mb_count; xfs_sb_t sb; int64_t bytes_read; block_size = 1 << mbp->mb_blocklog; max_indices = (block_size - sizeof(xfs_metablock_t)) / sizeof(__be64); metablock = (xfs_metablock_t *)calloc(max_indices + 1, block_size); if (metablock == NULL) fatal("memory allocation failure\n"); mb_count = be16_to_cpu(mbp->mb_count); if (mb_count == 0 || mb_count > max_indices) fatal("bad block count: %u\n", mb_count); block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t)); block_buffer = (char *)metablock + block_size; if (fread(block_index, block_size - sizeof(struct xfs_metablock), 1, src_f) != 1) fatal("error reading from metadump file\n"); if (block_index[0] != 0) fatal("first block is not the primary superblock\n"); if (fread(block_buffer, mb_count << mbp->mb_blocklog, 1, src_f) != 1) fatal("error reading from metadump file\n"); libxfs_sb_from_disk(&sb, (xfs_dsb_t *)block_buffer); if (sb.sb_magicnum != XFS_SB_MAGIC) fatal("bad magic number for primary superblock\n"); /* * Normally the upper bound would be simply XFS_MAX_SECTORSIZE * but the metadump format has a maximum number of BBSIZE blocks * it can store in a single metablock. */ if (sb.sb_sectsize < XFS_MIN_SECTORSIZE || sb.sb_sectsize > XFS_MAX_SECTORSIZE || sb.sb_sectsize > max_indices * block_size) fatal("bad sector size %u in metadump image\n", sb.sb_sectsize); ((xfs_dsb_t*)block_buffer)->sb_inprogress = 1; if (is_target_file) { /* ensure regular files are correctly sized */ if (ftruncate(dst_fd, sb.sb_dblocks * sb.sb_blocksize)) fatal("cannot set filesystem image size: %s\n", strerror(errno)); } else { /* ensure device is sufficiently large enough */ char *lb[XFS_MAX_SECTORSIZE] = { NULL }; off64_t off; off = sb.sb_dblocks * sb.sb_blocksize - sizeof(lb); if (pwrite(dst_fd, lb, sizeof(lb), off) < 0) fatal("failed to write last block, is target too " "small? (error: %s)\n", strerror(errno)); } bytes_read = 0; for (;;) { if (show_progress && (bytes_read & ((1 << 20) - 1)) == 0) print_progress("%lld MB read", bytes_read >> 20); for (cur_index = 0; cur_index < mb_count; cur_index++) { if (pwrite(dst_fd, &block_buffer[cur_index << mbp->mb_blocklog], block_size, be64_to_cpu(block_index[cur_index]) << BBSHIFT) < 0) fatal("error writing block %llu: %s\n", be64_to_cpu(block_index[cur_index]) << BBSHIFT, strerror(errno)); } if (mb_count < max_indices) break; if (fread(metablock, block_size, 1, src_f) != 1) fatal("error reading from metadump file\n"); mb_count = be16_to_cpu(metablock->mb_count); if (mb_count == 0) break; if (mb_count > max_indices) fatal("bad block count: %u\n", mb_count); if (fread(block_buffer, mb_count << mbp->mb_blocklog, 1, src_f) != 1) fatal("error reading from metadump file\n"); bytes_read += block_size + (mb_count << mbp->mb_blocklog); } if (progress_since_warning) putchar('\n'); memset(block_buffer, 0, sb.sb_sectsize); sb.sb_inprogress = 0; libxfs_sb_to_disk((xfs_dsb_t *)block_buffer, &sb); if (xfs_sb_version_hascrc(&sb)) { xfs_update_cksum(block_buffer, sb.sb_sectsize, offsetof(struct xfs_sb, sb_crc)); } if (pwrite(dst_fd, block_buffer, sb.sb_sectsize, 0) < 0) fatal("error writing primary superblock: %s\n", strerror(errno)); free(metablock); } static void usage(void) { fprintf(stderr, "Usage: %s [-V] [-g] [-i] source target\n", progname); exit(1); } extern int platform_check_ismounted(char *, char *, struct stat *, int); int main( int argc, char **argv) { FILE *src_f; int dst_fd; int c; int open_flags; struct stat statbuf; int is_target_file; struct xfs_metablock mb; progname = basename(argv[0]); while ((c = getopt(argc, argv, "giV")) != EOF) { switch (c) { case 'g': show_progress = 1; break; case 'i': show_info = 1; break; case 'V': printf("%s version %s\n", progname, VERSION); exit(0); default: usage(); } } if (argc - optind < 1 || argc - optind > 2) usage(); /* show_info without a target is ok */ if (!show_info && argc - optind != 2) usage(); /* * open source and test if this really is a dump. The first metadump block * will be passed to perform_restore() which will continue to read the * file from this point. This avoids rewind the stream, which causes * restore to fail when source was being read from stdin. */ if (strcmp(argv[optind], "-") == 0) { src_f = stdin; if (isatty(fileno(stdin))) fatal("cannot read from a terminal\n"); } else { src_f = fopen(argv[optind], "rb"); if (src_f == NULL) fatal("cannot open source dump file\n"); } if (fread(&mb, sizeof(mb), 1, src_f) != 1) fatal("error reading from metadump file\n"); if (mb.mb_magic != cpu_to_be32(XFS_MD_MAGIC)) fatal("specified file is not a metadata dump\n"); if (show_info) { if (mb.mb_info & XFS_METADUMP_INFO_FLAGS) { printf("%s: %sobfuscated, %s log, %s metadata blocks\n", argv[optind], mb.mb_info & XFS_METADUMP_OBFUSCATED ? "":"not ", mb.mb_info & XFS_METADUMP_DIRTYLOG ? "dirty":"clean", mb.mb_info & XFS_METADUMP_FULLBLOCKS ? "full":"zeroed"); } else { printf("%s: no informational flags present\n", argv[optind]); } if (argc - optind == 1) exit(0); } optind++; /* check and open target */ open_flags = O_RDWR; is_target_file = 0; if (stat(argv[optind], &statbuf) < 0) { /* ok, assume it's a file and create it */ open_flags |= O_CREAT; is_target_file = 1; } else if (S_ISREG(statbuf.st_mode)) { open_flags |= O_TRUNC; is_target_file = 1; } else { /* * check to make sure a filesystem isn't mounted on the device */ if (platform_check_ismounted(argv[optind], NULL, &statbuf, 0)) fatal("a filesystem is mounted on target device \"%s\"," " cannot restore to a mounted filesystem.\n", argv[optind]); } dst_fd = open(argv[optind], open_flags, 0644); if (dst_fd < 0) fatal("couldn't open target \"%s\"\n", argv[optind]); perform_restore(src_f, dst_fd, is_target_file, &mb); close(dst_fd); if (src_f != stdin) fclose(src_f); return 0; } xfsprogs-5.3.0/mkfs/Makefile0000644000175000017500000000111513435336037015651 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = mkfs.xfs HFILES = CFILES = proto.c xfs_mkfs.c LLDLIBS += $(LIBXFS) $(LIBXCMD) $(LIBFROG) $(LIBRT) $(LIBPTHREAD) $(LIBBLKID) \ $(LIBUUID) LTDEPENDENCIES += $(LIBXFS) $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static-libtool-libs default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/mkfs/proto.c0000644000175000017500000004105113570057155015524 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "xfs_multidisk.h" /* * Prototypes for internal functions. */ static char *getstr(char **pp); static void fail(char *msg, int i); static struct xfs_trans * getres(struct xfs_mount *mp, uint blocks); static void rsvfile(xfs_mount_t *mp, xfs_inode_t *ip, long long len); static int newfile(xfs_trans_t *tp, xfs_inode_t *ip, int symlink, int logit, char *buf, int len); static char *newregfile(char **pp, int *len); static void rtinit(xfs_mount_t *mp); static long filesize(int fd); /* * Use this for block reservations needed for mkfs's conditions * (basically no fragmentation). */ #define MKFS_BLOCKRES_INODE \ ((uint)(M_IGEO(mp)->ialloc_blks + (M_IGEO(mp)->inobt_maxlevels - 1))) #define MKFS_BLOCKRES(rb) \ ((uint)(MKFS_BLOCKRES_INODE + XFS_DA_NODE_MAXDEPTH + \ (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1) + (rb))) static long long getnum( const char *str, unsigned int blksize, unsigned int sectsize, bool convert) { long long i; char *sp; if (convert) return cvtnum(blksize, sectsize, str); i = strtoll(str, &sp, 0); if (i == 0 && sp == str) return -1LL; if (*sp != '\0') return -1LL; /* trailing garbage */ return i; } char * setup_proto( char *fname) { char *buf = NULL; static char dflt[] = "d--755 0 0 $"; int fd; long size; if (!fname) return dflt; if ((fd = open(fname, O_RDONLY)) < 0 || (size = filesize(fd)) < 0) { fprintf(stderr, _("%s: failed to open %s: %s\n"), progname, fname, strerror(errno)); goto out_fail; } buf = malloc(size + 1); if (read(fd, buf, size) < size) { fprintf(stderr, _("%s: read failed on %s: %s\n"), progname, fname, strerror(errno)); goto out_fail; } if (buf[size - 1] != '\n') { fprintf(stderr, _("%s: proto file %s premature EOF\n"), progname, fname); goto out_fail; } buf[size] = '\0'; /* * Skip past the stuff there for compatibility, a string and 2 numbers. */ (void)getstr(&buf); /* boot image name */ (void)getnum(getstr(&buf), 0, 0, false); /* block count */ (void)getnum(getstr(&buf), 0, 0, false); /* inode count */ close(fd); return buf; out_fail: if (fd >= 0) close(fd); free(buf); exit(1); } static void fail( char *msg, int i) { fprintf(stderr, "%s: %s [%d - %s]\n", progname, msg, i, strerror(i)); exit(1); } void res_failed( int i) { fail(_("cannot reserve space"), i); } static struct xfs_trans * getres( struct xfs_mount *mp, uint blocks) { struct xfs_trans *tp; int i; uint r; for (i = 0, r = MKFS_BLOCKRES(blocks); r >= blocks; r--) { i = -libxfs_trans_alloc_rollable(mp, r, &tp); if (i == 0) return tp; } res_failed(i); /* NOTREACHED */ return NULL; } static char * getstr( char **pp) { char c; char *p; char *rval; p = *pp; while ((c = *p)) { switch (c) { case ' ': case '\t': case '\n': p++; continue; case ':': p++; while (*p++ != '\n') ; continue; default: rval = p; while (c != ' ' && c != '\t' && c != '\n' && c != '\0') c = *++p; *p++ = '\0'; *pp = p; return rval; } } if (c != '\0') { fprintf(stderr, _("%s: premature EOF in prototype file\n"), progname); exit(1); } return NULL; } static void rsvfile( xfs_mount_t *mp, xfs_inode_t *ip, long long llen) { int error; xfs_trans_t *tp; error = -libxfs_alloc_file_space(ip, 0, llen, 1, 0); if (error) { fail(_("error reserving space for a file"), error); exit(1); } /* * update the inode timestamp, mode, and prealloc flag bits */ error = -libxfs_trans_alloc_rollable(mp, 0, &tp); if (error) fail(_("allocating transaction for a file"), error); libxfs_trans_ijoin(tp, ip, 0); VFS_I(ip)->i_mode &= ~S_ISUID; /* * Note that we don't have to worry about mandatory * file locking being disabled here because we only * clear the S_ISGID bit if the Group execute bit is * on, but if it was on then mandatory locking wouldn't * have been enabled. */ if (VFS_I(ip)->i_mode & S_IXGRP) VFS_I(ip)->i_mode &= ~S_ISGID; libxfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); if (error) fail(_("committing space for a file failed"), error); } static int newfile( xfs_trans_t *tp, xfs_inode_t *ip, int symlink, int logit, char *buf, int len) { xfs_buf_t *bp; xfs_daddr_t d; int error; int flags; xfs_bmbt_irec_t map; xfs_mount_t *mp; xfs_extlen_t nb; int nmap; flags = 0; mp = ip->i_mount; if (symlink && len <= XFS_IFORK_DSIZE(ip)) { libxfs_init_local_fork(ip, XFS_DATA_FORK, buf, len); ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; flags = XFS_ILOG_DDATA; } else if (len > 0) { nb = XFS_B_TO_FSB(mp, len); nmap = 1; error = -libxfs_bmapi_write(tp, ip, 0, nb, 0, nb, &map, &nmap); if (error) { fail(_("error allocating space for a file"), error); } if (nmap != 1) { fprintf(stderr, _("%s: cannot allocate space for file\n"), progname); exit(1); } d = XFS_FSB_TO_DADDR(mp, map.br_startblock); bp = libxfs_trans_get_buf(logit ? tp : NULL, mp->m_dev, d, nb << mp->m_blkbb_log, 0); memmove(bp->b_addr, buf, len); if (len < bp->b_bcount) memset((char *)bp->b_addr + len, 0, bp->b_bcount - len); if (logit) libxfs_trans_log_buf(tp, bp, 0, bp->b_bcount - 1); else libxfs_writebuf(bp, LIBXFS_EXIT_ON_FAILURE); } ip->i_d.di_size = len; return flags; } static char * newregfile( char **pp, int *len) { char *buf; int fd; char *fname; long size; fname = getstr(pp); if ((fd = open(fname, O_RDONLY)) < 0 || (size = filesize(fd)) < 0) { fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, fname, strerror(errno)); exit(1); } if ((*len = (int)size)) { buf = malloc(size); if (read(fd, buf, size) < size) { fprintf(stderr, _("%s: read failed on %s: %s\n"), progname, fname, strerror(errno)); exit(1); } } else buf = NULL; close(fd); return buf; } static void newdirent( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *pip, struct xfs_name *name, xfs_ino_t inum) { int error; int rsv; rsv = XFS_DIRENTER_SPACE_RES(mp, name->len); error = -libxfs_dir_createname(tp, pip, name, inum, rsv); if (error) fail(_("directory createname error"), error); } static void newdirectory( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, xfs_inode_t *pdp) { int error; error = -libxfs_dir_init(tp, dp, pdp); if (error) fail(_("directory create error"), error); } static void parseproto( xfs_mount_t *mp, xfs_inode_t *pip, struct fsxattr *fsxp, char **pp, char *name) { #define IF_REGULAR 0 #define IF_RESERVED 1 #define IF_BLOCK 2 #define IF_CHAR 3 #define IF_DIRECTORY 4 #define IF_SYMLINK 5 #define IF_FIFO 6 char *buf; int error; int flags; int fmt; int i; xfs_inode_t *ip; int len; long long llen; int majdev; int mindev; int mode; char *mstr; xfs_trans_t *tp; int val; int isroot = 0; cred_t creds; char *value; struct xfs_name xname; memset(&creds, 0, sizeof(creds)); mstr = getstr(pp); switch (mstr[0]) { case '-': fmt = IF_REGULAR; break; case 'r': fmt = IF_RESERVED; break; case 'b': fmt = IF_BLOCK; break; case 'c': fmt = IF_CHAR; break; case 'd': fmt = IF_DIRECTORY; break; case 'l': fmt = IF_SYMLINK; break; case 'p': fmt = IF_FIFO; break; default: fprintf(stderr, _("%s: bad format string %s\n"), progname, mstr); exit(1); } mode = 0; switch (mstr[1]) { case '-': break; case 'u': mode |= S_ISUID; break; default: fprintf(stderr, _("%s: bad format string %s\n"), progname, mstr); exit(1); } switch (mstr[2]) { case '-': break; case 'g': mode |= S_ISGID; break; default: fprintf(stderr, _("%s: bad format string %s\n"), progname, mstr); exit(1); } val = 0; for (i = 3; i < 6; i++) { if (mstr[i] < '0' || mstr[i] > '7') { fprintf(stderr, _("%s: bad format string %s\n"), progname, mstr); exit(1); } val = val * 8 + mstr[i] - '0'; } mode |= val; creds.cr_uid = (int)getnum(getstr(pp), 0, 0, false); creds.cr_gid = (int)getnum(getstr(pp), 0, 0, false); xname.name = (unsigned char *)name; xname.len = name ? strlen(name) : 0; xname.type = 0; flags = XFS_ILOG_CORE; switch (fmt) { case IF_REGULAR: buf = newregfile(pp, &len); tp = getres(mp, XFS_B_TO_FSB(mp, len)); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFREG, 1, 0, &creds, fsxp, &ip); if (error) fail(_("Inode allocation failed"), error); flags |= newfile(tp, ip, 0, 0, buf, len); if (buf) free(buf); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_REG_FILE; newdirent(mp, tp, pip, &xname, ip->i_ino); break; case IF_RESERVED: /* pre-allocated space only */ value = getstr(pp); llen = getnum(value, mp->m_sb.sb_blocksize, mp->m_sb.sb_sectsize, true); if (llen < 0) { fprintf(stderr, _("%s: Bad value %s for proto file %s\n"), progname, value, name); exit(1); } tp = getres(mp, XFS_B_TO_FSB(mp, llen)); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFREG, 1, 0, &creds, fsxp, &ip); if (error) fail(_("Inode pre-allocation failed"), error); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_REG_FILE; newdirent(mp, tp, pip, &xname, ip->i_ino); libxfs_trans_log_inode(tp, ip, flags); error = -libxfs_trans_commit(tp); if (error) fail(_("Space preallocation failed."), error); rsvfile(mp, ip, llen); libxfs_irele(ip); return; case IF_BLOCK: tp = getres(mp, 0); majdev = getnum(getstr(pp), 0, 0, false); mindev = getnum(getstr(pp), 0, 0, false); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFBLK, 1, IRIX_MKDEV(majdev, mindev), &creds, fsxp, &ip); if (error) { fail(_("Inode allocation failed"), error); } libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_BLKDEV; newdirent(mp, tp, pip, &xname, ip->i_ino); flags |= XFS_ILOG_DEV; break; case IF_CHAR: tp = getres(mp, 0); majdev = getnum(getstr(pp), 0, 0, false); mindev = getnum(getstr(pp), 0, 0, false); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFCHR, 1, IRIX_MKDEV(majdev, mindev), &creds, fsxp, &ip); if (error) fail(_("Inode allocation failed"), error); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_CHRDEV; newdirent(mp, tp, pip, &xname, ip->i_ino); flags |= XFS_ILOG_DEV; break; case IF_FIFO: tp = getres(mp, 0); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFIFO, 1, 0, &creds, fsxp, &ip); if (error) fail(_("Inode allocation failed"), error); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_FIFO; newdirent(mp, tp, pip, &xname, ip->i_ino); break; case IF_SYMLINK: buf = getstr(pp); len = (int)strlen(buf); tp = getres(mp, XFS_B_TO_FSB(mp, len)); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFLNK, 1, 0, &creds, fsxp, &ip); if (error) fail(_("Inode allocation failed"), error); flags |= newfile(tp, ip, 1, 1, buf, len); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_SYMLINK; newdirent(mp, tp, pip, &xname, ip->i_ino); break; case IF_DIRECTORY: tp = getres(mp, 0); error = -libxfs_inode_alloc(&tp, pip, mode|S_IFDIR, 1, 0, &creds, fsxp, &ip); if (error) fail(_("Inode allocation failed"), error); inc_nlink(VFS_I(ip)); /* account for . */ if (!pip) { pip = ip; mp->m_sb.sb_rootino = ip->i_ino; libxfs_log_sb(tp); isroot = 1; } else { libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_DIR; newdirent(mp, tp, pip, &xname, ip->i_ino); inc_nlink(VFS_I(pip)); libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE); } newdirectory(mp, tp, ip, pip); libxfs_trans_log_inode(tp, ip, flags); error = -libxfs_trans_commit(tp); if (error) fail(_("Directory inode allocation failed."), error); /* * RT initialization. Do this here to ensure that * the RT inodes get placed after the root inode. */ if (isroot) rtinit(mp); tp = NULL; for (;;) { name = getstr(pp); if (!name) break; if (strcmp(name, "$") == 0) break; parseproto(mp, ip, fsxp, pp, name); } libxfs_irele(ip); return; default: ASSERT(0); fail(_("Unknown format"), EINVAL); } libxfs_trans_log_inode(tp, ip, flags); error = -libxfs_trans_commit(tp); if (error) { fail(_("Error encountered creating file from prototype file"), error); } libxfs_irele(ip); } void parse_proto( xfs_mount_t *mp, struct fsxattr *fsx, char **pp) { parseproto(mp, NULL, fsx, pp, NULL); } /* * Allocate the realtime bitmap and summary inodes, and fill in data if any. */ static void rtinit( xfs_mount_t *mp) { xfs_fileoff_t bno; xfs_fileoff_t ebno; xfs_bmbt_irec_t *ep; int error; int i; xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; xfs_extlen_t nsumblocks; uint blocks; int nmap; xfs_inode_t *rbmip; xfs_inode_t *rsumip; xfs_trans_t *tp; struct cred creds; struct fsxattr fsxattrs; /* * First, allocate the inodes. */ i = -libxfs_trans_alloc_rollable(mp, MKFS_BLOCKRES_INODE, &tp); if (i) res_failed(i); memset(&creds, 0, sizeof(creds)); memset(&fsxattrs, 0, sizeof(fsxattrs)); error = -libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, &rbmip); if (error) { fail(_("Realtime bitmap inode allocation failed"), error); } /* * Do our thing with rbmip before allocating rsumip, * because the next call to ialloc() may * commit the transaction in which rbmip was allocated. */ mp->m_sb.sb_rbmino = rbmip->i_ino; rbmip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; rbmip->i_d.di_flags = XFS_DIFLAG_NEWRTBM; *(uint64_t *)&VFS_I(rbmip)->i_atime = 0; libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); libxfs_log_sb(tp); mp->m_rbmip = rbmip; error = -libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, &rsumip); if (error) { fail(_("Realtime summary inode allocation failed"), error); } mp->m_sb.sb_rsumino = rsumip->i_ino; rsumip->i_d.di_size = mp->m_rsumsize; libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE); libxfs_log_sb(tp); error = -libxfs_trans_commit(tp); if (error) fail(_("Completion of the realtime summary inode failed"), error); mp->m_rsumip = rsumip; /* * Next, give the bitmap file some zero-filled blocks. */ blocks = mp->m_sb.sb_rbmblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; i = -libxfs_trans_alloc_rollable(mp, blocks, &tp); if (i) res_failed(i); libxfs_trans_ijoin(tp, rbmip, 0); bno = 0; while (bno < mp->m_sb.sb_rbmblocks) { nmap = XFS_BMAP_MAX_NMAP; error = -libxfs_bmapi_write(tp, rbmip, bno, (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), 0, mp->m_sb.sb_rbmblocks, map, &nmap); if (error) { fail(_("Allocation of the realtime bitmap failed"), error); } for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, ep->br_startblock), XFS_FSB_TO_BB(mp, ep->br_blockcount)); bno += ep->br_blockcount; } } error = -libxfs_trans_commit(tp); if (error) fail(_("Block allocation of the realtime bitmap inode failed"), error); /* * Give the summary file some zero-filled blocks. */ nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; i = -libxfs_trans_alloc_rollable(mp, blocks, &tp); if (i) res_failed(i); libxfs_trans_ijoin(tp, rsumip, 0); bno = 0; while (bno < nsumblocks) { nmap = XFS_BMAP_MAX_NMAP; error = -libxfs_bmapi_write(tp, rsumip, bno, (xfs_extlen_t)(nsumblocks - bno), 0, nsumblocks, map, &nmap); if (error) { fail(_("Allocation of the realtime summary failed"), error); } for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, ep->br_startblock), XFS_FSB_TO_BB(mp, ep->br_blockcount)); bno += ep->br_blockcount; } } error = -libxfs_trans_commit(tp); if (error) fail(_("Block allocation of the realtime summary inode failed"), error); /* * Free the whole area using transactions. * Do one transaction per bitmap block. */ for (bno = 0; bno < mp->m_sb.sb_rextents; bno = ebno) { i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); if (i) res_failed(i); libxfs_trans_ijoin(tp, rbmip, 0); ebno = XFS_RTMIN(mp->m_sb.sb_rextents, bno + NBBY * mp->m_sb.sb_blocksize); error = -libxfs_rtfree_extent(tp, bno, (xfs_extlen_t)(ebno-bno)); if (error) { fail(_("Error initializing the realtime space"), error); } error = -libxfs_trans_commit(tp); if (error) fail(_("Initialization of the realtime space failed"), error); } } static long filesize( int fd) { struct stat stb; if (fstat(fd, &stb) < 0) return -1; return (long)stb.st_size; } xfsprogs-5.3.0/mkfs/xfs_mkfs.c0000644000175000017500000030035513570057155016206 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libfrog/util.h" #include "libxfs.h" #include #include "xfs_multidisk.h" #include "libxcmd.h" #include "libfrog/fsgeom.h" #include "libfrog/topology.h" #define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog))) #define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog))) #define MEGABYTES(count, blog) ((uint64_t)(count) << (20 - (blog))) /* * Use this macro before we have superblock and mount structure to * convert from basic blocks to filesystem blocks. */ #define DTOBT(d, bl) ((xfs_rfsblock_t)((d) >> ((bl) - BBSHIFT))) /* * amount (in bytes) we zero at the beginning and end of the device to * remove traces of other filesystems, raid superblocks, etc. */ #define WHACK_SIZE (128 * 1024) /* * XXX: The configured block and sector sizes are defined as global variables so * that they don't need to be passed to getnum/cvtnum(). */ static unsigned int blocksize; static unsigned int sectorsize; /* * Enums for each CLI parameter type are declared first so we can calculate the * maximum array size needed to hold them automatically. */ enum { B_SIZE = 0, B_MAX_OPTS, }; enum { D_AGCOUNT = 0, D_FILE, D_NAME, D_SIZE, D_SUNIT, D_SWIDTH, D_AGSIZE, D_SU, D_SW, D_SECTSIZE, D_NOALIGN, D_RTINHERIT, D_PROJINHERIT, D_EXTSZINHERIT, D_COWEXTSIZE, D_MAX_OPTS, }; enum { I_ALIGN = 0, I_MAXPCT, I_PERBLOCK, I_SIZE, I_ATTR, I_PROJID32BIT, I_SPINODES, I_MAX_OPTS, }; enum { L_AGNUM = 0, L_INTERNAL, L_SIZE, L_VERSION, L_SUNIT, L_SU, L_DEV, L_SECTSIZE, L_FILE, L_NAME, L_LAZYSBCNTR, L_MAX_OPTS, }; enum { N_SIZE = 0, N_VERSION, N_FTYPE, N_MAX_OPTS, }; enum { R_EXTSIZE = 0, R_SIZE, R_DEV, R_FILE, R_NAME, R_NOALIGN, R_MAX_OPTS, }; enum { S_SIZE = 0, S_SECTSIZE, S_MAX_OPTS, }; enum { M_CRC = 0, M_FINOBT, M_UUID, M_RMAPBT, M_REFLINK, M_MAX_OPTS, }; /* Just define the max options array size manually right now */ #define MAX_SUBOPTS D_MAX_OPTS #define SUBOPT_NEEDS_VAL (-1LL) #define MAX_CONFLICTS 8 #define LAST_CONFLICT (-1) /* * Table for parsing mkfs parameters. * * Description of the structure members follows: * * name MANDATORY * Name is a single char, e.g., for '-d file', name is 'd'. * * subopts MANDATORY * Subopts is a list of strings naming suboptions. In the example above, * it would contain "file". The last entry of this list has to be NULL. * * subopt_params MANDATORY * This is a list of structs tied with subopts. For each entry in subopts, * a corresponding entry has to be defined: * * subopt_params struct: * index MANDATORY * This number, starting from zero, denotes which item in subopt_params * it is. The index has to be the same as is the order in subopts list, * so we can access the right item both in subopt_param and subopts. * * seen INTERNAL * Do not set this flag when definning a subopt. It is used to remeber that * this subopt was already seen, for example for conflicts detection. * * str_seen INTERNAL * Do not set. It is used internally for respecification, when some options * has to be parsed twice - at first as a string, then later as a number. * * convert OPTIONAL * A flag signalling whether the user-given value can use suffixes. * If you want to allow the use of user-friendly values like 13k, 42G, * set it to true. * * is_power_2 OPTIONAL * An optional flag for subopts where the given value has to be a power * of two. * * conflicts MANDATORY * If your subopt is in a conflict with some other option, specify it. * Accepts the .index values of the conflicting subopts and the last * member of this list has to be LAST_CONFLICT. * * minval, maxval OPTIONAL * These options are used for automatic range check and they have to be * always used together in pair. If you don't want to limit the max value, * use something like UINT_MAX. If no value is given, then you must either * supply your own validation, or refuse any value in the 'case * X_SOMETHING' block. If you forget to define the min and max value, but * call a standard function for validating user's value, it will cause an * error message notifying you about this issue. * * (Said in another way, you can't have minval and maxval both equal * to zero. But if one value is different: minval=0 and maxval=1, * then it is OK.) * * defaultval MANDATORY * The value used if user specifies the subopt, but no value. * If the subopt accepts some values (-d file=[1|0]), then this * sets what is used with simple specifying the subopt (-d file). * A special SUBOPT_NEEDS_VAL can be used to require a user-given * value in any case. */ struct opt_params { const char name; const char *subopts[MAX_SUBOPTS]; struct subopt_param { int index; bool seen; bool str_seen; bool convert; bool is_power_2; struct _conflict { struct opt_params *opts; int subopt; } conflicts[MAX_CONFLICTS]; long long minval; long long maxval; long long defaultval; } subopt_params[MAX_SUBOPTS]; }; /* * The two dimensional conflict array requires some initialisations to know * about tables that haven't yet been defined. Work around this ordering * issue with extern definitions here. */ static struct opt_params sopts; static struct opt_params bopts = { .name = 'b', .subopts = { [B_SIZE] = "size", }, .subopt_params = { { .index = B_SIZE, .convert = true, .is_power_2 = true, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = XFS_MIN_BLOCKSIZE, .maxval = XFS_MAX_BLOCKSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, }, }; static struct opt_params dopts = { .name = 'd', .subopts = { [D_AGCOUNT] = "agcount", [D_FILE] = "file", [D_NAME] = "name", [D_SIZE] = "size", [D_SUNIT] = "sunit", [D_SWIDTH] = "swidth", [D_AGSIZE] = "agsize", [D_SU] = "su", [D_SW] = "sw", [D_SECTSIZE] = "sectsize", [D_NOALIGN] = "noalign", [D_RTINHERIT] = "rtinherit", [D_PROJINHERIT] = "projinherit", [D_EXTSZINHERIT] = "extszinherit", [D_COWEXTSIZE] = "cowextsize", }, .subopt_params = { { .index = D_AGCOUNT, .conflicts = { { &dopts, D_AGSIZE }, { NULL, LAST_CONFLICT } }, .minval = 1, .maxval = XFS_MAX_AGNUMBER, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_FILE, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = D_NAME, .conflicts = { { NULL, LAST_CONFLICT } }, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_SIZE, .conflicts = { { NULL, LAST_CONFLICT } }, .convert = true, .minval = XFS_AG_MIN_BYTES, .maxval = LLONG_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_SUNIT, .conflicts = { { &dopts, D_NOALIGN }, { &dopts, D_SU }, { &dopts, D_SW }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_SWIDTH, .conflicts = { { &dopts, D_NOALIGN }, { &dopts, D_SU }, { &dopts, D_SW }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_AGSIZE, .conflicts = { { &dopts, D_AGCOUNT }, { NULL, LAST_CONFLICT } }, .convert = true, .minval = XFS_AG_MIN_BYTES, .maxval = XFS_AG_MAX_BYTES, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_SU, .conflicts = { { &dopts, D_NOALIGN }, { &dopts, D_SUNIT }, { &dopts, D_SWIDTH }, { NULL, LAST_CONFLICT } }, .convert = true, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_SW, .conflicts = { { &dopts, D_NOALIGN }, { &dopts, D_SUNIT }, { &dopts, D_SWIDTH }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_SECTSIZE, .conflicts = { { &sopts, S_SIZE }, { &sopts, S_SECTSIZE }, { NULL, LAST_CONFLICT } }, .convert = true, .is_power_2 = true, .minval = XFS_MIN_SECTORSIZE, .maxval = XFS_MAX_SECTORSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_NOALIGN, .conflicts = { { &dopts, D_SU }, { &dopts, D_SW }, { &dopts, D_SUNIT }, { &dopts, D_SWIDTH }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = D_RTINHERIT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 1, .maxval = 1, .defaultval = 1, }, { .index = D_PROJINHERIT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_EXTSZINHERIT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = D_COWEXTSIZE, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, }, }; static struct opt_params iopts = { .name = 'i', .subopts = { [I_ALIGN] = "align", [I_MAXPCT] = "maxpct", [I_PERBLOCK] = "perblock", [I_SIZE] = "size", [I_ATTR] = "attr", [I_PROJID32BIT] = "projid32bit", [I_SPINODES] = "sparse", }, .subopt_params = { { .index = I_ALIGN, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = I_MAXPCT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 100, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = I_PERBLOCK, .conflicts = { { &iopts, I_SIZE }, { NULL, LAST_CONFLICT } }, .is_power_2 = true, .minval = XFS_MIN_INODE_PERBLOCK, .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = I_SIZE, .conflicts = { { &iopts, I_PERBLOCK }, { NULL, LAST_CONFLICT } }, .is_power_2 = true, .minval = XFS_DINODE_MIN_SIZE, .maxval = XFS_DINODE_MAX_SIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = I_ATTR, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 2, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = I_PROJID32BIT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = I_SPINODES, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, }, }; static struct opt_params lopts = { .name = 'l', .subopts = { [L_AGNUM] = "agnum", [L_INTERNAL] = "internal", [L_SIZE] = "size", [L_VERSION] = "version", [L_SUNIT] = "sunit", [L_SU] = "su", [L_DEV] = "logdev", [L_SECTSIZE] = "sectsize", [L_FILE] = "file", [L_NAME] = "name", [L_LAZYSBCNTR] = "lazy-count", }, .subopt_params = { { .index = L_AGNUM, .conflicts = { { &lopts, L_DEV }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = UINT_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_INTERNAL, .conflicts = { { &lopts, L_FILE }, { &lopts, L_DEV }, { &lopts, L_SECTSIZE }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = L_SIZE, .conflicts = { { NULL, LAST_CONFLICT } }, .convert = true, .minval = 2 * 1024 * 1024LL, /* XXX: XFS_MIN_LOG_BYTES */ .maxval = XFS_MAX_LOG_BYTES, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_VERSION, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 1, .maxval = 2, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_SUNIT, .conflicts = { { &lopts, L_SU }, { NULL, LAST_CONFLICT } }, .minval = 1, .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE), .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_SU, .conflicts = { { &lopts, L_SUNIT }, { NULL, LAST_CONFLICT } }, .convert = true, .minval = BBTOB(1), .maxval = XLOG_MAX_RECORD_BSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_DEV, .conflicts = { { &lopts, L_AGNUM }, { &lopts, L_NAME }, { &lopts, L_INTERNAL }, { NULL, LAST_CONFLICT } }, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_SECTSIZE, .conflicts = { { &lopts, L_INTERNAL }, { NULL, LAST_CONFLICT } }, .convert = true, .is_power_2 = true, .minval = XFS_MIN_SECTORSIZE, .maxval = XFS_MAX_SECTORSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_FILE, .conflicts = { { &lopts, L_INTERNAL }, { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = L_NAME, .conflicts = { { &lopts, L_AGNUM }, { &lopts, L_DEV }, { &lopts, L_INTERNAL }, { NULL, LAST_CONFLICT } }, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = L_LAZYSBCNTR, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, }, }; static struct opt_params nopts = { .name = 'n', .subopts = { [N_SIZE] = "size", [N_VERSION] = "version", [N_FTYPE] = "ftype", }, .subopt_params = { { .index = N_SIZE, .conflicts = { { NULL, LAST_CONFLICT } }, .convert = true, .is_power_2 = true, .minval = 1 << XFS_MIN_REC_DIRSIZE, .maxval = XFS_MAX_BLOCKSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = N_VERSION, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 2, .maxval = 2, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = N_FTYPE, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, }, }; static struct opt_params ropts = { .name = 'r', .subopts = { [R_EXTSIZE] = "extsize", [R_SIZE] = "size", [R_DEV] = "rtdev", [R_FILE] = "file", [R_NAME] = "name", [R_NOALIGN] = "noalign", }, .subopt_params = { { .index = R_EXTSIZE, .conflicts = { { NULL, LAST_CONFLICT } }, .convert = true, .minval = XFS_MIN_RTEXTSIZE, .maxval = XFS_MAX_RTEXTSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = R_SIZE, .conflicts = { { NULL, LAST_CONFLICT } }, .convert = true, .minval = 0, .maxval = LLONG_MAX, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = R_DEV, .conflicts = { { &ropts, R_NAME }, { NULL, LAST_CONFLICT } }, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = R_FILE, .minval = 0, .maxval = 1, .defaultval = 1, .conflicts = { { NULL, LAST_CONFLICT } }, }, { .index = R_NAME, .conflicts = { { &ropts, R_DEV }, { NULL, LAST_CONFLICT } }, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = R_NOALIGN, .minval = 0, .maxval = 1, .defaultval = 1, .conflicts = { { NULL, LAST_CONFLICT } }, }, }, }; static struct opt_params sopts = { .name = 's', .subopts = { [S_SIZE] = "size", [S_SECTSIZE] = "sectsize", }, .subopt_params = { { .index = S_SIZE, .conflicts = { { &sopts, S_SECTSIZE }, { &dopts, D_SECTSIZE }, { NULL, LAST_CONFLICT } }, .convert = true, .is_power_2 = true, .minval = XFS_MIN_SECTORSIZE, .maxval = XFS_MAX_SECTORSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = S_SECTSIZE, .conflicts = { { &sopts, S_SIZE }, { &dopts, D_SECTSIZE }, { NULL, LAST_CONFLICT } }, .convert = true, .is_power_2 = true, .minval = XFS_MIN_SECTORSIZE, .maxval = XFS_MAX_SECTORSIZE, .defaultval = SUBOPT_NEEDS_VAL, }, }, }; static struct opt_params mopts = { .name = 'm', .subopts = { [M_CRC] = "crc", [M_FINOBT] = "finobt", [M_UUID] = "uuid", [M_RMAPBT] = "rmapbt", [M_REFLINK] = "reflink", }, .subopt_params = { { .index = M_CRC, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = M_FINOBT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = M_UUID, .conflicts = { { NULL, LAST_CONFLICT } }, .defaultval = SUBOPT_NEEDS_VAL, }, { .index = M_RMAPBT, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, { .index = M_REFLINK, .conflicts = { { NULL, LAST_CONFLICT } }, .minval = 0, .maxval = 1, .defaultval = 1, }, }, }; /* quick way of checking if a parameter was set on the CLI */ static bool cli_opt_set( struct opt_params *opts, int subopt) { return opts->subopt_params[subopt].seen || opts->subopt_params[subopt].str_seen; } /* * Options configured on the command line. * * This stores all the specific config parameters the user sets on the command * line. We do not use these values directly - they are inputs to the mkfs * geometry validation and override any default configuration value we have. * * We don't keep flags to indicate what parameters are set - if we need to check * if an option was set on the command line, we check the relevant entry in the * option table which records whether it was specified in the .seen and * .str_seen variables in the table. * * Some parameters are stored as strings for post-parsing after their dependent * options have been resolved (e.g. block size and sector size have been parsed * and validated). * * This allows us to check that values have been set without needing separate * flags for each value, and hence avoids needing to record and check for each * specific option that can set the value later on in the code. In the cases * where we don't have a cli_params structure around, the above cli_opt_set() * function can be used. */ struct sb_feat_args { int log_version; int attr_version; int dir_version; bool inode_align; /* XFS_SB_VERSION_ALIGNBIT */ bool nci; /* XFS_SB_VERSION_BORGBIT */ bool lazy_sb_counters; /* XFS_SB_VERSION2_LAZYSBCOUNTBIT */ bool parent_pointers; /* XFS_SB_VERSION2_PARENTBIT */ bool projid32bit; /* XFS_SB_VERSION2_PROJID32BIT */ bool crcs_enabled; /* XFS_SB_VERSION2_CRCBIT */ bool dirftype; /* XFS_SB_VERSION2_FTYPE */ bool finobt; /* XFS_SB_FEAT_RO_COMPAT_FINOBT */ bool spinodes; /* XFS_SB_FEAT_INCOMPAT_SPINODES */ bool rmapbt; /* XFS_SB_FEAT_RO_COMPAT_RMAPBT */ bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */ bool nodalign; bool nortalign; }; struct cli_params { int sectorsize; int blocksize; /* parameters that depend on sector/block size being validated. */ char *dsize; char *agsize; char *dsu; char *dirblocksize; char *logsize; char *lsu; char *rtextsize; char *rtsize; /* parameters where 0 is a valid CLI value */ int dsunit; int dswidth; int dsw; int64_t logagno; int loginternal; int lsunit; /* parameters where 0 is not a valid value */ int64_t agcount; int inodesize; int inopblock; int imaxpct; int lsectorsize; uuid_t uuid; /* feature flags that are set */ struct sb_feat_args sb_feat; /* root inode characteristics */ struct fsxattr fsx; /* libxfs device setup */ struct libxfs_xinit *xi; }; /* * Calculated filesystem feature and geometry information. * * This structure contains the information we will use to create the on-disk * filesystem from. The validation and calculation code uses it to store all the * temporary and final config state for the filesystem. * * The information in this structure will contain a mix of validated CLI input * variables, default feature state and calculated values that are needed to * construct the superblock and other on disk features. These are all in one * place so that we don't have to pass handfuls of seemingly arbitrary variables * around to different functions to do the work we need to do. */ struct mkfs_params { int blocksize; int blocklog; int sectorsize; int sectorlog; int lsectorsize; int lsectorlog; int dirblocksize; int dirblocklog; int inodesize; int inodelog; int inopblock; uint64_t dblocks; uint64_t logblocks; uint64_t rtblocks; uint64_t rtextblocks; uint64_t rtextents; uint64_t rtbmblocks; /* rt bitmap blocks */ int dsunit; /* in FSBs */ int dswidth; /* in FSBs */ int lsunit; /* in FSBs */ uint64_t agsize; uint64_t agcount; int imaxpct; bool loginternal; uint64_t logstart; uint64_t logagno; uuid_t uuid; char *label; struct sb_feat_args sb_feat; }; /* * Default filesystem features and configuration values * * This structure contains the default mkfs values that are to be used when * a user does not specify the option on the command line. We do not use these * values directly - they are inputs to the mkfs geometry validation and * calculations. */ struct mkfs_default_params { char *source; /* where the defaults came from */ int sectorsize; int blocksize; /* feature flags that are set */ struct sb_feat_args sb_feat; /* root inode characteristics */ struct fsxattr fsx; }; static void __attribute__((noreturn)) usage( void ) { fprintf(stderr, _("Usage: %s\n\ /* blocksize */ [-b size=num]\n\ /* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\ /* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\ (sunit=value,swidth=value|su=num,sw=num|noalign),\n\ sectsize=num\n\ /* force overwrite */ [-f]\n\ /* inode size */ [-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n\ projid32bit=0|1,sparse=0|1]\n\ /* no discard */ [-K]\n\ /* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\ sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\ /* label */ [-L label (maximum 12 characters)]\n\ /* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\ /* no-op info only */ [-N]\n\ /* prototype file */ [-p fname]\n\ /* quiet */ [-q]\n\ /* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\ /* sectorsize */ [-s size=num]\n\ /* version */ [-V]\n\ devicename\n\ is required unless -d name=xxx is given.\n\ is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n\ xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n\ is xxx (512 byte blocks).\n"), progname); exit(1); } static void conflict( struct opt_params *opts, int option, struct opt_params *con_opts, int conflict) { fprintf(stderr, _("Cannot specify both -%c %s and -%c %s\n"), con_opts->name, con_opts->subopts[conflict], opts->name, opts->subopts[option]); usage(); } static void illegal( const char *value, const char *opt) { fprintf(stderr, _("Invalid value %s for -%s option\n"), value, opt); usage(); } static int ispow2( unsigned int i) { return (i & (i - 1)) == 0; } static void __attribute__((noreturn)) reqval( char opt, const char *tab[], int idx) { fprintf(stderr, _("-%c %s option requires a value\n"), opt, tab[idx]); usage(); } static void respec( char opt, const char *tab[], int idx) { fprintf(stderr, "-%c ", opt); if (tab) fprintf(stderr, "%s ", tab[idx]); fprintf(stderr, _("option respecified\n")); usage(); } static void unknown( char opt, char *s) { fprintf(stderr, _("unknown option -%c %s\n"), opt, s); usage(); } long long cvtnum( unsigned int blksize, unsigned int sectsize, const char *s) { long long i; char *sp; int c; i = strtoll(s, &sp, 0); if (i == 0 && sp == s) return -1LL; if (*sp == '\0') return i; if (sp[1] != '\0') return -1LL; if (*sp == 'b') { if (!blksize) { fprintf(stderr, _("Blocksize must be provided prior to using 'b' suffix.\n")); usage(); } else { return i * blksize; } } if (*sp == 's') { if (!sectsize) { fprintf(stderr, _("Sectorsize must be specified prior to using 's' suffix.\n")); usage(); } else { return i * sectsize; } } c = tolower(*sp); switch (c) { case 'e': i *= 1024LL; /* fall through */ case 'p': i *= 1024LL; /* fall through */ case 't': i *= 1024LL; /* fall through */ case 'g': i *= 1024LL; /* fall through */ case 'm': i *= 1024LL; /* fall through */ case 'k': return i * 1024LL; default: break; } return -1LL; } static void check_device_type( const char *name, int *isfile, bool no_size, bool no_name, int *create, const char *optname) { struct stat statbuf; if (*isfile && (no_size || no_name)) { fprintf(stderr, _("if -%s file then -%s name and -%s size are required\n"), optname, optname, optname); usage(); } if (!name) { fprintf(stderr, _("No device name specified\n")); usage(); } if (stat(name, &statbuf)) { if (errno == ENOENT && *isfile) { if (create) *create = 1; return; } fprintf(stderr, _("Error accessing specified device %s: %s\n"), name, strerror(errno)); usage(); return; } /* * We only want to completely truncate and recreate an existing file if * we were specifically told it was a file. Set the create flag only in * this case to trigger that behaviour. */ if (S_ISREG(statbuf.st_mode)) { if (!*isfile) *isfile = 1; else if (create) *create = 1; return; } if (S_ISBLK(statbuf.st_mode)) { if (*isfile) { fprintf(stderr, _("specified \"-%s file\" on a block device %s\n"), optname, name); usage(); } return; } fprintf(stderr, _("specified device %s not a file or block device\n"), name); usage(); } static void validate_overwrite( const char *name, bool force_overwrite) { if (!force_overwrite && check_overwrite(name)) { fprintf(stderr, _("%s: Use the -f option to force overwrite.\n"), progname); exit(1); } } static void validate_ag_geometry( int blocklog, uint64_t dblocks, uint64_t agsize, uint64_t agcount) { if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { fprintf(stderr, _("agsize (%lld blocks) too small, need at least %lld blocks\n"), (long long)agsize, (long long)XFS_AG_MIN_BLOCKS(blocklog)); usage(); } if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { fprintf(stderr, _("agsize (%lld blocks) too big, maximum is %lld blocks\n"), (long long)agsize, (long long)XFS_AG_MAX_BLOCKS(blocklog)); usage(); } if (agsize > dblocks) { fprintf(stderr, _("agsize (%lld blocks) too big, data area is %lld blocks\n"), (long long)agsize, (long long)dblocks); usage(); } if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { fprintf(stderr, _("too many allocation groups for size = %lld\n"), (long long)agsize); fprintf(stderr, _("need at most %lld allocation groups\n"), (long long)(dblocks / XFS_AG_MIN_BLOCKS(blocklog) + (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0))); usage(); } if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { fprintf(stderr, _("too few allocation groups for size = %lld\n"), (long long)agsize); fprintf(stderr, _("need at least %lld allocation groups\n"), (long long)(dblocks / XFS_AG_MAX_BLOCKS(blocklog) + (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0))); usage(); } /* * If the last AG is too small, reduce the filesystem size * and drop the blocks. */ if ( dblocks % agsize != 0 && (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) { fprintf(stderr, _("last AG size %lld blocks too small, minimum size is %lld blocks\n"), (long long)(dblocks % agsize), (long long)XFS_AG_MIN_BLOCKS(blocklog)); usage(); } /* * If agcount is too large, make it smaller. */ if (agcount > XFS_MAX_AGNUMBER + 1) { fprintf(stderr, _("%lld allocation groups is too many, maximum is %lld\n"), (long long)agcount, (long long)XFS_MAX_AGNUMBER + 1); usage(); } } static void zero_old_xfs_structures( libxfs_init_t *xi, xfs_sb_t *new_sb) { void *buf; xfs_sb_t sb; uint32_t bsize; int i; xfs_off_t off; /* * We open regular files with O_TRUNC|O_CREAT. Nothing to do here... */ if (xi->disfile && xi->dcreat) return; /* * read in existing filesystem superblock, use its geometry * settings and zero the existing secondary superblocks. */ buf = memalign(libxfs_device_alignment(), new_sb->sb_sectsize); if (!buf) { fprintf(stderr, _("error reading existing superblock -- failed to memalign buffer\n")); return; } memset(buf, 0, new_sb->sb_sectsize); /* * If we are creating an image file, it might be of zero length at this * point in time. Hence reading the existing superblock is going to * return zero bytes. It's not a failure we need to warn about in this * case. */ off = pread(xi->dfd, buf, new_sb->sb_sectsize, 0); if (off != new_sb->sb_sectsize) { if (!xi->disfile) fprintf(stderr, _("error reading existing superblock: %s\n"), strerror(errno)); goto done; } libxfs_sb_from_disk(&sb, buf); /* * perform same basic superblock validation to make sure we * actually zero secondary blocks */ if (sb.sb_magicnum != XFS_SB_MAGIC || sb.sb_blocksize == 0) goto done; for (bsize = 1, i = 0; bsize < sb.sb_blocksize && i < sizeof(sb.sb_blocksize) * NBBY; i++) bsize <<= 1; if (i < XFS_MIN_BLOCKSIZE_LOG || i > XFS_MAX_BLOCKSIZE_LOG || i != sb.sb_blocklog) goto done; if (sb.sb_dblocks > ((uint64_t)sb.sb_agcount * sb.sb_agblocks) || sb.sb_dblocks < ((uint64_t)(sb.sb_agcount - 1) * sb.sb_agblocks + XFS_MIN_AG_BLOCKS)) goto done; /* * block size and basic geometry seems alright, zero the secondaries. */ memset(buf, 0, new_sb->sb_sectsize); off = 0; for (i = 1; i < sb.sb_agcount; i++) { off += sb.sb_agblocks; if (pwrite(xi->dfd, buf, new_sb->sb_sectsize, off << sb.sb_blocklog) == -1) break; } done: free(buf); } static void discard_blocks(dev_t dev, uint64_t nsectors) { int fd; /* * We intentionally ignore errors from the discard ioctl. It is * not necessary for the mkfs functionality but just an optimization. */ fd = libxfs_device_to_fd(dev); if (fd > 0) platform_discard_blocks(fd, 0, nsectors << 9); } static __attribute__((noreturn)) void illegal_option( const char *value, struct opt_params *opts, int index, const char *reason) { fprintf(stderr, _("Invalid value %s for -%c %s option. %s\n"), value, opts->name, opts->subopts[index], reason); usage(); } /* * Check for conflicts and option respecification. */ static void check_opt( struct opt_params *opts, int index, bool str_seen) { struct subopt_param *sp = &opts->subopt_params[index]; int i; if (sp->index != index) { fprintf(stderr, _("Developer screwed up option parsing (%d/%d)! Please report!\n"), sp->index, index); reqval(opts->name, opts->subopts, index); } /* * Check for respecification of the option. This is more complex than it * seems because some options are parsed twice - once as a string during * input parsing, then later the string is passed to getnum for * conversion into a number and bounds checking. Hence the two variables * used to track the different uses based on the @str parameter passed * to us. */ if (!str_seen) { if (sp->seen) respec(opts->name, opts->subopts, index); sp->seen = true; } else { if (sp->str_seen) respec(opts->name, opts->subopts, index); sp->str_seen = true; } /* check for conflicts with the option */ for (i = 0; i < MAX_CONFLICTS; i++) { struct _conflict *con = &sp->conflicts[i]; if (con->subopt == LAST_CONFLICT) break; if (con->opts->subopt_params[con->subopt].seen || con->opts->subopt_params[con->subopt].str_seen) conflict(opts, index, con->opts, con->subopt); } } static long long getnum( const char *str, struct opt_params *opts, int index) { struct subopt_param *sp = &opts->subopt_params[index]; long long c; check_opt(opts, index, false); /* empty strings might just return a default value */ if (!str || *str == '\0') { if (sp->defaultval == SUBOPT_NEEDS_VAL) reqval(opts->name, opts->subopts, index); return sp->defaultval; } if (sp->minval == 0 && sp->maxval == 0) { fprintf(stderr, _("Option -%c %s has undefined minval/maxval." "Can't verify value range. This is a bug.\n"), opts->name, opts->subopts[index]); exit(1); } /* * Some values are pure numbers, others can have suffixes that define * the units of the number. Those get passed to cvtnum(), otherwise we * convert it ourselves to guarantee there is no trailing garbage in the * number. */ if (sp->convert) c = cvtnum(blocksize, sectorsize, str); else { char *str_end; c = strtoll(str, &str_end, 0); if (c == 0 && str_end == str) illegal_option(str, opts, index, _("Value not recognized as number.")); if (*str_end != '\0') illegal_option(str, opts, index, _("Unit suffixes are not allowed.")); } /* Validity check the result. */ if (c < sp->minval) illegal_option(str, opts, index, _("Value is too small.")); else if (c > sp->maxval) illegal_option(str, opts, index, _("Value is too large.")); if (sp->is_power_2 && !ispow2(c)) illegal_option(str, opts, index, _("Value must be a power of 2.")); return c; } /* * Option is a string - do all the option table work, and check there * is actually an option string. Otherwise we don't do anything with the string * here - validation will be done later when the string is converted to a value * or used as a file/device path. */ static char * getstr( char *str, struct opt_params *opts, int index) { check_opt(opts, index, true); /* empty strings for string options are not valid */ if (!str || *str == '\0') reqval(opts->name, opts->subopts, index); return str; } static int block_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case B_SIZE: cli->blocksize = getnum(value, opts, subopt); break; default: return -EINVAL; } return 0; } static int data_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case D_AGCOUNT: cli->agcount = getnum(value, opts, subopt); break; case D_AGSIZE: cli->agsize = getstr(value, opts, subopt); break; case D_FILE: cli->xi->disfile = getnum(value, opts, subopt); break; case D_NAME: cli->xi->dname = getstr(value, opts, subopt); break; case D_SIZE: cli->dsize = getstr(value, opts, subopt); break; case D_SUNIT: cli->dsunit = getnum(value, opts, subopt); break; case D_SWIDTH: cli->dswidth = getnum(value, opts, subopt); break; case D_SU: cli->dsu = getstr(value, opts, subopt); break; case D_SW: cli->dsw = getnum(value, opts, subopt); break; case D_NOALIGN: cli->sb_feat.nodalign = getnum(value, opts, subopt); break; case D_SECTSIZE: cli->sectorsize = getnum(value, opts, subopt); break; case D_RTINHERIT: if (getnum(value, opts, subopt)) cli->fsx.fsx_xflags |= FS_XFLAG_RTINHERIT; break; case D_PROJINHERIT: cli->fsx.fsx_projid = getnum(value, opts, subopt); cli->fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT; break; case D_EXTSZINHERIT: cli->fsx.fsx_extsize = getnum(value, opts, subopt); cli->fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT; break; case D_COWEXTSIZE: cli->fsx.fsx_cowextsize = getnum(value, opts, subopt); cli->fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE; break; default: return -EINVAL; } return 0; } static int inode_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case I_ALIGN: cli->sb_feat.inode_align = getnum(value, opts, subopt); break; case I_MAXPCT: cli->imaxpct = getnum(value, opts, subopt); break; case I_PERBLOCK: cli->inopblock = getnum(value, opts, subopt); break; case I_SIZE: cli->inodesize = getnum(value, opts, subopt); break; case I_ATTR: cli->sb_feat.attr_version = getnum(value, opts, subopt); break; case I_PROJID32BIT: cli->sb_feat.projid32bit = getnum(value, opts, subopt); break; case I_SPINODES: cli->sb_feat.spinodes = getnum(value, opts, subopt); break; default: return -EINVAL; } return 0; } static int log_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case L_AGNUM: cli->logagno = getnum(value, opts, subopt); break; case L_FILE: cli->xi->lisfile = getnum(value, opts, subopt); break; case L_INTERNAL: cli->loginternal = getnum(value, opts, subopt); break; case L_SU: cli->lsu = getstr(value, opts, subopt); break; case L_SUNIT: cli->lsunit = getnum(value, opts, subopt); break; case L_NAME: case L_DEV: cli->xi->logname = getstr(value, opts, subopt); cli->loginternal = 0; break; case L_VERSION: cli->sb_feat.log_version = getnum(value, opts, subopt); break; case L_SIZE: cli->logsize = getstr(value, opts, subopt); break; case L_SECTSIZE: cli->lsectorsize = getnum(value, opts, subopt); break; case L_LAZYSBCNTR: cli->sb_feat.lazy_sb_counters = getnum(value, opts, subopt); break; default: return -EINVAL; } return 0; } static int meta_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case M_CRC: cli->sb_feat.crcs_enabled = getnum(value, opts, subopt); if (cli->sb_feat.crcs_enabled) cli->sb_feat.dirftype = true; break; case M_FINOBT: cli->sb_feat.finobt = getnum(value, opts, subopt); break; case M_UUID: if (!value || *value == '\0') reqval('m', opts->subopts, subopt); if (platform_uuid_parse(value, &cli->uuid)) illegal(value, "m uuid"); break; case M_RMAPBT: cli->sb_feat.rmapbt = getnum(value, opts, subopt); break; case M_REFLINK: cli->sb_feat.reflink = getnum(value, opts, subopt); break; default: return -EINVAL; } return 0; } static int naming_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case N_SIZE: cli->dirblocksize = getstr(value, opts, subopt); break; case N_VERSION: value = getstr(value, &nopts, subopt); if (!strcasecmp(value, "ci")) { /* ASCII CI mode */ cli->sb_feat.nci = true; } else { cli->sb_feat.dir_version = getnum(value, opts, subopt); } break; case N_FTYPE: cli->sb_feat.dirftype = getnum(value, opts, subopt); break; default: return -EINVAL; } return 0; } static int rtdev_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case R_EXTSIZE: cli->rtextsize = getstr(value, opts, subopt); break; case R_FILE: cli->xi->risfile = getnum(value, opts, subopt); break; case R_NAME: case R_DEV: cli->xi->rtname = getstr(value, opts, subopt); break; case R_SIZE: cli->rtsize = getstr(value, opts, subopt); break; case R_NOALIGN: cli->sb_feat.nortalign = getnum(value, opts, subopt); break; default: return -EINVAL; } return 0; } static int sector_opts_parser( struct opt_params *opts, int subopt, char *value, struct cli_params *cli) { switch (subopt) { case S_SIZE: case S_SECTSIZE: cli->sectorsize = getnum(value, opts, subopt); cli->lsectorsize = cli->sectorsize; break; default: return -EINVAL; } return 0; } static struct subopts { char opt; struct opt_params *opts; int (*parser)(struct opt_params *opts, int subopt, char *value, struct cli_params *cli); } subopt_tab[] = { { 'b', &bopts, block_opts_parser }, { 'd', &dopts, data_opts_parser }, { 'i', &iopts, inode_opts_parser }, { 'l', &lopts, log_opts_parser }, { 'm', &mopts, meta_opts_parser }, { 'n', &nopts, naming_opts_parser }, { 'r', &ropts, rtdev_opts_parser }, { 's', &sopts, sector_opts_parser }, { '\0', NULL, NULL }, }; static void parse_subopts( char opt, char *arg, struct cli_params *cli) { struct subopts *sop = &subopt_tab[0]; char *p; int ret = 0; while (sop->opts) { if (sop->opt == opt) break; sop++; } /* should never happen */ if (!sop->opts) return; p = arg; while (*p != '\0') { char **subopts = (char **)sop->opts->subopts; char *value; int subopt; subopt = getsubopt(&p, subopts, &value); ret = (sop->parser)(sop->opts, subopt, value, cli); if (ret) unknown(opt, value); } } static void validate_sectorsize( struct mkfs_params *cfg, struct cli_params *cli, struct mkfs_default_params *dft, struct fs_topology *ft, char *dfile, int dry_run, int force_overwrite) { /* set configured sector sizes in preparation for checks */ if (!cli->sectorsize) { cfg->sectorsize = dft->sectorsize; } else { cfg->sectorsize = cli->sectorsize; } cfg->sectorlog = libxfs_highbit32(cfg->sectorsize); /* * Before anything else, verify that we are correctly operating on * files or block devices and set the control parameters correctly. */ check_device_type(dfile, &cli->xi->disfile, !cli->dsize, !dfile, dry_run ? NULL : &cli->xi->dcreat, "d"); if (!cli->loginternal) check_device_type(cli->xi->logname, &cli->xi->lisfile, !cli->logsize, !cli->xi->logname, dry_run ? NULL : &cli->xi->lcreat, "l"); if (cli->xi->rtname) check_device_type(cli->xi->rtname, &cli->xi->risfile, !cli->rtsize, !cli->xi->rtname, dry_run ? NULL : &cli->xi->rcreat, "r"); /* * Explicitly disable direct IO for image files so we don't error out on * sector size mismatches between the new filesystem and the underlying * host filesystem. */ if (cli->xi->disfile || cli->xi->lisfile || cli->xi->risfile) cli->xi->isdirect = 0; memset(ft, 0, sizeof(*ft)); get_topology(cli->xi, ft, force_overwrite); if (!cli->sectorsize) { /* * Unless specified manually on the command line use the * advertised sector size of the device. We use the physical * sector size unless the requested block size is smaller * than that, then we can use logical, but warn about the * inefficiency. * * Set the topology sectors if they were not probed to the * minimum supported sector size. */ if (!ft->lsectorsize) ft->lsectorsize = XFS_MIN_SECTORSIZE; /* Older kernels may not have physical/logical distinction */ if (!ft->psectorsize) ft->psectorsize = ft->lsectorsize; cfg->sectorsize = ft->psectorsize; if (cfg->blocksize < cfg->sectorsize && cfg->blocksize >= ft->lsectorsize) { fprintf(stderr, _("specified blocksize %d is less than device physical sector size %d\n" "switching to logical sector size %d\n"), cfg->blocksize, ft->psectorsize, ft->lsectorsize); cfg->sectorsize = ft->lsectorsize; } cfg->sectorlog = libxfs_highbit32(cfg->sectorsize); } /* validate specified/probed sector size */ if (cfg->sectorsize < XFS_MIN_SECTORSIZE || cfg->sectorsize > XFS_MAX_SECTORSIZE) { fprintf(stderr, _("illegal sector size %d\n"), cfg->sectorsize); usage(); } if (cfg->blocksize < cfg->sectorsize) { fprintf(stderr, _("block size %d cannot be smaller than sector size %d\n"), cfg->blocksize, cfg->sectorsize); usage(); } if (cfg->sectorsize < ft->lsectorsize) { fprintf(stderr, _("illegal sector size %d; hw sector is %d\n"), cfg->sectorsize, ft->lsectorsize); usage(); } } static void validate_blocksize( struct mkfs_params *cfg, struct cli_params *cli, struct mkfs_default_params *dft) { /* * Blocksize and sectorsize first, other things depend on them * For RAID4/5/6 we want to align sector size and block size, * so we need to start with the device geometry extraction too. */ if (!cli->blocksize) cfg->blocksize = dft->blocksize; else cfg->blocksize = cli->blocksize; cfg->blocklog = libxfs_highbit32(cfg->blocksize); /* validate block sizes are in range */ if (cfg->blocksize < XFS_MIN_BLOCKSIZE || cfg->blocksize > XFS_MAX_BLOCKSIZE) { fprintf(stderr, _("illegal block size %d\n"), cfg->blocksize); usage(); } if (cli->sb_feat.crcs_enabled && cfg->blocksize < XFS_MIN_CRC_BLOCKSIZE) { fprintf(stderr, _("Minimum block size for CRC enabled filesystems is %d bytes.\n"), XFS_MIN_CRC_BLOCKSIZE); usage(); } } /* * Grab log sector size and validate. * * XXX: should we probe sector size on external log device rather than using * the data device sector size? */ static void validate_log_sectorsize( struct mkfs_params *cfg, struct cli_params *cli, struct mkfs_default_params *dft) { if (cli->loginternal && cli->lsectorsize && cli->lsectorsize != cfg->sectorsize) { fprintf(stderr, _("Can't change sector size on internal log!\n")); usage(); } if (cli->lsectorsize) cfg->lsectorsize = cli->lsectorsize; else if (cli->loginternal) cfg->lsectorsize = cfg->sectorsize; else cfg->lsectorsize = dft->sectorsize; cfg->lsectorlog = libxfs_highbit32(cfg->lsectorsize); if (cfg->lsectorsize < XFS_MIN_SECTORSIZE || cfg->lsectorsize > XFS_MAX_SECTORSIZE || cfg->lsectorsize > cfg->blocksize) { fprintf(stderr, _("illegal log sector size %d\n"), cfg->lsectorsize); usage(); } if (cfg->lsectorsize > XFS_MIN_SECTORSIZE) { if (cli->sb_feat.log_version < 2) { /* user specified non-default log version */ fprintf(stderr, _("Version 1 logs do not support sector size %d\n"), cfg->lsectorsize); usage(); } } /* if lsu or lsunit was specified, automatically use v2 logs */ if ((cli_opt_set(&lopts, L_SU) || cli_opt_set(&lopts, L_SUNIT)) && cli->sb_feat.log_version == 1) { fprintf(stderr, _("log stripe unit specified, using v2 logs\n")); cli->sb_feat.log_version = 2; } } /* * Check that the incoming features make sense. The CLI structure was * initialised with the default values before parsing, so we can just * check it and copy it straight across to the cfg structure if it * checks out. */ static void validate_sb_features( struct mkfs_params *cfg, struct cli_params *cli) { /* * Now we have blocks and sector sizes set up, check parameters that are * no longer optional for CRC enabled filesystems. Catch them up front * here before doing anything else. */ if (cli->sb_feat.crcs_enabled) { /* minimum inode size is 512 bytes, rest checked later */ if (cli->inodesize && cli->inodesize < (1 << XFS_DINODE_DFL_CRC_LOG)) { fprintf(stderr, _("Minimum inode size for CRCs is %d bytes\n"), 1 << XFS_DINODE_DFL_CRC_LOG); usage(); } /* inodes always aligned */ if (!cli->sb_feat.inode_align) { fprintf(stderr, _("Inodes always aligned for CRC enabled filesystems\n")); usage(); } /* lazy sb counters always on */ if (!cli->sb_feat.lazy_sb_counters) { fprintf(stderr, _("Lazy superblock counters always enabled for CRC enabled filesystems\n")); usage(); } /* version 2 logs always on */ if (cli->sb_feat.log_version != 2) { fprintf(stderr, _("V2 logs always enabled for CRC enabled filesystems\n")); usage(); } /* attr2 always on */ if (cli->sb_feat.attr_version != 2) { fprintf(stderr, _("V2 attribute format always enabled on CRC enabled filesystems\n")); usage(); } /* 32 bit project quota always on */ /* attr2 always on */ if (!cli->sb_feat.projid32bit) { fprintf(stderr, _("32 bit Project IDs always enabled on CRC enabled filesystems\n")); usage(); } /* ftype always on */ if (!cli->sb_feat.dirftype) { fprintf(stderr, _("Directory ftype field always enabled on CRC enabled filesystems\n")); usage(); } } else { /* !crcs_enabled */ /* * The kernel doesn't support crc=0,finobt=1 filesystems. * If crcs are not enabled and the user has not explicitly * turned finobt on, then silently turn it off to avoid an * unnecessary warning. * If the user explicitly tried to use crc=0,finobt=1, * then issue an error. * The same is also true for sparse inodes and reflink. */ if (cli->sb_feat.finobt && cli_opt_set(&mopts, M_FINOBT)) { fprintf(stderr, _("finobt not supported without CRC support\n")); usage(); } cli->sb_feat.finobt = false; if (cli->sb_feat.spinodes && cli_opt_set(&iopts, I_SPINODES)) { fprintf(stderr, _("sparse inodes not supported without CRC support\n")); usage(); } cli->sb_feat.spinodes = false; if (cli->sb_feat.rmapbt) { fprintf(stderr, _("rmapbt not supported without CRC support\n")); usage(); } cli->sb_feat.rmapbt = false; if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) { fprintf(stderr, _("reflink not supported without CRC support\n")); usage(); } cli->sb_feat.reflink = false; } if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) && !cli->sb_feat.reflink) { fprintf(stderr, _("cowextsize not supported without reflink support\n")); usage(); } if (cli->sb_feat.reflink && cli->xi->rtname) { fprintf(stderr, _("reflink not supported with realtime devices\n")); usage(); cli->sb_feat.reflink = false; } if (cli->sb_feat.rmapbt && cli->xi->rtname) { fprintf(stderr, _("rmapbt not supported with realtime devices\n")); usage(); cli->sb_feat.rmapbt = false; } /* * Copy features across to config structure now. */ cfg->sb_feat = cli->sb_feat; if (!platform_uuid_is_null(&cli->uuid)) platform_uuid_copy(&cfg->uuid, &cli->uuid); } static void validate_dirblocksize( struct mkfs_params *cfg, struct cli_params *cli) { if (cli->dirblocksize) cfg->dirblocksize = getnum(cli->dirblocksize, &nopts, N_SIZE); if (cfg->dirblocksize) { if (cfg->dirblocksize < cfg->blocksize || cfg->dirblocksize > XFS_MAX_BLOCKSIZE) { fprintf(stderr, _("illegal directory block size %d\n"), cfg->dirblocksize); usage(); } cfg->dirblocklog = libxfs_highbit32(cfg->dirblocksize); return; } /* use default size based on current block size */ if (cfg->blocksize < (1 << XFS_MIN_REC_DIRSIZE)) cfg->dirblocklog = XFS_MIN_REC_DIRSIZE; else cfg->dirblocklog = cfg->blocklog; cfg->dirblocksize = 1 << cfg->dirblocklog; } static void validate_inodesize( struct mkfs_params *cfg, struct cli_params *cli) { if (cli->inopblock) cfg->inodelog = cfg->blocklog - libxfs_highbit32(cli->inopblock); else if (cli->inodesize) cfg->inodelog = libxfs_highbit32(cli->inodesize); else if (cfg->sb_feat.crcs_enabled) cfg->inodelog = XFS_DINODE_DFL_CRC_LOG; else cfg->inodelog = XFS_DINODE_DFL_LOG; cfg->inodesize = 1 << cfg->inodelog; cfg->inopblock = cfg->blocksize / cfg->inodesize; /* input parsing has already validated non-crc inode size range */ if (cfg->sb_feat.crcs_enabled && cfg->inodelog < XFS_DINODE_DFL_CRC_LOG) { fprintf(stderr, _("Minimum inode size for CRCs is %d bytes\n"), 1 << XFS_DINODE_DFL_CRC_LOG); usage(); } if (cfg->inodesize > cfg->blocksize / XFS_MIN_INODE_PERBLOCK || cfg->inopblock < XFS_MIN_INODE_PERBLOCK || cfg->inodesize < XFS_DINODE_MIN_SIZE || cfg->inodesize > XFS_DINODE_MAX_SIZE) { int maxsz; fprintf(stderr, _("illegal inode size %d\n"), cfg->inodesize); maxsz = min(cfg->blocksize / XFS_MIN_INODE_PERBLOCK, XFS_DINODE_MAX_SIZE); if (XFS_DINODE_MIN_SIZE == maxsz) fprintf(stderr, _("allowable inode size with %d byte blocks is %d\n"), cfg->blocksize, XFS_DINODE_MIN_SIZE); else fprintf(stderr, _("allowable inode size with %d byte blocks is between %d and %d\n"), cfg->blocksize, XFS_DINODE_MIN_SIZE, maxsz); exit(1); } } static xfs_rfsblock_t calc_dev_size( char *size, struct mkfs_params *cfg, struct opt_params *opts, int sizeopt, char *type) { uint64_t dbytes; xfs_rfsblock_t dblocks; if (!size) return 0; dbytes = getnum(size, opts, sizeopt); if (dbytes % XFS_MIN_BLOCKSIZE) { fprintf(stderr, _("illegal %s length %lld, not a multiple of %d\n"), type, (long long)dbytes, XFS_MIN_BLOCKSIZE); usage(); } dblocks = (xfs_rfsblock_t)(dbytes >> cfg->blocklog); if (dbytes % cfg->blocksize) { fprintf(stderr, _("warning: %s length %lld not a multiple of %d, truncated to %lld\n"), type, (long long)dbytes, cfg->blocksize, (long long)(dblocks << cfg->blocklog)); } return dblocks; } static void validate_rtextsize( struct mkfs_params *cfg, struct cli_params *cli, struct fs_topology *ft) { uint64_t rtextbytes; /* * If specified, check rt extent size against its constraints. */ if (cli->rtextsize) { rtextbytes = getnum(cli->rtextsize, &ropts, R_EXTSIZE); if (rtextbytes % cfg->blocksize) { fprintf(stderr, _("illegal rt extent size %lld, not a multiple of %d\n"), (long long)rtextbytes, cfg->blocksize); usage(); } cfg->rtextblocks = (xfs_extlen_t)(rtextbytes >> cfg->blocklog); } else { /* * If realtime extsize has not been specified by the user, * and the underlying volume is striped, then set rtextblocks * to the stripe width. */ uint64_t rswidth; if (!cfg->sb_feat.nortalign && !cli->xi->risfile && !(!cli->rtsize && cli->xi->disfile)) rswidth = ft->rtswidth; else rswidth = 0; /* check that rswidth is a multiple of fs blocksize */ if (!cfg->sb_feat.nortalign && rswidth && !(BBTOB(rswidth) % cfg->blocksize)) { rswidth = DTOBT(rswidth, cfg->blocklog); rtextbytes = rswidth << cfg->blocklog; if (rtextbytes > XFS_MIN_RTEXTSIZE && rtextbytes <= XFS_MAX_RTEXTSIZE) { cfg->rtextblocks = rswidth; } } if (!cfg->rtextblocks) { cfg->rtextblocks = (cfg->blocksize < XFS_MIN_RTEXTSIZE) ? XFS_MIN_RTEXTSIZE >> cfg->blocklog : 1; } } ASSERT(cfg->rtextblocks); } /* Validate the incoming extsize hint. */ static void validate_extsize_hint( struct xfs_mount *mp, struct cli_params *cli) { xfs_failaddr_t fa; uint16_t flags = 0; /* * First we validate the extent size inherit hint on a directory so * that we know that we'll be propagating a correct hint and flag to * new files on the data device. */ if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT) flags |= XFS_DIFLAG_EXTSZINHERIT; fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFDIR, flags); if (fa) { fprintf(stderr, _("illegal extent size hint %lld, must be less than %u.\n"), (long long)cli->fsx.fsx_extsize, min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2)); usage(); } /* * Now we do it again with a realtime file so that we know the hint and * flag that get passed on to realtime files will be correct. */ if (mp->m_sb.sb_rextsize == 0) return; flags = XFS_DIFLAG_REALTIME; if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT) flags |= XFS_DIFLAG_EXTSIZE; fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFREG, flags); if (fa) { fprintf(stderr, _("illegal extent size hint %lld, must be less than %u and a multiple of %u.\n"), (long long)cli->fsx.fsx_extsize, min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2), mp->m_sb.sb_rextsize); usage(); } } /* Validate the incoming CoW extsize hint. */ static void validate_cowextsize_hint( struct xfs_mount *mp, struct cli_params *cli) { xfs_failaddr_t fa; uint64_t flags2 = 0; /* * Validate the copy on write extent size inherit hint on a directory * so that we know that we'll be propagating a correct hint and flag to * new files on the data device. */ if (cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) flags2 |= XFS_DIFLAG2_COWEXTSIZE; fa = libxfs_inode_validate_cowextsize(mp, cli->fsx.fsx_cowextsize, S_IFDIR, 0, flags2); if (fa) { fprintf(stderr, _("illegal CoW extent size hint %lld, must be less than %u.\n"), (long long)cli->fsx.fsx_cowextsize, min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2)); usage(); } } /* * Validate the configured stripe geometry, or is none is specified, pull * the configuration from the underlying device. * * CLI parameters come in as different units, go out as filesystem blocks. */ static void calc_stripe_factors( struct mkfs_params *cfg, struct cli_params *cli, struct fs_topology *ft) { long long int big_dswidth; int dsunit = 0; int dswidth = 0; int lsunit = 0; int dsu = 0; int dsw = 0; int lsu = 0; bool use_dev = false; if (cli_opt_set(&dopts, D_SUNIT)) dsunit = cli->dsunit; if (cli_opt_set(&dopts, D_SWIDTH)) dswidth = cli->dswidth; if (cli_opt_set(&dopts, D_SU)) dsu = getnum(cli->dsu, &dopts, D_SU); if (cli_opt_set(&dopts, D_SW)) dsw = cli->dsw; /* data sunit/swidth options */ if (cli_opt_set(&dopts, D_SUNIT) != cli_opt_set(&dopts, D_SWIDTH)) { fprintf(stderr, _("both data sunit and data swidth options must be specified\n")); usage(); } /* convert dsu/dsw to dsunit/dswidth and use them from now on */ if (dsu || dsw) { if (cli_opt_set(&dopts, D_SU) != cli_opt_set(&dopts, D_SW)) { fprintf(stderr, _("both data su and data sw options must be specified\n")); usage(); } if (dsu % cfg->sectorsize) { fprintf(stderr, _("data su must be a multiple of the sector size (%d)\n"), cfg->sectorsize); usage(); } dsunit = (int)BTOBBT(dsu); big_dswidth = (long long int)dsunit * dsw; if (big_dswidth > INT_MAX) { fprintf(stderr, _("data stripe width (%lld) is too large of a multiple of the data stripe unit (%d)\n"), big_dswidth, dsunit); usage(); } dswidth = big_dswidth; } if ((dsunit && !dswidth) || (!dsunit && dswidth) || (dsunit && (dswidth % dsunit != 0))) { fprintf(stderr, _("data stripe width (%d) must be a multiple of the data stripe unit (%d)\n"), dswidth, dsunit); usage(); } /* If sunit & swidth were manually specified as 0, same as noalign */ if ((cli_opt_set(&dopts, D_SUNIT) || cli_opt_set(&dopts, D_SU)) && !dsunit && !dswidth) cfg->sb_feat.nodalign = true; /* if we are not using alignment, don't apply device defaults */ if (cfg->sb_feat.nodalign) { cfg->dsunit = 0; cfg->dswidth = 0; goto check_lsunit; } /* if no stripe config set, use the device default */ if (!dsunit) { /* Ignore nonsense from device. XXX add more validation */ if (ft->dsunit && ft->dswidth == 0) { fprintf(stderr, _("%s: Volume reports stripe unit of %d bytes and stripe width of 0, ignoring.\n"), progname, BBTOB(ft->dsunit)); ft->dsunit = 0; ft->dswidth = 0; } else { dsunit = ft->dsunit; dswidth = ft->dswidth; use_dev = true; } } else { /* check and warn if user-specified alignment is sub-optimal */ if (ft->dsunit && ft->dsunit != dsunit) { fprintf(stderr, _("%s: Specified data stripe unit %d is not the same as the volume stripe unit %d\n"), progname, dsunit, ft->dsunit); } if (ft->dswidth && ft->dswidth != dswidth) { fprintf(stderr, _("%s: Specified data stripe width %d is not the same as the volume stripe width %d\n"), progname, dswidth, ft->dswidth); } } /* * now we have our stripe config, check it's a multiple of block * size. */ if ((BBTOB(dsunit) % cfg->blocksize) || (BBTOB(dswidth) % cfg->blocksize)) { /* * If we are using device defaults, just clear them and we're * good to go. Otherwise bail out with an error. */ if (!use_dev) { fprintf(stderr, _("%s: Stripe unit(%d) or stripe width(%d) is not a multiple of the block size(%d)\n"), progname, BBTOB(dsunit), BBTOB(dswidth), cfg->blocksize); exit(1); } dsunit = 0; dswidth = 0; cfg->sb_feat.nodalign = true; } /* convert from 512 byte blocks to fs blocksize */ cfg->dsunit = DTOBT(dsunit, cfg->blocklog); cfg->dswidth = DTOBT(dswidth, cfg->blocklog); check_lsunit: /* log sunit options */ if (cli_opt_set(&lopts, L_SUNIT)) lsunit = cli->lsunit; else if (cli_opt_set(&lopts, L_SU)) lsu = getnum(cli->lsu, &lopts, L_SU); else if (cfg->lsectorsize > XLOG_HEADER_SIZE) lsu = cfg->blocksize; /* lsunit matches filesystem block size */ if (lsu) { /* verify if lsu is a multiple block size */ if (lsu % cfg->blocksize != 0) { fprintf(stderr, _("log stripe unit (%d) must be a multiple of the block size (%d)\n"), lsu, cfg->blocksize); usage(); } lsunit = (int)BTOBBT(lsu); } if (BBTOB(lsunit) % cfg->blocksize != 0) { fprintf(stderr, _("log stripe unit (%d) must be a multiple of the block size (%d)\n"), BBTOB(lsunit), cfg->blocksize); usage(); } /* * check that log sunit is modulo fsblksize or default it to dsunit. */ if (lsunit) { /* convert from 512 byte blocks to fs blocks */ cfg->lsunit = DTOBT(lsunit, cfg->blocklog); } else if (cfg->sb_feat.log_version == 2 && cfg->loginternal && cfg->dsunit) { /* lsunit and dsunit now in fs blocks */ cfg->lsunit = cfg->dsunit; } if (cfg->sb_feat.log_version == 2 && cfg->lsunit * cfg->blocksize > 256 * 1024) { /* Warn only if specified on commandline */ if (cli->lsu || cli->lsunit != -1) { fprintf(stderr, _("log stripe unit (%d bytes) is too large (maximum is 256KiB)\n" "log stripe unit adjusted to 32KiB\n"), (cfg->lsunit * cfg->blocksize)); } /* XXX: 64k block size? */ cfg->lsunit = (32 * 1024) / cfg->blocksize; } } static void open_devices( struct mkfs_params *cfg, struct libxfs_xinit *xi) { uint64_t sector_mask; /* * Initialize. This will open the log and rt devices as well. */ xi->setblksize = cfg->sectorsize; if (!libxfs_init(xi)) usage(); if (!xi->ddev) { fprintf(stderr, _("no device name given in argument list\n")); usage(); } /* * Ok, Linux only has a 1024-byte resolution on device _size_, * and the sizes below are in basic 512-byte blocks, * so if we have (size % 2), on any partition, we can't get * to the last 512 bytes. The same issue exists for larger * sector sizes - we cannot write past the last sector. * * So, we reduce the size (in basic blocks) to a perfect * multiple of the sector size, or 1024, whichever is larger. */ sector_mask = (uint64_t)-1 << (max(cfg->sectorlog, 10) - BBSHIFT); xi->dsize &= sector_mask; xi->rtsize &= sector_mask; xi->logBBsize &= (uint64_t)-1 << (max(cfg->lsectorlog, 10) - BBSHIFT); } static void discard_devices( struct libxfs_xinit *xi) { /* * This function has to be called after libxfs has been initialized. */ if (!xi->disfile) discard_blocks(xi->ddev, xi->dsize); if (xi->rtdev && !xi->risfile) discard_blocks(xi->rtdev, xi->rtsize); if (xi->logdev && xi->logdev != xi->ddev && !xi->lisfile) discard_blocks(xi->logdev, xi->logBBsize); } static void validate_datadev( struct mkfs_params *cfg, struct cli_params *cli) { struct libxfs_xinit *xi = cli->xi; if (!xi->dsize) { /* * if the device is a file, we can't validate the size here. * Instead, the file will be truncated to the correct length * later on. if it's not a file, we've got a dud device. */ if (!xi->disfile) { fprintf(stderr, _("can't get size of data subvolume\n")); usage(); } ASSERT(cfg->dblocks); } else if (cfg->dblocks) { /* check the size fits into the underlying device */ if (cfg->dblocks > DTOBT(xi->dsize, cfg->blocklog)) { fprintf(stderr, _("size %s specified for data subvolume is too large, maximum is %lld blocks\n"), cli->dsize, (long long)DTOBT(xi->dsize, cfg->blocklog)); usage(); } } else { /* no user size, so use the full block device */ cfg->dblocks = DTOBT(xi->dsize, cfg->blocklog); } if (cfg->dblocks < XFS_MIN_DATA_BLOCKS) { fprintf(stderr, _("size %lld of data subvolume is too small, minimum %d blocks\n"), (long long)cfg->dblocks, XFS_MIN_DATA_BLOCKS); usage(); } if (xi->dbsize > cfg->sectorsize) { fprintf(stderr, _( "Warning: the data subvolume sector size %u is less than the sector size \n\ reported by the device (%u).\n"), cfg->sectorsize, xi->dbsize); } } /* * This is more complex than it needs to be because we still support volume * based external logs. They are only discovered *after* the devices have been * opened, hence the crazy "is this really an internal log" checks here. */ static void validate_logdev( struct mkfs_params *cfg, struct cli_params *cli, char **devname) { struct libxfs_xinit *xi = cli->xi; *devname = NULL; /* check for volume log first */ if (cli->loginternal && xi->volname && xi->logdev) { *devname = _("volume log"); cfg->loginternal = false; } else cfg->loginternal = cli->loginternal; /* now run device checks */ if (cfg->loginternal) { if (xi->logdev) { fprintf(stderr, _("can't have both external and internal logs\n")); usage(); } /* * if no sector size has been specified on the command line, * use what has been configured and validated for the data * device. */ if (!cli->lsectorsize) { cfg->lsectorsize = cfg->sectorsize; cfg->lsectorlog = cfg->sectorlog; } if (cfg->sectorsize != cfg->lsectorsize) { fprintf(stderr, _("data and log sector sizes must be equal for internal logs\n")); usage(); } if (cli->logsize && cfg->logblocks >= cfg->dblocks) { fprintf(stderr, _("log size %lld too large for internal log\n"), (long long)cfg->logblocks); usage(); } *devname = _("internal log"); return; } /* External/log subvolume checks */ if (xi->logname) *devname = xi->logname; if (!*devname || !xi->logdev) { fprintf(stderr, _("no log subvolume or external log.\n")); usage(); } if (!cfg->logblocks) { if (xi->logBBsize == 0) { fprintf(stderr, _("unable to get size of the log subvolume.\n")); usage(); } cfg->logblocks = DTOBT(xi->logBBsize, cfg->blocklog); } else if (cfg->logblocks > DTOBT(xi->logBBsize, cfg->blocklog)) { fprintf(stderr, _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"), cli->logsize, (long long)DTOBT(xi->logBBsize, cfg->blocklog)); usage(); } if (xi->lbsize > cfg->lsectorsize) { fprintf(stderr, _( "Warning: the log subvolume sector size %u is less than the sector size\n\ reported by the device (%u).\n"), cfg->lsectorsize, xi->lbsize); } } static void validate_rtdev( struct mkfs_params *cfg, struct cli_params *cli, char **devname) { struct libxfs_xinit *xi = cli->xi; *devname = NULL; if (!xi->rtdev) { if (cli->rtsize) { fprintf(stderr, _("size specified for non-existent rt subvolume\n")); usage(); } *devname = _("none"); cfg->rtblocks = 0; cfg->rtextents = 0; cfg->rtbmblocks = 0; return; } if (!xi->rtsize) { fprintf(stderr, _("Invalid zero length rt subvolume found\n")); usage(); } /* volume rtdev */ if (xi->volname) *devname = _("volume rt"); else *devname = xi->rtname; if (cli->rtsize) { if (cfg->rtblocks > DTOBT(xi->rtsize, cfg->blocklog)) { fprintf(stderr, _("size %s specified for rt subvolume is too large, maxi->um is %lld blocks\n"), cli->rtsize, (long long)DTOBT(xi->rtsize, cfg->blocklog)); usage(); } if (xi->rtbsize > cfg->sectorsize) { fprintf(stderr, _( "Warning: the realtime subvolume sector size %u is less than the sector size\n\ reported by the device (%u).\n"), cfg->sectorsize, xi->rtbsize); } } else { /* grab volume size */ cfg->rtblocks = DTOBT(xi->rtsize, cfg->blocklog); } cfg->rtextents = cfg->rtblocks / cfg->rtextblocks; cfg->rtbmblocks = (xfs_extlen_t)howmany(cfg->rtextents, NBBY * cfg->blocksize); } static void calculate_initial_ag_geometry( struct mkfs_params *cfg, struct cli_params *cli) { if (cli->agsize) { /* User-specified AG size */ cfg->agsize = getnum(cli->agsize, &dopts, D_AGSIZE); /* * Check specified agsize is a multiple of blocksize. */ if (cfg->agsize % cfg->blocksize) { fprintf(stderr, _("agsize (%s) not a multiple of fs blk size (%d)\n"), cli->agsize, cfg->blocksize); usage(); } cfg->agsize /= cfg->blocksize; cfg->agcount = cfg->dblocks / cfg->agsize + (cfg->dblocks % cfg->agsize != 0); } else if (cli->agcount) { /* User-specified AG count */ cfg->agcount = cli->agcount; cfg->agsize = cfg->dblocks / cfg->agcount + (cfg->dblocks % cfg->agcount != 0); } else { calc_default_ag_geometry(cfg->blocklog, cfg->dblocks, cfg->dsunit, &cfg->agsize, &cfg->agcount); } } /* * Align the AG size to stripe geometry. If this fails and we are using * discovered stripe geometry, tell the caller to clear the stripe geometry. * Otherwise, set the aligned geometry (valid or invalid!) so that the * validation call will fail and exit. */ static void align_ag_geometry( struct mkfs_params *cfg) { uint64_t tmp_agsize; int dsunit = cfg->dsunit; if (!dsunit) goto validate; /* * agsize is not a multiple of dsunit */ if ((cfg->agsize % dsunit) != 0) { /* * Round up to stripe unit boundary. Also make sure * that agsize is still larger than * XFS_AG_MIN_BLOCKS(blocklog) */ tmp_agsize = ((cfg->agsize + dsunit - 1) / dsunit) * dsunit; /* * Round down to stripe unit boundary if rounding up * created an AG size that is larger than the AG max. */ if (tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog)) tmp_agsize = (cfg->agsize / dsunit) * dsunit; if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog) && tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog)) { /* * If the AG size is invalid and we are using device * probed stripe alignment, just clear the alignment * and continue on. */ if (!cli_opt_set(&dopts, D_SUNIT) && !cli_opt_set(&dopts, D_SU)) { cfg->dsunit = 0; cfg->dswidth = 0; goto validate; } /* * set the agsize to the invalid value so the following * validation of the ag will fail and print a nice error * and exit. */ cfg->agsize = tmp_agsize; goto validate; } /* update geometry to be stripe unit aligned */ cfg->agsize = tmp_agsize; if (!cli_opt_set(&dopts, D_AGCOUNT)) cfg->agcount = cfg->dblocks / cfg->agsize + (cfg->dblocks % cfg->agsize != 0); if (cli_opt_set(&dopts, D_AGSIZE)) fprintf(stderr, _("agsize rounded to %lld, sunit = %d\n"), (long long)cfg->agsize, dsunit); } if ((cfg->agsize % cfg->dswidth) == 0 && cfg->dswidth != cfg->dsunit && cfg->agcount > 1) { if (cli_opt_set(&dopts, D_AGCOUNT) || cli_opt_set(&dopts, D_AGSIZE)) { fprintf(stderr, _( "Warning: AG size is a multiple of stripe width. This can cause performance\n\ problems by aligning all AGs on the same disk. To avoid this, run mkfs with\n\ an AG size that is one stripe unit smaller or larger, for example %llu.\n"), (unsigned long long)cfg->agsize - dsunit); goto validate; } /* * This is a non-optimal configuration because all AGs start on * the same disk in the stripe. Changing the AG size by one * sunit will guarantee that this does not happen. */ tmp_agsize = cfg->agsize - dsunit; if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog)) { tmp_agsize = cfg->agsize + dsunit; if (cfg->dblocks < cfg->agsize) { /* oh well, nothing to do */ tmp_agsize = cfg->agsize; } } cfg->agsize = tmp_agsize; cfg->agcount = cfg->dblocks / cfg->agsize + (cfg->dblocks % cfg->agsize != 0); } validate: /* * If the last AG is too small, reduce the filesystem size * and drop the blocks. */ if (cfg->dblocks % cfg->agsize != 0 && (cfg->dblocks % cfg->agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog))) { ASSERT(!cli_opt_set(&dopts, D_AGCOUNT)); cfg->dblocks = (xfs_rfsblock_t)((cfg->agcount - 1) * cfg->agsize); cfg->agcount--; ASSERT(cfg->agcount != 0); } validate_ag_geometry(cfg->blocklog, cfg->dblocks, cfg->agsize, cfg->agcount); } static void calculate_imaxpct( struct mkfs_params *cfg, struct cli_params *cli) { cfg->imaxpct = cli->imaxpct; if (cfg->imaxpct) return; /* * This returns the % of the disk space that is used for * inodes, it changes relatively to the FS size: * - over 50 TB, use 1%, * - 1TB - 50 TB, use 5%, * - under 1 TB, use XFS_DFL_IMAXIMUM_PCT (25%). */ if (cfg->dblocks < TERABYTES(1, cfg->blocklog)) cfg->imaxpct = XFS_DFL_IMAXIMUM_PCT; else if (cfg->dblocks < TERABYTES(50, cfg->blocklog)) cfg->imaxpct = 5; else cfg->imaxpct = 1; } /* * Set up the initial state of the superblock so we can start using the * libxfs geometry macros. */ static void sb_set_features( struct mkfs_params *cfg, struct xfs_sb *sbp) { struct sb_feat_args *fp = &cfg->sb_feat; sbp->sb_versionnum = XFS_DFL_SB_VERSION_BITS; if (fp->crcs_enabled) sbp->sb_versionnum |= XFS_SB_VERSION_5; else sbp->sb_versionnum |= XFS_SB_VERSION_4; if (fp->inode_align) { int cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; sbp->sb_versionnum |= XFS_SB_VERSION_ALIGNBIT; if (cfg->sb_feat.crcs_enabled) cluster_size *= cfg->inodesize / XFS_DINODE_MIN_SIZE; sbp->sb_inoalignmt = cluster_size >> cfg->blocklog; } else sbp->sb_inoalignmt = 0; if (cfg->dsunit) sbp->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT; if (fp->log_version == 2) sbp->sb_versionnum |= XFS_SB_VERSION_LOGV2BIT; if (fp->attr_version == 1) sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; if (fp->nci) sbp->sb_versionnum |= XFS_SB_VERSION_BORGBIT; if (cfg->sectorsize > BBSIZE || cfg->lsectorsize > BBSIZE) { sbp->sb_versionnum |= XFS_SB_VERSION_SECTORBIT; sbp->sb_logsectlog = (uint8_t)cfg->lsectorlog; sbp->sb_logsectsize = (uint16_t)cfg->lsectorsize; } else { sbp->sb_logsectlog = 0; sbp->sb_logsectsize = 0; } sbp->sb_features2 = 0; if (fp->lazy_sb_counters) sbp->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; if (fp->projid32bit) sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; if (fp->parent_pointers) sbp->sb_features2 |= XFS_SB_VERSION2_PARENTBIT; if (fp->crcs_enabled) sbp->sb_features2 |= XFS_SB_VERSION2_CRCBIT; if (fp->attr_version == 2) sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT; /* v5 superblocks have their own feature bit for dirftype */ if (fp->dirftype && !fp->crcs_enabled) sbp->sb_features2 |= XFS_SB_VERSION2_FTYPE; /* update whether extended features are in use */ if (sbp->sb_features2 != 0) sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; /* * Due to a structure alignment issue, sb_features2 ended up in one * of two locations, the second "incorrect" location represented by * the sb_bad_features2 field. To avoid older kernels mounting * filesystems they shouldn't, set both field to the same value. */ sbp->sb_bad_features2 = sbp->sb_features2; if (!fp->crcs_enabled) return; /* default features for v5 filesystems */ sbp->sb_features_compat = 0; sbp->sb_features_ro_compat = 0; sbp->sb_features_incompat = XFS_SB_FEAT_INCOMPAT_FTYPE; sbp->sb_features_log_incompat = 0; if (fp->finobt) sbp->sb_features_ro_compat = XFS_SB_FEAT_RO_COMPAT_FINOBT; if (fp->rmapbt) sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT; if (fp->reflink) sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK; /* * Sparse inode chunk support has two main inode alignment requirements. * First, sparse chunk alignment must match the cluster size. Second, * full chunk alignment must match the inode chunk size. * * Copy the already calculated/scaled inoalignmt to spino_align and * update the former to the full inode chunk size. */ if (fp->spinodes) { sbp->sb_spino_align = sbp->sb_inoalignmt; sbp->sb_inoalignmt = XFS_INODES_PER_CHUNK * cfg->inodesize >> cfg->blocklog; sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_SPINODES; } } /* * Make sure that the log size is a multiple of the stripe unit */ static void align_log_size( struct mkfs_params *cfg, int sunit) { uint64_t tmp_logblocks; /* nothing to do if it's already aligned. */ if ((cfg->logblocks % sunit) == 0) return; if (cli_opt_set(&lopts, L_SIZE)) { fprintf(stderr, _("log size %lld is not a multiple of the log stripe unit %d\n"), (long long) cfg->logblocks, sunit); usage(); } tmp_logblocks = ((cfg->logblocks + (sunit - 1)) / sunit) * sunit; /* If the log is too large, round down instead of round up */ if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) || ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)) { tmp_logblocks = (cfg->logblocks / sunit) * sunit; } cfg->logblocks = tmp_logblocks; } /* * Make sure that the internal log is correctly aligned to the specified * stripe unit. */ static void align_internal_log( struct mkfs_params *cfg, struct xfs_mount *mp, int sunit) { uint64_t logend; /* round up log start if necessary */ if ((cfg->logstart % sunit) != 0) cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit; /* If our log start overlaps the next AG's metadata, fail. */ if (XFS_FSB_TO_AGBNO(mp, cfg->logstart) <= XFS_AGFL_BLOCK(mp)) { fprintf(stderr, _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" "within an allocation group.\n"), (long long) cfg->logstart); usage(); } /* round up/down the log size now */ align_log_size(cfg, sunit); /* check the aligned log still starts and ends in the same AG. */ logend = cfg->logstart + cfg->logblocks - 1; if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend)) { fprintf(stderr, _("Due to stripe alignment, the internal log size (%lld) is too large.\n" "Must fit within an allocation group.\n"), (long long) cfg->logblocks); usage(); } } static void validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks) { if (logblocks < min_logblocks) { fprintf(stderr, _("log size %lld blocks too small, minimum size is %d blocks\n"), (long long)logblocks, min_logblocks); usage(); } if (logblocks > XFS_MAX_LOG_BLOCKS) { fprintf(stderr, _("log size %lld blocks too large, maximum size is %lld blocks\n"), (long long)logblocks, XFS_MAX_LOG_BLOCKS); usage(); } if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES) { fprintf(stderr, _("log size %lld bytes too large, maximum size is %lld bytes\n"), (long long)(logblocks << blocklog), XFS_MAX_LOG_BYTES); usage(); } } static void calculate_log_size( struct mkfs_params *cfg, struct cli_params *cli, struct xfs_mount *mp) { struct xfs_sb *sbp = &mp->m_sb; int min_logblocks; struct xfs_mount mount; /* we need a temporary mount to calculate the minimum log size. */ memset(&mount, 0, sizeof(mount)); mount.m_sb = *sbp; libxfs_mount(&mount, &mp->m_sb, 0, 0, 0, 0); min_logblocks = libxfs_log_calc_minimum_size(&mount); libxfs_umount(&mount); ASSERT(min_logblocks); min_logblocks = max(XFS_MIN_LOG_BLOCKS, min_logblocks); /* if we have lots of blocks, check against XFS_MIN_LOG_BYTES, too */ if (!cli->logsize && cfg->dblocks >= (1024*1024*1024) >> cfg->blocklog) min_logblocks = max(min_logblocks, XFS_MIN_LOG_BYTES >> cfg->blocklog); /* * external logs will have a device and size by now, so all we have * to do is validate it against minimum size and align it. */ if (!cfg->loginternal) { if (min_logblocks > cfg->logblocks) { fprintf(stderr, _("external log device %lld too small, must be at least %lld blocks\n"), (long long)cfg->logblocks, (long long)min_logblocks); usage(); } cfg->logstart = 0; cfg->logagno = 0; if (cfg->lsunit) align_log_size(cfg, cfg->lsunit); validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); return; } /* internal log - if no size specified, calculate automatically */ if (!cfg->logblocks) { if (cfg->dblocks < GIGABYTES(1, cfg->blocklog)) { /* tiny filesystems get minimum sized logs. */ cfg->logblocks = min_logblocks; } else if (cfg->dblocks < GIGABYTES(16, cfg->blocklog)) { /* * For small filesystems, we want to use the * XFS_MIN_LOG_BYTES for filesystems smaller than 16G if * at all possible, ramping up to 128MB at 256GB. */ cfg->logblocks = min(XFS_MIN_LOG_BYTES >> cfg->blocklog, min_logblocks * XFS_DFL_LOG_FACTOR); } else { /* * With a 2GB max log size, default to maximum size * at 4TB. This keeps the same ratio from the older * max log size of 128M at 256GB fs size. IOWs, * the ratio of fs size to log size is 2048:1. */ cfg->logblocks = (cfg->dblocks << cfg->blocklog) / 2048; cfg->logblocks = cfg->logblocks >> cfg->blocklog; } /* Ensure the chosen size meets minimum log size requirements */ cfg->logblocks = max(min_logblocks, cfg->logblocks); /* * Make sure the log fits wholly within an AG * * XXX: If agf->freeblks ends up as 0 because the log uses all * the free space, it causes the kernel all sorts of problems * with per-ag reservations. Right now just back it off one * block, but there's a whole can of worms here that needs to be * opened to decide what is the valid maximum size of a log in * an AG. */ cfg->logblocks = min(cfg->logblocks, libxfs_alloc_ag_max_usable(mp) - 1); /* and now clamp the size to the maximum supported size */ cfg->logblocks = min(cfg->logblocks, XFS_MAX_LOG_BLOCKS); if ((cfg->logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES) cfg->logblocks = XFS_MAX_LOG_BYTES >> cfg->blocklog; validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); } if (cfg->logblocks > sbp->sb_agblocks - libxfs_prealloc_blocks(mp)) { fprintf(stderr, _("internal log size %lld too large, must fit in allocation group\n"), (long long)cfg->logblocks); usage(); } if (cli_opt_set(&lopts, L_AGNUM)) { if (cli->logagno >= sbp->sb_agcount) { fprintf(stderr, _("log ag number %lld too large, must be less than %lld\n"), (long long)cli->logagno, (long long)sbp->sb_agcount); usage(); } cfg->logagno = cli->logagno; } else cfg->logagno = (xfs_agnumber_t)(sbp->sb_agcount / 2); cfg->logstart = XFS_AGB_TO_FSB(mp, cfg->logagno, libxfs_prealloc_blocks(mp)); /* * Align the logstart at stripe unit boundary. */ if (cfg->lsunit) { align_internal_log(cfg, mp, cfg->lsunit); } else if (cfg->dsunit) { align_internal_log(cfg, mp, cfg->dsunit); } validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); } /* * Set up superblock with the minimum parameters required for * the libxfs macros needed by the log sizing code to run successfully. * This includes a minimum log size calculation, so we need everything * that goes into that calculation to be setup here including feature * flags. */ static void start_superblock_setup( struct mkfs_params *cfg, struct xfs_mount *mp, struct xfs_sb *sbp) { sbp->sb_magicnum = XFS_SB_MAGIC; sbp->sb_sectsize = (uint16_t)cfg->sectorsize; sbp->sb_sectlog = (uint8_t)cfg->sectorlog; sbp->sb_blocksize = cfg->blocksize; sbp->sb_blocklog = (uint8_t)cfg->blocklog; sbp->sb_agblocks = (xfs_agblock_t)cfg->agsize; sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize); sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount; sbp->sb_inodesize = (uint16_t)cfg->inodesize; sbp->sb_inodelog = (uint8_t)cfg->inodelog; sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize); sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog); sbp->sb_dirblklog = cfg->dirblocklog - cfg->blocklog; sb_set_features(cfg, sbp); /* * log stripe unit is stored in bytes on disk and cannot be zero * for v2 logs. */ if (cfg->sb_feat.log_version == 2) { if (cfg->lsunit) sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit); else sbp->sb_logsunit = 1; } else sbp->sb_logsunit = 0; } static void initialise_mount( struct mkfs_params *cfg, struct xfs_mount *mp, struct xfs_sb *sbp) { /* Minimum needed for libxfs_prealloc_blocks() */ mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; } /* * Format everything from the generated config into the superblock that * will be used to initialise the on-disk superblock. This is the in-memory * copy, so no need to care about endian swapping here. */ static void finish_superblock_setup( struct mkfs_params *cfg, struct xfs_mount *mp, struct xfs_sb *sbp) { if (cfg->label) { size_t label_len; /* * Labels are null terminated unless the string fits exactly * in the label field, so assume sb_fname is zeroed and then * do a memcpy because the destination isn't a normal C string. */ label_len = min(sizeof(sbp->sb_fname), strlen(cfg->label)); memcpy(sbp->sb_fname, cfg->label, label_len); } sbp->sb_dblocks = cfg->dblocks; sbp->sb_rblocks = cfg->rtblocks; sbp->sb_rextents = cfg->rtextents; platform_uuid_copy(&sbp->sb_uuid, &cfg->uuid); /* Only in memory; libxfs expects this as if read from disk */ platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid); sbp->sb_logstart = cfg->logstart; sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO; sbp->sb_rextsize = cfg->rtextblocks; sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount; sbp->sb_rbmblocks = cfg->rtbmblocks; sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks; sbp->sb_rextslog = (uint8_t)(cfg->rtextents ? libxfs_highbit32((unsigned int)cfg->rtextents) : 0); sbp->sb_inprogress = 1; /* mkfs is in progress */ sbp->sb_imax_pct = cfg->imaxpct; sbp->sb_icount = 0; sbp->sb_ifree = 0; sbp->sb_fdblocks = cfg->dblocks - cfg->agcount * libxfs_prealloc_blocks(mp) - (cfg->loginternal ? cfg->logblocks : 0); sbp->sb_frextents = 0; /* will do a free later */ sbp->sb_uquotino = sbp->sb_gquotino = sbp->sb_pquotino = 0; sbp->sb_qflags = 0; sbp->sb_unit = cfg->dsunit; sbp->sb_width = cfg->dswidth; } /* * Sanitise the data and log devices and prepare them so libxfs can mount the * device successfully. Also check we can access the rt device if configured. */ static void prepare_devices( struct mkfs_params *cfg, struct libxfs_xinit *xi, struct xfs_mount *mp, struct xfs_sb *sbp, bool clear_stale) { struct xfs_buf *buf; int whack_blks = BTOBB(WHACK_SIZE); int lsunit; /* * If there's an old XFS filesystem on the device with enough intact * information that we can parse the superblock, there's enough * information on disk to confuse a future xfs_repair call. To avoid * this, whack all the old secondary superblocks that we can find. */ if (clear_stale) zero_old_xfs_structures(xi, sbp); /* * If the data device is a file, grow out the file to its final size if * needed so that the reads for the end of the device in the mount code * will succeed. */ if (xi->disfile && xi->dsize * xi->dbsize < cfg->dblocks * cfg->blocksize) { if (ftruncate(xi->dfd, cfg->dblocks * cfg->blocksize) < 0) { fprintf(stderr, _("%s: Growing the data section failed\n"), progname); exit(1); } /* update size to be able to whack blocks correctly */ xi->dsize = BTOBB(cfg->dblocks * cfg->blocksize); } /* * Zero out the end to obliterate any old MD RAID (or other) metadata at * the end of the device. (MD sb is ~64k from the end, take out a wider * swath to be sure) */ buf = libxfs_getbuf(mp->m_ddev_targp, (xi->dsize - whack_blks), whack_blks); memset(buf->b_addr, 0, WHACK_SIZE); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); libxfs_purgebuf(buf); /* * Now zero out the beginning of the device, to obliterate any old * filesystem signatures out there. This should take care of * swap (somewhere around the page size), jfs (32k), * ext[2,3] and reiserfs (64k) - and hopefully all else. */ buf = libxfs_getbuf(mp->m_ddev_targp, 0, whack_blks); memset(buf->b_addr, 0, WHACK_SIZE); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); libxfs_purgebuf(buf); /* OK, now write the superblock... */ buf = libxfs_getbuf(mp->m_ddev_targp, XFS_SB_DADDR, XFS_FSS_TO_BB(mp, 1)); buf->b_ops = &xfs_sb_buf_ops; memset(buf->b_addr, 0, cfg->sectorsize); libxfs_sb_to_disk(buf->b_addr, sbp); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); libxfs_purgebuf(buf); /* ...and zero the log.... */ lsunit = sbp->sb_logsunit; if (lsunit == 1) lsunit = sbp->sb_logsectsize; libxfs_log_clear(mp->m_logdev_targp, NULL, XFS_FSB_TO_DADDR(mp, cfg->logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, cfg->logblocks), &sbp->sb_uuid, cfg->sb_feat.log_version, lsunit, XLOG_FMT, XLOG_INIT_CYCLE, false); /* finally, check we can write the last block in the realtime area */ if (mp->m_rtdev_targp->dev && cfg->rtblocks > 0) { buf = libxfs_getbuf(mp->m_rtdev_targp, XFS_FSB_TO_BB(mp, cfg->rtblocks - 1LL), BTOBB(cfg->blocksize)); memset(buf->b_addr, 0, cfg->blocksize); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); libxfs_purgebuf(buf); } } /* * XXX: this code is mostly common with the kernel growfs code. * These initialisations should be pulled into libxfs to keep the * kernel/userspace header initialisation code the same. */ static void initialise_ag_headers( struct mkfs_params *cfg, struct xfs_mount *mp, struct xfs_sb *sbp, xfs_agnumber_t agno, int *worst_freelist, struct list_head *buffer_list) { struct aghdr_init_data id = { .agno = agno, .agsize = cfg->agsize, }; struct xfs_perag *pag = libxfs_perag_get(mp, agno); int error; if (agno == cfg->agcount - 1) id.agsize = cfg->dblocks - (xfs_rfsblock_t)(agno * cfg->agsize); INIT_LIST_HEAD(&id.buffer_list); error = -libxfs_ag_init_headers(mp, &id); if (error) { fprintf(stderr, _("AG header init failed, error %d\n"), error); exit(1); } list_splice_tail_init(&id.buffer_list, buffer_list); if (libxfs_alloc_min_freelist(mp, pag) > *worst_freelist) *worst_freelist = libxfs_alloc_min_freelist(mp, pag); libxfs_perag_put(pag); } static void initialise_ag_freespace( struct xfs_mount *mp, xfs_agnumber_t agno, int worst_freelist) { struct xfs_alloc_arg args; struct xfs_trans *tp; int c; c = -libxfs_trans_alloc_rollable(mp, worst_freelist, &tp); if (c) res_failed(c); memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = mp; args.agno = agno; args.alignment = 1; args.pag = libxfs_perag_get(mp, agno); libxfs_alloc_fix_freelist(&args, 0); libxfs_perag_put(args.pag); c = -libxfs_trans_commit(tp); if (c) { errno = c; perror(_("initializing AG free space list")); exit(1); } } /* * rewrite several secondary superblocks with the root inode number filled out. * This can help repair recovery from a trashed primary superblock without * losing the root inode. */ static void rewrite_secondary_superblocks( struct xfs_mount *mp) { struct xfs_buf *buf; /* rewrite the last superblock */ buf = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, mp->m_sb.sb_agcount - 1, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), LIBXFS_EXIT_ON_FAILURE, &xfs_sb_buf_ops); XFS_BUF_TO_SBP(buf)->sb_rootino = cpu_to_be64(mp->m_sb.sb_rootino); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); /* and one in the middle for luck if there's enough AGs for that */ if (mp->m_sb.sb_agcount <= 2) return; buf = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, (mp->m_sb.sb_agcount - 1) / 2, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), LIBXFS_EXIT_ON_FAILURE, &xfs_sb_buf_ops); XFS_BUF_TO_SBP(buf)->sb_rootino = cpu_to_be64(mp->m_sb.sb_rootino); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); } int main( int argc, char **argv) { xfs_agnumber_t agno; xfs_buf_t *buf; int c; char *dfile = NULL; char *logfile = NULL; char *rtfile = NULL; int dry_run = 0; int discard = 1; int force_overwrite = 0; int quiet = 0; char *protofile = NULL; char *protostring = NULL; int worst_freelist = 0; struct libxfs_xinit xi = { .isdirect = LIBXFS_DIRECT, .isreadonly = LIBXFS_EXCLUSIVELY, }; struct xfs_mount mbuf = {}; struct xfs_mount *mp = &mbuf; struct xfs_sb *sbp = &mp->m_sb; struct fs_topology ft = {}; struct cli_params cli = { .xi = &xi, .loginternal = 1, }; struct mkfs_params cfg = {}; /* build time defaults */ struct mkfs_default_params dft = { .source = _("package build definitions"), .sectorsize = XFS_MIN_SECTORSIZE, .blocksize = 1 << XFS_DFL_BLOCKSIZE_LOG, .sb_feat = { .log_version = 2, .attr_version = 2, .dir_version = 2, .inode_align = true, .nci = false, .lazy_sb_counters = true, .projid32bit = true, .crcs_enabled = true, .dirftype = true, .finobt = true, .spinodes = true, .rmapbt = false, .reflink = true, .parent_pointers = false, .nodalign = false, .nortalign = false, }, }; struct list_head buffer_list; platform_uuid_generate(&cli.uuid); progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); /* * TODO: Sourcing defaults from a config file * * Before anything else, see if there's a config file with different * defaults. If a file exists in , read in the new * default values and overwrite them in the &dft structure. This way the * new defaults will apply before we parse the CLI, and the CLI will * still be able to override them. When more than one source is * implemented, emit a message to indicate where the defaults being * used came from. * * printf(_("Default configuration sourced from %s\n"), dft.source); */ /* copy new defaults into CLI parsing structure */ memcpy(&cli.sb_feat, &dft.sb_feat, sizeof(cli.sb_feat)); memcpy(&cli.fsx, &dft.fsx, sizeof(cli.fsx)); while ((c = getopt(argc, argv, "b:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) { switch (c) { case 'C': case 'f': force_overwrite = 1; break; case 'b': case 'd': case 'i': case 'l': case 'm': case 'n': case 'r': case 's': parse_subopts(c, optarg, &cli); break; case 'L': if (strlen(optarg) > sizeof(sbp->sb_fname)) illegal(optarg, "L"); cfg.label = optarg; break; case 'N': dry_run = 1; break; case 'K': discard = 0; break; case 'p': if (protofile) respec('p', NULL, 0); protofile = optarg; break; case 'q': quiet = 1; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); case '?': unknown(optopt, ""); } } if (argc - optind > 1) { fprintf(stderr, _("extra arguments\n")); usage(); } else if (argc - optind == 1) { dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME); } else dfile = xi.dname; protostring = setup_proto(protofile); /* * Extract as much of the valid config as we can from the CLI input * before opening the libxfs devices. */ validate_blocksize(&cfg, &cli, &dft); validate_sectorsize(&cfg, &cli, &dft, &ft, dfile, dry_run, force_overwrite); /* * XXX: we still need to set block size and sector size global variables * so that getnum/cvtnum works correctly */ blocksize = cfg.blocksize; sectorsize = cfg.sectorsize; validate_log_sectorsize(&cfg, &cli, &dft); validate_sb_features(&cfg, &cli); /* * we've now completed basic validation of the features, sector and * block sizes, so from this point onwards we use the values found in * the cfg structure for them, not the command line structure. */ validate_dirblocksize(&cfg, &cli); validate_inodesize(&cfg, &cli); /* * if the device size was specified convert it to a block count * now we have a valid block size. These will be set to zero if * nothing was specified, indicating we should use the full device. */ cfg.dblocks = calc_dev_size(cli.dsize, &cfg, &dopts, D_SIZE, "data"); cfg.logblocks = calc_dev_size(cli.logsize, &cfg, &lopts, L_SIZE, "log"); cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt"); validate_rtextsize(&cfg, &cli, &ft); /* * Open and validate the device configurations */ open_devices(&cfg, &xi); validate_overwrite(dfile, force_overwrite); validate_datadev(&cfg, &cli); validate_logdev(&cfg, &cli, &logfile); validate_rtdev(&cfg, &cli, &rtfile); calc_stripe_factors(&cfg, &cli, &ft); /* * At this point when know exactly what size all the devices are, * so we can start validating and calculating layout options that are * dependent on device sizes. Once calculated, make sure everything * aligns to device geometry correctly. */ calculate_initial_ag_geometry(&cfg, &cli); align_ag_geometry(&cfg); calculate_imaxpct(&cfg, &cli); /* * Set up the basic superblock parameters now so that we can use * the geometry information we've already validated in libxfs * provided functions to determine on-disk format information. */ start_superblock_setup(&cfg, mp, sbp); initialise_mount(&cfg, mp, sbp); /* * With the mount set up, we can finally calculate the log size * constraints and do default size calculations and final validation */ calculate_log_size(&cfg, &cli, mp); finish_superblock_setup(&cfg, mp, sbp); /* Validate the extent size hints now that @mp is fully set up. */ validate_extsize_hint(mp, &cli); validate_cowextsize_hint(mp, &cli); /* Print the intended geometry of the fs. */ if (!quiet || dry_run) { struct xfs_fsop_geom geo; libxfs_fs_geometry(sbp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER); xfs_report_geom(&geo, dfile, logfile, rtfile); if (dry_run) exit(0); } /* * All values have been validated, discard the old device layout. */ if (discard && !dry_run) discard_devices(&xi); /* * we need the libxfs buffer cache from here on in. */ libxfs_buftarg_init(mp, xi.ddev, xi.logdev, xi.rtdev); /* * Before we mount the filesystem we need to make sure the devices have * enough of the filesystem structure on them that allows libxfs to * mount. */ prepare_devices(&cfg, &xi, mp, sbp, force_overwrite); mp = libxfs_mount(mp, sbp, xi.ddev, xi.logdev, xi.rtdev, 0); if (mp == NULL) { fprintf(stderr, _("%s: filesystem failed to initialize\n"), progname); exit(1); } /* * Initialise all the static on disk metadata. */ INIT_LIST_HEAD(&buffer_list); for (agno = 0; agno < cfg.agcount; agno++) { initialise_ag_headers(&cfg, mp, sbp, agno, &worst_freelist, &buffer_list); if (agno % 16) continue; if (libxfs_buf_delwri_submit(&buffer_list)) { fprintf(stderr, _("%s: writing AG headers failed\n"), progname); exit(1); } } if (libxfs_buf_delwri_submit(&buffer_list)) { fprintf(stderr, _("%s: writing AG headers failed\n"), progname); exit(1); } /* * Initialise the freespace freelists (i.e. AGFLs) in each AG. */ for (agno = 0; agno < cfg.agcount; agno++) initialise_ag_freespace(mp, agno, worst_freelist); /* * Allocate the root inode and anything else in the proto file. */ parse_proto(mp, &cli.fsx, &protostring); /* * Protect ourselves against possible stupidity */ if (XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino) != 0) { fprintf(stderr, _("%s: root inode created in AG %u, not AG 0\n"), progname, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino)); exit(1); } /* * Re-write multiple secondary superblocks with rootinode field set */ if (mp->m_sb.sb_agcount > 1) rewrite_secondary_superblocks(mp); /* * Dump all inodes and buffers before marking us all done. * Need to drop references to inodes we still hold, first. */ libxfs_rtmount_destroy(mp); libxfs_bcache_purge(); /* * Mark the filesystem ok. */ buf = libxfs_getsb(mp); if (!buf || buf->b_error) exit(1); (XFS_BUF_TO_SBP(buf))->sb_inprogress = 0; libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); libxfs_umount(mp); if (xi.rtdev) libxfs_device_close(xi.rtdev); if (xi.logdev && xi.logdev != xi.ddev) libxfs_device_close(xi.logdev); libxfs_device_close(xi.ddev); libxfs_destroy(); return 0; } xfsprogs-5.3.0/po/Makefile0000644000175000017500000000114613435336037015333 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs POTHEAD = $(PKG_NAME).pot # If the user has requested a specific set of translations, only build those. SUPPORTED_LINGUAS = $(patsubst %.po,%,$(wildcard *.po)) LINGUAS ?= $(SUPPORTED_LINGUAS) LINGUAS := $(filter $(SUPPORTED_LINGUAS),$(LINGUAS)) LSRCFILES = $(LINGUAS:%=%.po) LDIRT = $(POTHEAD) XGETTEXTFILES = $(LOCALIZED_FILES) default: $(POTHEAD) $(LINGUAS:%=%.mo) include $(BUILDRULES) install: default $(INSTALL_LINGUAS) install-dev install-lib: xfsprogs-5.3.0/po/de.po0000644000175000017500000151572113034246041014623 0ustar nathansnathans# Translation of xfsprogs to German # Copyright (C) Chris Leick , 2009. # This file is distributed under the same license as the xfsprogs package. # Chris Leick , 2009. # msgid "" msgstr "" "Project-Id-Version: xfsprogs 3.0.3\n" "Report-Msgid-Bugs-To: nathans@debian.org\n" "POT-Creation-Date: 2009-09-29 09:36-0300\n" "PO-Revision-Date: 2009-10-21 21:08+0100\n" "Last-Translator: Chris Leick \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: .././copy/xfs_copy.c:102 #, c-format msgid "Check logfile \"%s\" for more details\n" msgstr "Prüfen Sie die Protokolldatei »%s«, um mehr Details zu erhalten\n" #: .././copy/xfs_copy.c:108 #, c-format msgid "%s: could not write to logfile \"%s\".\n" msgstr "%s: Es konnte nicht in die Protokolldatei »%s« geschrieben werden.\n" #: .././copy/xfs_copy.c:111 #, c-format msgid "Aborting XFS copy -- logfile error -- reason: %s\n" msgstr "Kopieren von XFS wird abgebrochen -- Protokollfehler -- Grund: %s\n" #: .././copy/xfs_copy.c:126 .././copy/xfs_copy.c:286 .././copy/xfs_copy.c:563 #: .././copy/xfs_copy.c:570 msgid "Aborting XFS copy - reason" msgstr "Kopieren von XFS wird abgebrochen - Grund" #: .././copy/xfs_copy.c:140 msgid "THE FOLLOWING COPIES FAILED TO COMPLETE\n" msgstr "DAS VERVOLLSTÄNDIGEN DER FOLGENDEN KOPIEN SCHEITERTE\n" #: .././copy/xfs_copy.c:144 msgid "write error" msgstr "Schreibfehler" #: .././copy/xfs_copy.c:146 msgid "lseek error" msgstr "lseek-Fehler" #: .././copy/xfs_copy.c:147 #, c-format msgid " at offset %lld\n" msgstr " bei Versatz %lld\n" #: .././copy/xfs_copy.c:151 #, c-format msgid "All copies completed.\n" msgstr "Alle Kopien vervollständigt.\n" #: .././copy/xfs_copy.c:154 #, c-format msgid "See \"%s\" for more details.\n" msgstr "Lesen Sie »%s«, um mehr Details zu erhalten.\n" #: .././copy/xfs_copy.c:255 #, c-format msgid "%s: write error on target %d \"%s\" at offset %lld\n" msgstr "%s: Schreibfehler auf Ziel %d »%s« bei Versatz %lld\n" #: .././copy/xfs_copy.c:260 #, c-format msgid "%s: lseek error on target %d \"%s\" at offset %lld\n" msgstr "%s: lseek-Fehler auf Ziel %d »%s« bei Versatz %lld\n" #: .././copy/xfs_copy.c:266 #, c-format msgid "Aborting target %d - reason" msgstr "Ziel %d wird abgebrochen - Grund" #: .././copy/xfs_copy.c:270 msgid "Aborting XFS copy - no more targets.\n" msgstr "Kopieren von XFS wird abgebrochen - keine Ziele mehr.\n" #: .././copy/xfs_copy.c:281 #, c-format msgid "%s: thread %d died unexpectedly, target \"%s\" incomplete\n" msgstr "%s: Thread %d unerwartet beendet, Ziel »%s« unvollständig\n" #: .././copy/xfs_copy.c:283 #, c-format msgid "%s: offset was probably %lld\n" msgstr "%s: Versatz war vermutlich %lld\n" #: .././copy/xfs_copy.c:294 #, c-format msgid "%s: Unknown child died (should never happen!)\n" msgstr "%s: Unbekannter Kindprozess beendet (sollte nie vorkommen!)\n" #: .././copy/xfs_copy.c:304 #, c-format msgid "Usage: %s [-bd] [-L logfile] source target [target ...]\n" msgstr "Aufruf: %s [-bd] [-L Protokolldatei] Quelle Ziel [Ziel ...]\n" #: .././copy/xfs_copy.c:386 #, c-format msgid "%s: lseek failure at offset %lld\n" msgstr "%s: lseek-Fehlschlag bei Versatz %lld\n" #: .././copy/xfs_copy.c:401 #, c-format msgid "assert error: buf->length = %d, buf->size = %d\n" msgstr "bestätigter Fehler: buf->length = %d, buf->size = %d\n" #: .././copy/xfs_copy.c:408 #, c-format msgid "%s: read failure at offset %lld\n" msgstr "%s: Lese-Fehlschlag bei Versatz %lld\n" #: .././copy/xfs_copy.c:543 .././db/init.c:93 .././estimate/xfs_estimate.c:141 #: .././fsr/xfs_fsr.c:243 .././growfs/xfs_growfs.c:182 .././io/init.c:180 #: .././logprint/logprint.c:196 .././mkfs/xfs_mkfs.c:1362 #: .././quota/init.c:131 .././repair/xfs_repair.c:322 .././rtcp/xfs_rtcp.c:57 #, c-format msgid "%s version %s\n" msgstr "%s Version %s\n" #: .././copy/xfs_copy.c:561 #, c-format msgid "%s: couldn't open log file \"%s\"\n" msgstr "%s: Protokolldatei »%s« kann nicht geöffnet werden.\n" #: .././copy/xfs_copy.c:568 #, c-format msgid "%s: couldn't set up logfile stream\n" msgstr "%s: Protokoll-Datenstrom konnte nicht erzeugt werden\n" #: .././copy/xfs_copy.c:580 msgid "Couldn't allocate target array\n" msgstr "Ziel-Array konnte nicht bereitgestellt werden.\n" #: .././copy/xfs_copy.c:595 #, c-format msgid "%s: couldn't register atexit function.\n" msgstr "%s: atexit-Funktion konnte nicht registriert werden.\n" #: .././copy/xfs_copy.c:604 #, c-format msgid "%s: couldn't open source \"%s\"\n" msgstr "%s: Konnte Quelle »%s« nicht öffnen.\n" #: .././copy/xfs_copy.c:610 #, c-format msgid "%s: couldn't stat source \"%s\"\n" msgstr "%s: kann Quellenstatus »%s« nicht abfragen.\n" #: .././copy/xfs_copy.c:620 #, c-format msgid "%s: Cannot set direct I/O flag on \"%s\".\n" msgstr "%s: Direkte I/O-Markierung auf »%s« kann nicht gesetzt werden.\n" #: .././copy/xfs_copy.c:625 #, c-format msgid "%s: xfsctl on file \"%s\" failed.\n" msgstr "%s: xfsctl auf Datei »%s« fehlgeschlagen.\n" #: .././copy/xfs_copy.c:648 #, c-format msgid "%s: Warning -- a filesystem is mounted on the source device.\n" msgstr "%s: Warnung -- ein Dateisystem ist auf dem Quellgerät eingehängt.\n" #: .././copy/xfs_copy.c:651 msgid "\t\tGenerated copies may be corrupt unless the source is\n" msgstr "" "\t\tGenerierte Kopien könnten fehlerhaft sein, sofern die Quelle nicht\n" #: .././copy/xfs_copy.c:653 msgid "\t\tunmounted or mounted read-only. Copy proceeding...\n" msgstr "" "\t\tabgehängt oder nur mit Lesezugriff eingehängt ist.\n" "\t\tKopieren durchführen ...\n" #: .././copy/xfs_copy.c:670 #, c-format msgid "" "%s: couldn't initialize XFS library\n" "%s: Aborting.\n" msgstr "" "%s: XFS-Bibliothek konnte nicht initialisiert werden.\n" "%s: Abbruch.\n" #: .././copy/xfs_copy.c:684 #, c-format msgid "" "%s: %s filesystem failed to initialize\n" "%s: Aborting.\n" msgstr "" "%s: %s-Dateisystem konnte nicht initialisiert werden.\n" "%s: Abbruch.\n" #: .././copy/xfs_copy.c:688 #, c-format msgid "" "%s %s filesystem failed to initialize\n" "%s: Aborting.\n" msgstr "" "%s: %s-Dateisystem konnte nicht initialisiert werden.\n" "%s: Abbruch.\n" #: .././copy/xfs_copy.c:692 #, c-format msgid "" "%s: %s has an external log.\n" "%s: Aborting.\n" msgstr "" "%s: %s hat ein externes Protokoll.\n" "%s: Abbruch.\n" #: .././copy/xfs_copy.c:696 #, c-format msgid "" "%s: %s has a real-time section.\n" "%s: Aborting.\n" msgstr "" "%s: %s hat einen Echtzeit-Bereich.\n" "%s: Abbruch.\n" #: .././copy/xfs_copy.c:721 msgid "" "Error: filesystem block size is smaller than the disk sectorsize.\n" "Aborting XFS copy now.\n" msgstr "" "Fehler: Die Blockgröße des Dateisystems ist kleiner als die Sektorgröße\n" "der Platte. XFS-Kopieren wird nun abgebrochen.\n" #: .././copy/xfs_copy.c:742 #, c-format msgid "Creating file %s\n" msgstr "Datei %s wird erzeugt.\n" #: .././copy/xfs_copy.c:760 #, c-format msgid "" "%s: a filesystem is mounted on target device \"%s\".\n" "%s cannot copy to mounted filesystems. Aborting\n" msgstr "" "%s: Ein Dateisystem ist auf dem Zielgerät »%s« eingehängt.\n" "%s kann nicht auf eingehängte Dateisysteme schreiben. Abbruch\n" #: .././copy/xfs_copy.c:771 #, c-format msgid "%s: couldn't open target \"%s\"\n" msgstr "%s: Ziel »%s« kann nicht geöffnet werden.\n" #: .././copy/xfs_copy.c:781 #, c-format msgid "%s: cannot grow data section.\n" msgstr "%s: Datenbereich kann nicht vergrößert werden.\n" #: .././copy/xfs_copy.c:789 #, c-format msgid "%s: xfsctl on \"%s\" failed.\n" msgstr "%s: xfsctl auf »%s« fehlgeschlagen.\n" #: .././copy/xfs_copy.c:808 #, c-format msgid "%s: failed to write last block\n" msgstr "%s: Letzter Block konnte nicht geschrieben werden.\n" #: .././copy/xfs_copy.c:810 #, c-format msgid "\tIs target \"%s\" too small?\n" msgstr "\tIst das Ziel »%s« zu klein?\n" #: .././copy/xfs_copy.c:820 msgid "Couldn't initialize global thread mask\n" msgstr "Globale Thread-Maske kann nicht initialisiert werden\n" #: .././copy/xfs_copy.c:827 msgid "Error initializing wbuf 0\n" msgstr "Fehler beim Initialisieren von wbuf 0\n" #: .././copy/xfs_copy.c:835 msgid "Error initializing btree buf 1\n" msgstr "Fehler beim Initialisieren von btree buf 1\n" #: .././copy/xfs_copy.c:840 msgid "Error creating first semaphore.\n" msgstr "Fehler beim Erstellen des ersten Semaphor.\n" #: .././copy/xfs_copy.c:855 msgid "Couldn't malloc space for thread args\n" msgstr "" "Für die Thread-Argumente konnte kein Speicherplatz bereit\n" "gestellt werden.\n" #: .././copy/xfs_copy.c:867 #, c-format msgid "Error creating thread mutex %d\n" msgstr "Fehler beim Erzeugen des Thread-Mutex %d\n" #: .././copy/xfs_copy.c:884 #, c-format msgid "Error creating thread for target %d\n" msgstr "Fehler beim Erzeugen des Threads für Ziel %d\n" #: .././copy/xfs_copy.c:974 msgid "WARNING: source filesystem inconsistent.\n" msgstr "WARNUNG: Quell-Dateisystem ist nicht konsistent.\n" #: .././copy/xfs_copy.c:976 msgid " A leaf btree rec isn't a leaf. Aborting now.\n" msgstr " Ein Blatt »btree rec« ist kein Blatt. Es wird nun abgebrochen.\n" #: .././db/check.c:372 msgid "free block usage information" msgstr "Information über freie Blöcke" #: .././db/check.c:375 msgid "[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..." msgstr "[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..." #: .././db/check.c:376 msgid "get block usage and check consistency" msgstr "Blockbenutzung erhalten und Konsistenz prüfen" #: .././db/check.c:379 msgid "[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..." msgstr "" "[-n Anzahl] [-x Mindestlänge] [-y Maximallänge] [-s füllen] [-0123] " "[-t Typ] ..." #: .././db/check.c:380 msgid "trash randomly selected block(s)" msgstr "zufällig ausgewähle Blöcke wegwerfen" #: .././db/check.c:383 msgid "[-n] [-c blockcount]" msgstr "[-n] [-c Blockanzahl]" #: .././db/check.c:384 msgid "print usage for current block(s)" msgstr "Benutzung für aktuelle Blöcke ausgeben" #: .././db/check.c:387 msgid "[-s] [-i ino] ..." msgstr "[-s] [-i ino] ..." #: .././db/check.c:388 msgid "print inode-name pairs" msgstr "Inode-Namenspaare ausgeben" #: .././db/check.c:408 #, c-format msgid "-i %lld bad inode number\n" msgstr "-i %lld falsche Inode-Nummer\n" #: .././db/check.c:420 #, c-format msgid "inode %lld add link, now %u\n" msgstr "Inode %lld Verweis hinzufügen, nun %u\n" #: .././db/check.c:447 #, c-format msgid "inode %lld parent %lld\n" msgstr "Inode %lld Übergeordnet %lld\n" #: .././db/check.c:760 msgid "block usage information not allocated\n" msgstr "Blockbenutzungsinformationen nicht zugeteilt\n" #: .././db/check.c:798 msgid "already have block usage information\n" msgstr "Blockbenutzungsinformationen bereits erhalten\n" #: .././db/check.c:814 .././db/check.c:922 msgid "WARNING: this may be a newer XFS filesystem.\n" msgstr "WARNUNG: Dies könnte ein neueres XFS-Dateisystem sein\n" #: .././db/check.c:850 #, c-format msgid "sb_icount %lld, counted %lld\n" msgstr "sb_icount %lld, gezählt %lld\n" #: .././db/check.c:856 #, c-format msgid "sb_ifree %lld, counted %lld\n" msgstr "sb_ifree %lld, gezählt %lld\n" #: .././db/check.c:862 #, c-format msgid "sb_fdblocks %lld, counted %lld\n" msgstr "sb_fdblocks %lld, gezählt %lld\n" #: .././db/check.c:868 #, c-format msgid "sb_fdblocks %lld, aggregate AGF count %lld\n" msgstr "sb_fdblocks %lld, gesamte AGF-Anzahl %lld\n" #: .././db/check.c:874 #, c-format msgid "sb_frextents %lld, counted %lld\n" msgstr "sb_frextents %lld, gezählt %lld\n" #: .././db/check.c:881 #, c-format msgid "sb_features2 (0x%x) not same as sb_bad_features2 (0x%x)\n" msgstr "sb_features2 (0x%x) entspricht nicht sb_bad_features2 (0x%x)\n" #: .././db/check.c:890 #, c-format msgid "sb versionnum missing attr bit %x\n" msgstr "sb-Versionsnummer fehlt attr-Bit %x\n" #: .././db/check.c:897 #, c-format msgid "sb versionnum missing nlink bit %x\n" msgstr "sb-Versionsnummer fehlt nlink-Bit %x\n" #: .././db/check.c:904 #, c-format msgid "sb versionnum missing quota bit %x\n" msgstr "sb-Versionsnummer fehlt Quota-Bit %x\n" #: .././db/check.c:911 #, c-format msgid "sb versionnum extra align bit %x\n" msgstr "zusätzliches sb-Versionsnummerausrichtungs-Bit %x\n" #: .././db/check.c:951 msgid "zeroed" msgstr "auf Null gesetzt" #: .././db/check.c:951 msgid "set" msgstr "setze" #: .././db/check.c:951 msgid "flipped" msgstr "umgeblättert" #: .././db/check.c:951 msgid "randomized" msgstr "randomisiert" #: .././db/check.c:961 #, c-format msgid "can't read block %u/%u for trashing\n" msgstr "Block %u/%u zum Wegwerfen kann nicht gelesen werden\n" #: .././db/check.c:991 #, c-format msgid "blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n" msgstr "blocktrash: %u/%u %s Block %d Bit%s startet %d:%d %s\n" #: .././db/check.c:1023 .././db/check.c:1180 msgid "must run blockget first\n" msgstr "zuerst muss blockget ausgeführt werden\n" #: .././db/check.c:1067 #, c-format msgid "bad blocktrash count %s\n" msgstr "falsche blocktrash-Anzahl %s\n" #: .././db/check.c:1081 #, c-format msgid "bad blocktrash type %s\n" msgstr "falscher blocktrash-Typ %s\n" #: .././db/check.c:1090 #, c-format msgid "bad blocktrash min %s\n" msgstr "falsches blocktrash-Minimum %s\n" #: .././db/check.c:1098 #, c-format msgid "bad blocktrash max %s\n" msgstr "falsches blocktrash-Maximum %s\n" #: .././db/check.c:1103 msgid "bad option for blocktrash command\n" msgstr "falscher Option für blocktrash-Befehl\n" #: .././db/check.c:1108 msgid "bad min/max for blocktrash command\n" msgstr "falsches Minimum/Maximum für blocktrash-Befehl\n" #: .././db/check.c:1134 msgid "blocktrash: no matching blocks\n" msgstr "blocktrash: keine passenden Blöcke\n" #: .././db/check.c:1138 #, c-format msgid "blocktrash: seed %u\n" msgstr "blocktrash: %u füllen\n" #: .././db/check.c:1196 #, c-format msgid "bad blockuse count %s\n" msgstr "falsche blockuse-Anzahl %s\n" #: .././db/check.c:1202 .././db/check.c:1887 msgid "must run blockget -n first\n" msgstr "zuerst muss »blockget -n« ausgeführt werden\n" #: .././db/check.c:1208 msgid "bad option for blockuse command\n" msgstr "falsche Option für Befehl blockuse\n" #: .././db/check.c:1215 #, c-format msgid "block %llu (%u/%u) type %s" msgstr "Block %llu (%u/%u) Typ %s" #: .././db/check.c:1219 #, c-format msgid " inode %lld" msgstr "Inode %lld" #: .././db/check.c:1257 #, c-format msgid "block %u/%u expected type %s got %s\n" msgstr "Block %u/%u erwartete Typ %s bekam %s\n" #: .././db/check.c:1289 #, c-format msgid "blocks %u/%u..%u claimed by inode %lld\n" msgstr "Blöcke %u/%u..%u werden von Inode %lld beansprucht\n" #: .././db/check.c:1297 #, c-format msgid "block %u/%u claimed by inode %lld, previous inum %lld\n" msgstr "Block %u/%u von Inode %lld beansprucht, vorherige inum %lld\n" #: .././db/check.c:1326 #, c-format msgid "link count mismatch for inode %lld (name %s), nlink %d, counted %d\n" msgstr "" "keine Übereinstimmung bei Verweisanzahl für Inode %lld (Name %s), " "nlink %d, gezählt %d\n" #: .././db/check.c:1334 #, c-format msgid "disconnected inode %lld, nlink %d\n" msgstr "getrennter Inode %lld, nlink %d\n" #: .././db/check.c:1338 #, c-format msgid "allocated inode %lld has 0 link count\n" msgstr "zugeteilter Inode %lld hat Verweisanzahl 0\n" #: .././db/check.c:1348 #, c-format msgid "inode %lld name %s\n" msgstr "Inode %lld Name %s\n" #: .././db/check.c:1382 .././db/check.c:1397 #, c-format msgid "block %u/%u out of range\n" msgstr "Block %u/%u außerhalb des Bereichs\n" #: .././db/check.c:1385 .././db/check.c:1400 #, c-format msgid "blocks %u/%u..%u out of range\n" msgstr "Blöcke %u/%u..%u außerhalb des Bereichs\n" #: .././db/check.c:1423 #, c-format msgid "rtblock %llu expected type %s got %s\n" msgstr "rtblock %llu erwartete Typ %s bekam %s\n" #: .././db/check.c:1443 #, c-format msgid "rtblocks %llu..%llu claimed by inode %lld\n" msgstr "" "rtblocks %llu..%llu von Inode %lld beansprucht\n" #: .././db/check.c:1452 #, c-format msgid "rtblock %llu claimed by inode %lld, previous inum %lld\n" msgstr "rtblock %llu von Inode %lld beansprucht, vorheriger inum %lld\n" #: .././db/check.c:1470 #, c-format msgid "root inode %lld is missing\n" msgstr "Wurzel-Inode %lld fehlt\n" #: .././db/check.c:1475 #, c-format msgid "root inode %lld is not a directory\n" msgstr "Wurzel-Inode %lld ist kein Verzeichnis\n" #: .././db/check.c:1491 #, c-format msgid "rtblock %llu out of range\n" msgstr "rtblock %llu außerhalb des Bereichs\n" #: .././db/check.c:1515 #, c-format msgid "blocks %u/%u..%u claimed by block %u/%u\n" msgstr "Blöcke %u/%u..%u von Block %u/%u beansprucht\n" #: .././db/check.c:1524 #, c-format msgid "setting block %u/%u to %s\n" msgstr "Block %u/%u wird auf %s gesetzt\n" #: .././db/check.c:1547 #, c-format msgid "setting rtblock %llu to %s\n" msgstr "rtblock %llu wird auf %s gesetzt\n" #: .././db/check.c:1568 .././repair/rt.c:151 #, c-format msgid "rt summary mismatch, size %d block %llu, file: %d, computed: %d\n" msgstr "" "rt-Zusammenfassung stimmt nicht überein, Größe %d Block %llu, Datei: %d,\n" "berechnet: %d\n" #: .././db/check.c:1593 #, c-format msgid "block %u/%u type %s not expected\n" msgstr "Block %u/%u Typ %s nicht erwartet\n" #: .././db/check.c:1614 #, c-format msgid "rtblock %llu type %s not expected\n" msgstr "rtblock %llu Typ %s nicht erwartet\n" #: .././db/check.c:1651 #, c-format msgid "dir ino %lld missing leaf entry for %x/%x\n" msgstr "dir ino %lld fehlt der Blatteintrag für %x/%x\n" #: .././db/check.c:1770 #, c-format msgid "bad superblock magic number %x, giving up\n" msgstr "falsche Magische Nummer %x von Superblock, es wird aufgegeben\n" #: .././db/check.c:1824 msgid "bad option for blockget command\n" msgstr "falsche Option für blockget-Befehl\n" #: .././db/check.c:1904 #, c-format msgid "bad option -%c for ncheck command\n" msgstr "falsche Option -%c für ncheck-Befehl\n" #: .././db/check.c:1977 .././db/check.c:2944 #, c-format msgid "block 0 for directory inode %lld is missing\n" msgstr "Block 0 für Verzeichnis-Inode %lld fehlt\n" #: .././db/check.c:1997 .././db/check.c:2955 #, c-format msgid "can't read block 0 for directory inode %lld\n" msgstr "Block 0 für Verzeichnis-Inode %lld kann nicht gelesen werden\n" #: .././db/check.c:2043 #, c-format msgid "inode %lld extent [%lld,%lld,%lld,%d]\n" msgstr "Inode %lld Umfang [%lld,%lld,%lld,%d]\n" #: .././db/check.c:2046 #, c-format msgid "bmap rec out of order, inode %lld entry %d\n" msgstr "bmap rec außer Betrieb, Inode %lld Eintrag %d \n" #: .././db/check.c:2052 #, c-format msgid "inode %lld bad rt block number %lld, offset %lld\n" msgstr "Inode %lld falsche rt-Blocknummer %lld, Versatz %lld\n" #: .././db/check.c:2062 .././db/check.c:2068 #, c-format msgid "inode %lld bad block number %lld [%d,%d], offset %lld\n" msgstr "Inode %lld falsche Block-Nummer %lld [%d,%d], Versatz %lld\n" #: .././db/check.c:2086 .././db/check.c:2100 #, c-format msgid "inode %lld block %lld at offset %lld\n" msgstr "Inode %lld Block %lld bei Versatz %lld\n" #: .././db/check.c:2128 #, c-format msgid "level for ino %lld %s fork bmap root too large (%u)\n" msgstr "Stufe für ino %lld %s-Fork bmap-Wurzel zu groß (%u)\n" #: .././db/check.c:2131 .././db/check.c:2143 .././db/check.c:2170 #: .././db/bmap.c:216 .././repair/scan.c:153 .././repair/dinode.c:631 #: .././repair/dinode.c:1178 msgid "data" msgstr "Daten" #: .././db/check.c:2131 .././db/check.c:2143 .././db/check.c:2170 #: .././db/bmap.c:216 .././repair/scan.c:155 .././repair/dinode.c:633 #: .././repair/dinode.c:1180 msgid "attr" msgstr "attr" #: .././db/check.c:2140 #, c-format msgid "numrecs for ino %lld %s fork bmap root too large (%u)\n" msgstr "numrecs für ino %lld %s-Fork bmap-Wurzel zu groß (%u)\n" #: .././db/check.c:2167 .././repair/dinode.c:1291 #, c-format msgid "extent count for ino %lld %s fork too low (%d) for file format\n" msgstr "Umfanganzahl für ino %lld %s-Fork zu niedrig (%d) für Dateiformat\n" #: .././db/check.c:2217 .././db/check.c:3295 #, c-format msgid "bad directory data magic # %#x for dir ino %lld block %d\n" msgstr "falsche magische Verzeichnisdaten-# %#x für ino %lld Block %d\n" #: .././db/check.c:2234 #, c-format msgid "bad block directory tail for dir ino %lld\n" msgstr "falsches Verzeichnisblockende für dir ino %lld\n" #: .././db/check.c:2279 #, c-format msgid "dir %lld block %d bad free entry at %d\n" msgstr "dir %lld Block %d falscher freier Eintrag bei %d\n" #: .././db/check.c:2303 #, c-format msgid "dir %lld block %d zero length entry at %d\n" msgstr "dir %lld Block %d Eintrag der Länge Null bei %d\n" #: .././db/check.c:2312 #, c-format msgid "dir %lld block %d bad entry at %d\n" msgstr "dir %lld Block %d falscher Eintrag bei %d\n" #: .././db/check.c:2330 #, c-format msgid "dir %lld block %d entry %*.*s %lld\n" msgstr "dir %lld Block %d Eintrag %*.*s %lld\n" #: .././db/check.c:2337 #, c-format msgid "dir %lld block %d entry %*.*s bad inode number %lld\n" msgstr "dir %lld Block %d Eintrag %*.*s falsche Inode-Nummer %lld\n" #: .././db/check.c:2347 .././db/check.c:3018 #, c-format msgid "multiple .. entries in dir %lld (%lld, %lld)\n" msgstr "mehrere .. Einträge in dir %lld (%lld, %lld)\n" #: .././db/check.c:2364 .././db/check.c:3035 #, c-format msgid "dir %lld entry . inode number mismatch (%lld)\n" msgstr "dir %lld Eintrag . Inode-Nummer stimmt nicht überein (%lld)\n" #: .././db/check.c:2377 #, c-format msgid "dir %lld block %d bad count %u\n" msgstr "dir %lld Block %d falsche Anzahl %u\n" #: .././db/check.c:2388 .././db/check.c:3309 #, c-format msgid "dir %lld block %d extra leaf entry %x %x\n" msgstr "dir %lld Block %d zusätzlicher Blatteintrag %x %x\n" #: .././db/check.c:2400 #, c-format msgid "dir %lld block %d bad bestfree data\n" msgstr "dir %lld Block %d falsche bestfree-Daten\n" #: .././db/check.c:2408 #, c-format msgid "dir %lld block %d bad block tail count %d (stale %d)\n" msgstr "dir %lld Block %d falsche Blockgrößenanzahl %d (abgelaufen %d)\n" #: .././db/check.c:2417 #, c-format msgid "dir %lld block %d bad stale tail count %d\n" msgstr "dir %lld Block %d falsche Anzahl abgelaufener Blöcke %d\n" #: .././db/check.c:2423 #, c-format msgid "dir %lld block %d consecutive free entries\n" msgstr "dir %lld Block %d aufeinander folgende freie Einträge\n" #: .././db/check.c:2429 #, c-format msgid "dir %lld block %d entry/unused tag mismatch\n" msgstr "dir %lld Block %d Eintrag/nichtbenutzte Markierung passt nicht\n" #: .././db/check.c:2482 #, c-format msgid "no . entry for directory %lld\n" msgstr "kein .-Eintrag für Verzeichnis %lld\n" #: .././db/check.c:2487 #, c-format msgid "no .. entry for directory %lld\n" msgstr "kein ..-Eintrag für Verzeichnis %lld\n" #: .././db/check.c:2491 #, c-format msgid ". and .. same for non-root directory %lld\n" msgstr ".- und ..-Einträge für Nicht-Wurzelverzeichnis %lld gleich\n" #: .././db/check.c:2496 #, c-format msgid "root directory %lld has .. %lld\n" msgstr "Wurzelverzeichnis %lld hat .. %lld\n" #: .././db/check.c:2526 .././db/check.c:2561 #, c-format msgid "bad size (%lld) or format (%d) for directory inode %lld\n" msgstr "falsche Größe (%lld) oder Format (%d) für Verzeichnis-Inode %lld\n" #: .././db/check.c:2589 #, c-format msgid "bad number of extents %d for inode %lld\n" msgstr "falsche Anzahl von Ausweitungen %d für Inode %lld\n" #: .././db/check.c:2659 #, c-format msgid "bad magic number %#x for inode %lld\n" msgstr "falsche Magische Nummer %#x für Inode %lld\n" #: .././db/check.c:2666 #, c-format msgid "bad version number %#x for inode %lld\n" msgstr "falsche Versionsnummer %#x für Inode %lld\n" #: .././db/check.c:2674 #, c-format msgid "bad nblocks %lld for free inode %lld\n" msgstr "falsche nblocks %lld für freien Inode %lld\n" #: .././db/check.c:2685 #, c-format msgid "bad nlink %d for free inode %lld\n" msgstr "falscher nlink %d für freien Inode %lld\n" #: .././db/check.c:2691 #, c-format msgid "bad mode %#o for free inode %lld\n" msgstr "falscher Modus %#o für freien Inode %lld\n" #: .././db/check.c:2699 #, c-format msgid "bad next unlinked %#x for inode %lld\n" msgstr "falsche nächste gelöste Verknüpfung %#x für Inode %lld\n" #: .././db/check.c:2709 #, c-format msgid "bad format %d for inode %lld type %#o\n" msgstr "falsches Format %d für Inode %lld Typ %#o\n" #: .././db/check.c:2716 #, c-format msgid "bad fork offset %d for inode %lld\n" msgstr "falsche Abspaltungsversatz %d für Inode %lld\n" #: .././db/check.c:2723 #, c-format msgid "bad attribute format %d for inode %lld\n" msgstr "falsches Attributformat %d für Inode %lld\n" #: .././db/check.c:2729 #, c-format msgid "" "inode %lld mode %#o fmt %s afmt %s nex %d anex %d nblk %lld sz %lld%s%s%s%s%s" "%s%s\n" msgstr "" "Inode %lld Modus %#o fmt %s afmt %s nex %d anex %d nblk %lld sz " "%lld%s%s%s%s%s%s%s\n" #: .././db/check.c:2849 #, c-format msgid "bad nblocks %lld for inode %lld, counted %lld\n" msgstr "falsche nblocks %lld für Inode %lld, gezählt %lld\n" #: .././db/check.c:2856 #, c-format msgid "bad nextents %d for inode %lld, counted %d\n" msgstr "falsche nextents %d für Inode %lld, gezählt %d\n" #: .././db/check.c:2862 #, c-format msgid "bad anextents %d for inode %lld, counted %d\n" msgstr "falsche anextents %d für Inode %lld, gezählt %d\n" #: .././db/check.c:2914 #, c-format msgid "local inode %lld data is too large (size %lld)\n" msgstr "" "lokales Inode-%lld-Daten-Unterelement ist zu groß (Größe = %lld)\n" #: .././db/check.c:2923 #, c-format msgid "local inode %lld attr is too large (size %d)\n" msgstr "lokales Inode-%lld-attr ist zu groß (Größe = %d)\n" #: .././db/check.c:2988 #, c-format msgid "bad directory leaf magic # %#x for dir ino %lld\n" msgstr "falsche magische Verzeichnis-Blatt # %#x für dir ino %lld\n" #: .././db/check.c:3001 .././db/check.c:3766 #, c-format msgid "dir %lld entry %*.*s %lld\n" msgstr "dir %lld Eintrag %*.*s %lld\n" #: .././db/check.c:3008 .././db/check.c:3662 .././db/check.c:3754 #, c-format msgid "dir %lld entry %*.*s bad inode number %lld\n" msgstr "dir %lld Eintrag %*.*s falsche Inode-Nummer %lld\n" #: .././db/check.c:3087 .././db/check.c:3356 #, c-format msgid "dir inode %lld block %u=%llu\n" msgstr "dir inode %lld Block %u=%llu\n" #: .././db/check.c:3099 .././db/check.c:3366 #, c-format msgid "can't read block %u for directory inode %lld\n" msgstr "Block %u für Verzeichnis-Inode %lld kann nicht gelesen werden\n" #: .././db/check.c:3113 .././db/check.c:3379 #, c-format msgid "multiple .. entries in dir %lld\n" msgstr "mehrfache .. Einträge in Verzeichnis-Inode %lld\n" #: .././db/check.c:3135 #, c-format msgid "missing free index for data block %d in dir ino %lld\n" msgstr "freier Index für Datenblock %d in dir ino %lld fehlt\n" #: .././db/check.c:3161 #, c-format msgid "bad free block magic # %#x for dir ino %lld block %d\n" msgstr "falsche frei magische Block-# %#x für ino %lld Block %d\n" #: .././db/check.c:3171 #, c-format msgid "bad free block firstdb %d for dir ino %lld block %d\n" msgstr "falscher freier Block firstdb %d für dir ino %lld Block %d\n" #: .././db/check.c:3184 #, c-format msgid "bad free block nvalid/nused %d/%d for dir ino %lld block %d\n" msgstr "falscher freier Block nvalid/nused %d/%d für dir ino %lld Block %d\n" #: .././db/check.c:3198 #, c-format msgid "bad free block ent %d is %d should be %d for dir ino %lld block %d\n" msgstr "" "falscher freier Block ent %d ist %d, sollte %d sein für dir ino %lld " "Block %d\n" #: .././db/check.c:3212 #, c-format msgid "bad free block nused %d should be %d for dir ino %lld block %d\n" msgstr "" "falscher freier nused-Block %d sollte %d sein für dir ino %lld Block %d\n" #: .././db/check.c:3241 #, c-format msgid "bad leaf block forw/back pointers %d/%d for dir ino %lld block %d\n" msgstr "" "Falscher Blattblock Vorwärts-/Rückwärtszeiger %d/%d für dir ino %lld Block " "%d\n" #: .././db/check.c:3250 #, c-format msgid "single leaf block for dir ino %lld block %d should be at block %d\n" msgstr "" "einzelner Blattblock für dir ino %lld Block %d sollte bei Block %d sein\n" #: .././db/check.c:3262 #, c-format msgid "bestfree %d for dir ino %lld block %d doesn't match table value %d\n" msgstr "" "bestfree %d für dir ino %lld Block %d passt nicht zu Tabellenwert %d\n" #: .././db/check.c:3286 #, c-format msgid "bad node block level %d for dir ino %lld block %d\n" msgstr "falsche Knotenblockstufe %d für dir ino %lld Block %d\n" #: .././db/check.c:3318 #, c-format msgid "dir %lld block %d stale mismatch %d/%d\n" msgstr "dir %lld Block %d abgelaufene Nichtübereinstimmung %d/%d\n" #: .././db/check.c:3350 #, c-format msgid "can't read root block for directory inode %lld\n" msgstr "Block für Verzeichnis-Inode %lld kann nicht gelesen werden\n" #: .././db/check.c:3439 #, c-format msgid "can't read block %lld for %s quota inode (fsblock %lld)\n" msgstr "" "Block %lld für %s Quota-Inode (fsblock %lld) kann nicht gelesen " "werden\n" #: .././db/check.c:3449 #, c-format msgid "%s dqblk %lld entry %d id %u bc %lld ic %lld rc %lld\n" msgstr "%s dqblk %lld Eintrag %d id %u bc %lld ic %lld rc %lld\n" #: .././db/check.c:3457 #, c-format msgid "bad magic number %#x for %s dqblk %lld entry %d id %u\n" msgstr "falsche Magische Nummer %#x für %s dqblk %lld Eintrag %d ID %u\n\n" #: .././db/check.c:3466 #, c-format msgid "bad version number %#x for %s dqblk %lld entry %d id %u\n" msgstr "falsche Versionsnummer %#x für %s dqblk %lld Eintrag %d ID %u\n" #: .././db/check.c:3476 #, c-format msgid "bad flags %#x for %s dqblk %lld entry %d id %u\n" msgstr "Falsche Markierungen %#x für %s dqblk %lld Eintrag %d ID %u\n" #: .././db/check.c:3485 #, c-format msgid "bad id %u for %s dqblk %lld entry %d id %u\n" msgstr "falsche ID %u für %s dqblk %lld Eintrag %d ID %u\n" #: .././db/check.c:3531 #, c-format msgid "block %lld for rtbitmap inode is missing\n" msgstr "Block %lld für rtbitmap-Inode fehlt\n" #: .././db/check.c:3542 #, c-format msgid "can't read block %lld for rtbitmap inode\n" msgstr "Block %lld für rtbitmap-Inode kann nicht gelesen werden\n" #: .././db/check.c:3598 #, c-format msgid "block %lld for rtsummary inode is missing\n" msgstr "Block %lld für rtsummary-Inode fehlt\n" #: .././db/check.c:3609 #, c-format msgid "can't read block %lld for rtsummary inode\n" msgstr "Block %lld für rtsummary-Inode kann nicht gelesen werden\n" #: .././db/check.c:3642 .././db/check.c:3746 #, c-format msgid "dir %lld entry . %lld\n" msgstr "dir %lld Eintrag . %lld\n" #: .././db/check.c:3650 #, c-format msgid "dir %llu bad size in entry at %d\n" msgstr "dir %llu falsche Größe im Eintrag bei %d\n" #: .././db/check.c:3674 #, c-format msgid "dir %lld entry %*.*s offset %d %lld\n" msgstr "dir %lld Eintrag %*.*s Versatz %d %lld\n" #: .././db/check.c:3679 #, c-format msgid "dir %lld entry %*.*s bad offset %d\n" msgstr "dir %lld Eintrag %*.*s falscher Versatz %d\n" #: .././db/check.c:3692 #, c-format msgid "dir %llu size is %lld, should be %u\n" msgstr "dir %llu Größe ist %lld, sollte %u sein\n" #: .././db/check.c:3700 #, c-format msgid "dir %llu offsets too high\n" msgstr "dir %llu Versätze zu groß\n" #: .././db/check.c:3711 .././db/check.c:3780 #, c-format msgid "dir %lld entry .. bad inode number %lld\n" msgstr "dir %lld Eintrag .. falsche Inode-Nummer %lld\n" #: .././db/check.c:3716 .././db/check.c:3785 #, c-format msgid "dir %lld entry .. %lld\n" msgstr "dir %lld Eintrag .. %lld\n" #: .././db/check.c:3719 #, c-format msgid "dir %lld i8count mismatch is %d should be %d\n" msgstr "dir %lld i8count Nichtübereinstimmung ist %d sollte %d sein\n" #: .././db/check.c:3771 #, c-format msgid "dir %llu size is %lld, should be %d\n" msgstr "dir %llu Größe ist %lld, sollte %d sein\n" #: .././db/check.c:3862 #, c-format msgid "%s quota id %u, have/exp" msgstr "%s Quota-ID %u, have/exp" #: .././db/check.c:3865 #, c-format msgid " bc %lld/%lld" msgstr " bc %lld/%lld" #: .././db/check.c:3869 #, c-format msgid " ic %lld/%lld" msgstr " ic %lld/%lld" #: .././db/check.c:3873 #, c-format msgid " rc %lld/%lld" msgstr " rc %lld/%lld" #: .././db/check.c:3929 #, c-format msgid "can't read superblock for ag %u\n" msgstr "Superblock für ag %u kann nicht gelesen werden\n" #: .././db/check.c:3938 #, c-format msgid "bad sb magic # %#x in ag %u\n" msgstr "falsche magische sb-# %#x in ag %u\n" #: .././db/check.c:3944 #, c-format msgid "bad sb version # %#x in ag %u\n" msgstr "falsche sb-Version # %#x in ag %u\n" #: .././db/check.c:3954 .././db/sb.c:201 msgid "mkfs not completed successfully\n" msgstr "mkfs nicht erfolgreich vervollständigt\n" #: .././db/check.c:3966 .././db/frag.c:368 #, c-format msgid "can't read agf block for ag %u\n" msgstr "agf-Block für ag %u kann nicht gelesen werden\n" #: .././db/check.c:3972 #, c-format msgid "bad agf magic # %#x in ag %u\n" msgstr "falsche magische agf-# %#x in ag %u\n" #: .././db/check.c:3978 #, c-format msgid "bad agf version # %#x in ag %u\n" msgstr "falsche agf-Version # %#x im ag %u\n" #: .././db/check.c:3994 .././db/frag.c:377 #, c-format msgid "can't read agi block for ag %u\n" msgstr "agi-Block für ag %u kann nicht gelesen werden\n" #: .././db/check.c:4000 #, c-format msgid "bad agi magic # %#x in ag %u\n" msgstr "falsche magische agi-# %#x in ag %u\n" #: .././db/check.c:4006 #, c-format msgid "bad agi version # %#x in ag %u\n" msgstr "falsche agi-Version # %#x in ag %u\n" #: .././db/check.c:4031 #, c-format msgid "agf_freeblks %u, counted %u in ag %u\n" msgstr "agf_freeblks %u, gezählt %u in ag %u\n" #: .././db/check.c:4038 #, c-format msgid "agf_longest %u, counted %u in ag %u\n" msgstr "agf_longest %u, gezählt %u in ag %u\n" #: .././db/check.c:4046 #, c-format msgid "agf_btreeblks %u, counted %u in ag %u\n" msgstr "agf_btreeblks %u, gezählt %u in ag %u\n" #: .././db/check.c:4054 #, c-format msgid "agi_count %u, counted %u in ag %u\n" msgstr "agi_count %u, gezählt %u in ag %u\n" #: .././db/check.c:4061 #, c-format msgid "agi_freecount %u, counted %u in ag %u\n" msgstr "agi_freecount %u, gezählt %u in ag %u\n" #: .././db/check.c:4070 #, c-format msgid "agi unlinked bucket %d is %u in ag %u (inode=%lld)\n" msgstr "agi gelöster Verweis Behälter %d ist %u in ag %u (Inode=%lld)\n" #: .././db/check.c:4107 #, c-format msgid "can't read agfl block for ag %u\n" msgstr "agfl-Block für ag %u kann nicht gelesen werden\n" #: .././db/check.c:4126 #, c-format msgid "freeblk count %u != flcount %u in ag %u\n" msgstr "freeblk-Anzahl %u != flcount %u in ag %u\n" #: .././db/check.c:4155 .././db/check.c:4183 .././db/frag.c:400 #: .././db/frag.c:423 .././db/freesp.c:270 #, c-format msgid "can't read btree block %u/%u\n" msgstr "btree-Block %u/%u kann nicht gelesen werden\n" #: .././db/check.c:4216 #, c-format msgid "bad magic # %#x in inode %lld bmbt block %u/%u\n" msgstr "falsche magische # %#x in Inode %lld bmbt-Block %u/%u\n" #: .././db/check.c:4223 #, c-format msgid "expected level %d got %d in inode %lld bmbt block %u/%u\n" msgstr "erwartete Stufe %d hat %d in Inode %lld bmbt-Block %u/%u\n" #: .././db/check.c:4235 .././db/check.c:4252 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in inode %lld bmap block %lld\n" msgstr "" "falsche btree nrecs (%u, Min=%u, Max=%u) in Inode %lld bmap-Block %lld\n" #: .././db/check.c:4280 #, c-format msgid "bad magic # %#x in btbno block %u/%u\n" msgstr "falsche magische # %#x in btbno-Block %u/%u\n" #: .././db/check.c:4289 #, c-format msgid "expected level %d got %d in btbno block %u/%u\n" msgstr "erwartete Stufe %d hat %d in btbno-Block %u/%u\n" #: .././db/check.c:4298 .././db/check.c:4326 .././db/check.c:4371 #: .././db/check.c:4402 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in btbno block %u/%u\n" msgstr "falsche btree nrecs (%u, Min=%u, Max=%u) in btbno-Block %u/%u\n" #: .././db/check.c:4313 #, c-format msgid "out-of-order bno btree record %d (%u %u) block %u/%u\n" msgstr "außer Betreib bno btree Datensatz %d (%u %u) Block %u/%u\n" #: .././db/check.c:4353 #, c-format msgid "bad magic # %#x in btcnt block %u/%u\n" msgstr "falsche magische # %#x in btcnt-Block %u/%u\n" #: .././db/check.c:4362 #, c-format msgid "expected level %d got %d in btcnt block %u/%u\n" msgstr "erwartete Stufe %d hat %d in btcnt-Block %u/%u\n" #: .././db/check.c:4390 #, c-format msgid "out-of-order cnt btree record %d (%u %u) block %u/%u\n" msgstr "außer Betreib cnt btree Datensatz %d (%u %u) Block %u/%u\n" #: .././db/check.c:4433 #, c-format msgid "bad magic # %#x in inobt block %u/%u\n" msgstr "falsche magische # %#x in inobt-Block %u/%u\n" #: .././db/check.c:4440 #, c-format msgid "expected level %d got %d in inobt block %u/%u\n" msgstr "erwartete Stufe %d hat %d in inobt-Block %u/%u\n" #: .././db/check.c:4449 .././db/check.c:4515 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in inobt block %u/%u\n" msgstr "falsche btree nrecs (%u, Min=%u, Max=%u) in inobt-Block %u/%u\n" #: .././db/check.c:4484 .././db/frag.c:493 #, c-format msgid "can't read inode block %u/%u\n" msgstr "btree-Block %u/%u kann nicht gelesen werden\n" #: .././db/check.c:4502 #, c-format msgid "ir_freecount/free mismatch, inode chunk %u/%u, freecount %d nfree %d\n" msgstr "" "ir_freecount/free Nichtübereinstimmung, Inode Speicherstück %u/%u, " "freecount %d nfree %d\n" #: .././db/check.c:4557 #, c-format msgid "setting inode to %lld for block %u/%u\n" msgstr "Inode wird auf %lld gesetzt für Block %u/%u\n" #: .././db/check.c:4589 #, c-format msgid "setting inode to %lld for rtblock %llu\n" msgstr "Inode wird auf %lld gesetzt für rtblock %llu\n" #: .././db/check.c:4605 #, c-format msgid "inode %lld nlink %u %s dir\n" msgstr "Inode %lld nlink %u %s dir\n" #: .././db/addr.c:35 msgid "[field-expression]" msgstr "[Feldausdruck]" #: .././db/addr.c:36 msgid "set current address" msgstr "derzeitige Adresse setzen" #: .././db/addr.c:42 msgid "" "\n" " 'addr' uses the given field to set the filesystem address and type\n" "\n" " Examples:\n" "\n" " sb\n" " a rootino - set the type to inode and set position to the root inode\n" " a u.bmx[0].startblock (for inode with blockmap)\n" "\n" msgstr "" "\n" " »addr« benutzt das gegebene Feld, um die Dateisystemadresse und den Typ\n" " zu setzen\n" "\n" " Beispiele:\n" "\n" " sb\n" " ein Wurzel-ino - setzt den Typ auf Inode und setzt die Position auf den\n" " Wurzel-Inode\n" " ein u.bmx[0].startblock (für Inode mit blockmap)\n" "\n" #: .././db/addr.c:72 .././db/attrset.c:86 .././db/attrset.c:189 #: .././db/print.c:74 .././db/type.c:102 .././db/write.c:101 msgid "no current type\n" msgstr "kein aktueller Typ\n" #: .././db/addr.c:82 #, c-format msgid "no fields for type %s\n" msgstr "keine Felder für Typ %s\n" #: .././db/addr.c:95 msgid "array not allowed for addr command\n" msgstr "Array nicht für addr-Befehl erlaubt\n" #: .././db/addr.c:105 #, c-format msgid "no next type for field %s\n" msgstr "kein nächster Typ für Feld %s\n" #: .././db/addr.c:112 #, c-format msgid "no addr function for field %s (type %s)\n" msgstr "keine addr-Funktion für Feld %s (Typ %s)\n" #: .././db/frag.c:173 #, c-format msgid "actual %llu, ideal %llu, fragmentation factor %.2f%%\n" msgstr "aktuell %llu, ideal %llu, Unterteilungsfaktor %.2f%%\n" #: .././db/frag.c:214 msgid "bad option for frag command\n" msgstr "falsche Opzion für frag-Befehl\n" #: .././db/frag.c:352 #, c-format msgid "inode %lld actual %lld ideal %lld\n" msgstr "Inode %lld aktuell %lld ideal %lld\n" #: .././db/frag.c:446 .././db/frag.c:457 #, c-format msgid "invalid numrecs (%u) in %s block\n" msgstr "ungültige numrecs (%u) in %s-Block\n" #: .././db/agfl.c:36 .././db/agi.c:35 .././db/sb.c:42 .././db/agf.c:35 msgid "[agno]" msgstr "[agno]" #: .././db/agfl.c:37 msgid "set address to agfl block" msgstr "Adresse auf agfl Block setzen" #: .././db/agfl.c:63 msgid "" "\n" " set allocation group freelist\n" "\n" " Example:\n" "\n" " agfl 5\n" " Located in the fourth sector of each allocation group,\n" " the agfl freelist for internal btree space allocation is maintained\n" " for each allocation group. This acts as a reserved pool of space\n" " separate from the general filesystem freespace (not used for user data).\n" "\n" msgstr "" "\n" " Zuteilungsgruppen-freelist setzen\n" "\n" " Beispiel:\n" "\n" " agfl 5\n" " Die agfl freelist, die sich für interne btree-Speicherzuteilung im\n" " vierten Abschnitt jeder Zuteilungsgruppe befindet, wird für jede\n" " Zuteilungsgruppe verwaltet. Dies agiert als ein reservierter Speicherpool\n" " getrennt vom allgemeinen Dateisystem-freespace (nicht für Benutzerdaten\n" " benutzt).\n" "\n" #: .././db/agfl.c:90 .././db/agi.c:89 .././db/sb.c:151 .././db/agf.c:104 #, c-format msgid "bad allocation group number %s\n" msgstr "falsche Zuteilungsgruppennummer %s\n" #: .././db/agi.c:36 msgid "set address to agi header" msgstr "Adressen auf agi-Kopfzeilen setzen" #: .././db/agi.c:64 msgid "" "\n" " set allocation group inode btree\n" "\n" " Example:\n" "\n" " agi 3 (set location to 3rd allocation group inode btree and type to 'agi')\n" "\n" " Located in the 3rd 512 byte block of each allocation group,\n" " the agi inode btree tracks all used/free inodes in the allocation group.\n" " Inodes are allocated in 16k 'chunks', each btree entry tracks a 'chunk'.\n" "\n" msgstr "" "\n" " Zuteilungsgruppen-Inode btree setzen\n" "\n" " Beispiel:\n" "\n" " agi 3 (setzt Ort auf 3. Zuteilungsgruppen-Inode btree und Typ auf " "»agi«)\n" "\n" " Der im dritten 512-Byte-Block von jeder Zuteilungsruppe gelegene\n" " agi-Inode btree spürt alle benutzten/freien Inodes in der\n" " Zuteilungsgruppe auf. Inodes sind in 16k-»chunks« zugeteilt, jeder\n" " btree-Eintrag folgt einem »chunk«.\n" "\n" #: .././db/attrset.c:38 msgid "[-r|-s|-p|-u] [-n] [-R|-C] [-v n] name" msgstr "[-r|-s|-p|-u] [-n] [-R|-C] [-v n] Name" #: .././db/attrset.c:39 msgid "set the named attribute on the current inode" msgstr "das Namens-Attribut des aktuellen Inodes setzen" #: .././db/attrset.c:42 msgid "[-r|-s|-p|-u] [-n] name" msgstr "[-r|-s|-p|-u] [-n] Name" #: .././db/attrset.c:43 msgid "remove the named attribute from the current inode" msgstr "das genannte Attribut aus dem aktuellen Inode entfernen" #: .././db/attrset.c:49 msgid "" "\n" " The 'attr_set' and 'attr_remove' commands provide interfaces for debugging\n" " the extended attribute allocation and removal code.\n" " Both commands require an attribute name to be specified, and the attr_set\n" " command allows an optional value length (-v) to be provided as well.\n" " There are 4 namespace flags:\n" " -r -- 'root'\n" " -u -- 'user'\t\t(default)\n" " -s -- 'secure'\n" "\n" " For attr_set, these options further define the type of set operation:\n" " -C -- 'create' - create attribute, fail if it already exists\n" " -R -- 'replace' - replace attribute, fail if it does not exist\n" " The backward compatibility mode 'noattr2' can be emulated (-n) also.\n" "\n" msgstr "" "\n" " Die »attr_set«- und xattr_remove«-Befehle stellen Schittstellen für die\n" " Fehlersuche in der erweiterten Attributszuteilung und Code-Entfernung\n" " zur Verfügung. Beide Befehle benötigen zur Angabe einen Attributs-Namen\n" " und der attr_set-Befehl erlaubt außerdem die Angabe einer optionalen\n" " Wertlänge (-v).\n" " Es gibt vier Namensraumkennzeichen:\n" " -r -- 'root'\n" " -u -- 'user'\t\t(Vorgabe)\n" " -s -- 'secure'\n" "\n" " Für attr-set definieren diese Optionen weiterhin den Typ der\n" " Einstelloperation:\n" " -C -- »createy - erzeugt Attribut, scheitert, wenn es bereits besteht\n" " -R -- »replace« - ersetzt Attribut, scheitert, wenn es nicht besteht\n" " Außerdem kann der Rückwärtskompatibilitätsmodus »noattr2« (-n) emuliert\n" " werden.\n" #: .././db/attrset.c:90 .././db/attrset.c:193 msgid "current type is not inode\n" msgstr "aktueller Typ ist nicht Inode\n" #: .././db/attrset.c:125 #, c-format msgid "bad attr_set valuelen %s\n" msgstr "falsche attr_set valuelen %s\n" #: .././db/attrset.c:131 msgid "bad option for attr_set command\n" msgstr "falsche Option für attr_set-Befehl\n" #: .././db/attrset.c:137 msgid "too few options for attr_set (no name given)\n" msgstr "zu wenige Optionen für attr_set (kein Name angegeben)\n" #: .././db/attrset.c:147 #, c-format msgid "cannot allocate buffer (%d)\n" msgstr "Puffer (%d) kann nicht zugeteilt werden\n" #: .././db/attrset.c:156 .././db/attrset.c:231 #, c-format msgid "failed to iget inode %llu\n" msgstr "iget von Inode %llu fehlgeschlagen\n" #: .././db/attrset.c:162 #, c-format msgid "failed to set attr %s on inode %llu\n" msgstr "attr %s auf Inode %llu zu setzen ist fehlgeschlagen\n" #: .././db/attrset.c:217 msgid "bad option for attr_remove command\n" msgstr "falsche Option für attr_remove-Befehl\n" #: .././db/attrset.c:223 msgid "too few options for attr_remove (no name given)\n" msgstr "zu wenige Optionen für attr_remove (kein Name angegeben)\n" #: .././db/attrset.c:237 #, c-format msgid "failed to remove attr %s from inode %llu\n" msgstr "Entfernen von attr %s von Inode %llu fehlgeschlagen\n" #: .././db/block.c:43 .././db/block.c:49 msgid "filoff" msgstr "filoff" #: .././db/block.c:44 msgid "set address to file offset (attr fork)" msgstr "Adresse auf Dateiversatz setzen (attr fork)" #: .././db/block.c:46 msgid "[d]" msgstr "[d]" #: .././db/block.c:47 msgid "set address to daddr value" msgstr "Adresse auf daddr-Wert setzen" #: .././db/block.c:50 msgid "set address to file offset (data fork)" msgstr "Adresse auf Dateiversatz setzen (Daten-fork)" #: .././db/block.c:52 msgid "[fsb]" msgstr "[fsb]" #: .././db/block.c:53 msgid "set address to fsblock value" msgstr "Adresse auf fsblock-Wert setzen" #: .././db/block.c:59 msgid "" "\n" " Example:\n" "\n" " 'ablock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's attribute fork. The filesystem block size is specified in\n" " the superblock.\n" "\n" msgstr "" "\n" " Beispiel:\n" "\n" " »ablock 23« - setzt die Dateiposition auf den 23. Dateisystemblock im\n" " Attributs-Fork des Inodes. Die Dateisystemblockgröße ist im Superblock\n" " angegeben.\n" "\n" #: .././db/block.c:82 .././db/block.c:177 #, c-format msgid "bad block number %s\n" msgstr "falsche Blocknummer %s\n" #: .././db/block.c:90 msgid "no attribute data for file\n" msgstr "Attributsdaten für Datei\n" #: .././db/block.c:96 msgid "file attr block is unmapped\n" msgstr "attr-Block der Datei ist nicht abgebildet\n" #: .././db/block.c:119 msgid "" "\n" " Example:\n" "\n" " 'daddr 102' - sets position to the 102nd absolute disk block\n" " (512 byte block).\n" msgstr "" "\n" " Beispiel:\n" "\n" " »daddr 102« - setzt Position auf den 102. absoluten Plattenblock\n" " (512 Byte-Block).\n" #: .././db/block.c:135 #, c-format msgid "current daddr is %lld\n" msgstr "aktuelle daddr ist %lld\n" #: .././db/block.c:141 #, c-format msgid "bad daddr %s\n" msgstr "falsche daddr %s\n" #: .././db/block.c:153 msgid "" "\n" " Example:\n" "\n" " 'dblock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's data fork. The filesystem block size is specified in the\n" " superblock.\n" "\n" msgstr "" "\n" " Beispiel:\n" "\n" " »dblock 23« - setzt die Dateiposition auf den 23. Dateisystemblock im\n" " Daten-Fork des Inodes. Die Dateisystemblockgröße ist im Superblock\n" " angegeben.\n" "\n" #: .././db/block.c:185 msgid "no type for file data\n" msgstr "kein Typ für Dateidaten\n" #: .././db/block.c:192 msgid "file data block is unmapped\n" msgstr "Dateidatenblock ist nicht abgebildet\n" #: .././db/block.c:210 msgid "" "\n" " Example:\n" "\n" " 'fsblock 1023' - sets the file position to the 1023rd filesystem block.\n" " The filesystem block size is specified in the superblock and set during\n" " mkfs time. Offset is absolute (not AG relative).\n" "\n" msgstr "" "\n" " Beispiel:\n" "\n" " »fsblock 1023« - setzt die Dateiposition auf den 1023. Dateisystemblock.\n" " Die Dateisystemblockgröße ist im Superblock angegeben und wurde während \n" " der mkfs-Zeit gesetzt. Versatz ist absolut (nicht AG-relativ).\n" "\n" #: .././db/block.c:229 #, c-format msgid "current fsblock is %lld\n" msgstr "aktueller fsblock ist %lld\n" #: .././db/block.c:235 .././db/block.c:241 #, c-format msgid "bad fsblock %s\n" msgstr "falscher fsblock %s\n" #: .././db/bmap.c:39 msgid "[-ad] [block [len]]" msgstr "[-ad] [Block [len]]" #: .././db/bmap.c:40 msgid "show block map for current file" msgstr "Blockkarte für aktuelle Datei anzeigen" #: .././db/bmap.c:153 .././db/inode.c:386 msgid "no current inode\n" msgstr "kein aktueller Inode\n" #: .././db/bmap.c:166 msgid "bad option for bmap command\n" msgstr "falsche Option für bmap-Befehl\n" #: .././db/bmap.c:183 #, c-format msgid "bad block number for bmap %s\n" msgstr "falsche Blocknummer für bmap %s\n" #: .././db/bmap.c:191 #, c-format msgid "bad len for bmap %s\n" msgstr "falsche len für bmap %s\n" #: .././db/bmap.c:214 #, c-format msgid "%s offset %lld startblock %llu (%u/%u) count %llu flag %u\n" msgstr "%s Versatz %lld Startblock %llu (%u/%u) zählt %llu Flag %u\n" #: .././db/command.c:82 .././db/help.c:56 .././libxcmd/help.c:49 #, c-format msgid "command %s not found\n" msgstr "Befehl %s nicht gefunden\n" #: .././db/command.c:86 #, c-format msgid "bad argument count %d to %s, expected " msgstr "falsche Argument-Anzahl %d bis %s, erwartet" #: .././db/command.c:88 #, c-format msgid "at least %d" msgstr "mindestens %d" #: .././db/command.c:92 #, c-format msgid "between %d and %d" msgstr "zwischen %d und %d" #: .././db/command.c:93 msgid " arguments\n" msgstr "Argumente\n" #: .././db/convert.c:171 #, c-format msgid "bad argument count %d to convert, expected 3,5,7,9 arguments\n" msgstr "falsche Argument-Anzahl %d zu konvertieren, 3,5,7,9 Argumente erwartet\n" #: .././db/convert.c:176 .././db/convert.c:183 #, c-format msgid "unknown conversion type %s\n" msgstr "unbekannte Umwandlungstyp %s\n" #: .././db/convert.c:187 msgid "result type same as argument\n" msgstr "Ergebnistyp entspricht Argument\n" #: .././db/convert.c:191 #, c-format msgid "conflicting conversion type %s\n" msgstr "widersprüchlicher Umwandlungstyp %s\n" #: .././db/convert.c:270 #, c-format msgid "%s is not a number\n" msgstr "%s ist keine Zahl\n" #: .././db/debug.c:27 msgid "[flagbits]" msgstr "[flagbits]" #: .././db/debug.c:28 msgid "set debug option bits" msgstr "Bits für Fehlersuchoptionen setzen" #: .././db/debug.c:42 #, c-format msgid "bad value for debug %s\n" msgstr "falscher Wert für Fehlersuche %s\n" #: .././db/dquot.c:37 msgid "[projid|gid|uid]" msgstr "[projid|gid|uid]" #: .././db/dquot.c:38 msgid "set current address to project, group or user quota block" msgstr "aktuelle Adresse auf Projekt, Gruppe oder Benutzer-Quota setzen" #: .././db/dquot.c:124 msgid "bad option for dquot command\n" msgstr "falsche Option für dquot-Befehl\n" #: .././db/dquot.c:128 .././quota/project.c:347 msgid "project" msgstr "Projekt" #: .././db/dquot.c:128 msgid "group" msgstr "Gruppe" #: .././db/dquot.c:128 msgid "user" msgstr "Benutzer" #: .././db/dquot.c:130 #, c-format msgid "dquot command requires one %s id argument\n" msgstr "dquot-Befehl benötigt ein %s ID-Argument\n" #: .././db/dquot.c:137 #, c-format msgid "no %s quota inode present\n" msgstr "kein %s Quota-Inode vorhanden\n" #: .././db/dquot.c:142 #, c-format msgid "bad %s id for dquot %s\n" msgstr "falsche %s ID für dquot %s\n" #: .././db/dquot.c:154 #, c-format msgid "no %s quota data for id %d\n" msgstr "keine %s Quota-Daten für ID %d\n" #: .././db/echo.c:27 msgid "[args]..." msgstr "[args] ..." #: .././db/echo.c:28 msgid "echo arguments" msgstr "echo Argumente" #: .././db/faddr.c:40 .././db/faddr.c:63 msgid "no current allocation group, cannot set new addr\n" msgstr "" "keine aktuelle Zuteilungsgruppe, neue addr kann nicht gesetzt werden\n" #: .././db/faddr.c:45 .././db/faddr.c:117 .././db/faddr.c:148 #: .././db/faddr.c:180 .././db/faddr.c:202 .././db/faddr.c:232 #: .././db/faddr.c:262 .././db/faddr.c:316 .././db/faddr.c:335 msgid "null block number, cannot set new addr\n" msgstr "Nullblocknummer, neue addr kann nicht gesetzt werden\n" #: .././db/faddr.c:68 .././db/faddr.c:353 .././db/faddr.c:371 #: .././db/faddr.c:389 msgid "null inode number, cannot set new addr\n" msgstr "Null-Inode-Nummer, neue addr kann nicht gesetzt werden\n" #: .././db/faddr.c:88 msgid "null attribute block number, cannot set new addr\n" msgstr "Null-Attributsblocknummer, neue addr kann nicht gesetzt werden\n" #: .././db/faddr.c:94 msgid "attribute block is unmapped\n" msgstr "Attributsblock ist unmapped\n" #: .././db/faddr.c:123 .././db/faddr.c:155 .././db/faddr.c:208 #: .././db/faddr.c:239 msgid "file block is unmapped\n" msgstr "Dateiblock ist unmapped\n" #: .././db/faddr.c:285 msgid "null directory block number, cannot set new addr\n" msgstr "Null-Verzeichnisblocknummer, neue addr kann nicht gesetzt werden\n" #: .././db/faddr.c:292 msgid "directory block is unmapped\n" msgstr "Verzeichnisblock ist unmapped\n" #: .././db/flist.c:149 #, c-format msgid "field %s not found\n" msgstr "Feld %s nicht gefunden\n" #: .././db/flist.c:159 #, c-format msgid "no elements in %s\n" msgstr "keine Elemente in %s\n" #: .././db/flist.c:165 #, c-format msgid "indices %d-%d for field %s out of range %d-%d\n" msgstr "Indizes %d-%d für Feld %s außerhalb des Bereichs %d-%d\n" #: .././db/flist.c:173 #, c-format msgid "index %d for field %s out of range %d-%d\n" msgstr "Index %d für Feld %s außerhalb des Bereichs %d-%d\n" #: .././db/flist.c:187 #, c-format msgid "field %s is not an array\n" msgstr "Feld %s ist kein Array\n" #: .././db/flist.c:200 #, c-format msgid "field %s has no subfields\n" msgstr "Feld %s hat keine Unterfelder\n" #: .././db/flist.c:220 #, c-format msgid "fl@%p:\n" msgstr "fl@%p:\n" #: .././db/flist.c:221 #, c-format msgid "\tname=%s, fld=%p, child=%p, sibling=%p\n" msgstr "\tName=%s, fld=%p, Kind=%p, Geschwister=%p\n" #: .././db/flist.c:223 #, c-format msgid "\tlow=%d, high=%d, flags=%d (%s%s), offset=%d\n" msgstr "\tniedrig=%d, hoch=%d, Kennzeichen=%d (%s%s), Versatz=%d\n" #: .././db/flist.c:225 msgid "oklow " msgstr "oklow" #: .././db/flist.c:226 msgid "okhigh" msgstr "okhigh" #: .././db/flist.c:227 #, c-format msgid "\tfld->name=%s, fld->ftyp=%d (%s)\n" msgstr "\tfld->name=%s, fld->ftyp=%d (%s)\n" #: .././db/flist.c:230 #, c-format msgid "\tfld->flags=%d (%s%s%s%s%s)\n" msgstr "\tfld->flags=%d (%s%s%s%s%s)\n" #: .././db/flist.c:322 #, c-format msgid "bad syntax in field name %s\n" msgstr "falsche Syntax in Feldname %s\n" #: .././db/flist.c:378 #, c-format msgid "missing closing quote %s\n" msgstr "fehlendes schließendes Anführungszeichen %s\n" #: .././db/flist.c:395 #, c-format msgid "bad character in field %s\n" msgstr "falsches Zeichen in Feld %s\n" #: .././db/fprint.c:98 msgid "null" msgstr "null" #: .././db/freesp.c:106 #, c-format msgid "total free extents %lld\n" msgstr "gesamte freie Extents %lld\n" #: .././db/freesp.c:107 #, c-format msgid "total free blocks %lld\n" msgstr "gesamte freie Blöcke %lld\n" #: .././db/freesp.c:108 #, c-format msgid "average free extent size %g\n" msgstr "durchschnittliche freie Extent-Größe %g\n" #: .././db/freesp.c:199 msgid "" "freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... [-m binmult]\n" msgstr "" "freesp-Argumente: [-bcds] [-a agno] [-e binsize] [-h h1]... [-m binmult]\n" #: .././db/freesp.c:400 msgid "from" msgstr "von" #: .././db/freesp.c:400 msgid "to" msgstr "bis" #: .././db/freesp.c:400 .././repair/progress.c:26 msgid "extents" msgstr "Extents" #: .././db/freesp.c:400 .././repair/progress.c:18 msgid "blocks" msgstr "Blöcke" #: .././db/freesp.c:400 msgid "pct" msgstr "pct" #: .././db/hash.c:30 msgid "string" msgstr "Zeichenkette" #: .././db/hash.c:31 msgid "calculate hash value" msgstr "Hash-Wert berechnen" #: .././db/hash.c:37 msgid "" "\n" " 'hash' prints out the calculated hash value for a string using the\n" "directory/attribute code hash function.\n" "\n" " Usage: \"hash \"\n" "\n" msgstr "" "\n" "»hash« gibt den berechneten Hash-Wert für eine Zeichenkette unter\n" "Benutzung der Verzeichnis-/Code-Hash-Funktion aus .\n" "\n" "Aufruf: »hash «\n" "\n" #: .././db/help.c:30 .././db/io.c:48 .././libxcmd/help.c:92 msgid "[command]" msgstr "[Befehl]" #: .././db/help.c:31 .././libxcmd/help.c:93 msgid "help for one or all commands" msgstr "Hilfe für einen oder alle Befehle" #: .././db/help.c:40 .././libxcmd/help.c:33 #, c-format msgid "" "\n" "Use 'help commandname' for extended help.\n" msgstr "" "\n" "»help Befehlsname« benutzen, um erweitere Hilfe zu erhalten.\n" #: .././db/help.c:89 #, c-format msgid "(or %s) " msgstr "(oder %s) " #: .././db/init.c:46 #, c-format msgid "Usage: %s [-fFrxV] [-p prog] [-l logdev] [-c cmd]... device\n" msgstr "Aufruf: %s [-fFrxV] [-p Programm] [-l logdev] [-c Befehl]... Gerät\n" #: .././db/init.c:112 msgid "" "\n" "fatal error -- couldn't initialize XFS library\n" msgstr "" "\n" "fataler Fehler -- XFS-Bibliothek kann nicht initialisiert werden\n" #: .././db/init.c:118 #, c-format msgid "%s: %s is invalid (cannot read first 512 bytes)\n" msgstr "" "%s: %s ist ungültig (die ersten 512 Bytes können nicht gelesen werden)\n" #: .././db/init.c:129 #, c-format msgid "" "%s: %s is not a valid XFS filesystem (unexpected SB magic number 0x%08x)\n" msgstr "" "%s: %s ist kein gültige XFS-Dateisystem (unerwartete SB Magische\n" "Nummer 0x%08x)\n" #: .././db/init.c:141 #, c-format msgid "%s: device %s unusable (not an XFS filesystem?)\n" msgstr "%s: Gerät %s unbenutzbar (kein XFS-Dateisystem?)\n" #: .././db/inode.c:381 #, c-format msgid "bad value for inode number %s\n" msgstr "falscher Wert für Inode-Nummer %s\n" #: .././db/inode.c:388 #, c-format msgid "current inode number is %lld\n" msgstr "aktuelle Inode-Nummer ist %lld\n" #: .././db/inode.c:596 #, c-format msgid "bad inode number %lld\n" msgstr "falsche Inode-Nummer %lld\n" #: .././db/input.c:43 msgid "source-file" msgstr "Quelldatei" #: .././db/input.c:44 msgid "get commands from source-file" msgstr "Befehle aus Quelldatei beziehen" #: .././db/input.c:320 #, c-format msgid "can't open %s\n" msgstr "%s kann nicht geöffnet werden\n" #: .././db/io.c:46 msgid "pop location from the stack" msgstr "Ort vom Stack hervorholen" #: .././db/io.c:49 msgid "push location to the stack" msgstr "Ort auf den Stack bewegen" #: .././db/io.c:52 msgid "view the location stack" msgstr "den Stack-Ort ansehen" #: .././db/io.c:55 msgid "move forward to next entry in the position ring" msgstr "vorwärts zum nächsten Eintrag im Positionsring bewegen" #: .././db/io.c:58 msgid "move to the previous location in the position ring" msgstr "zum vorherigen Ort im Positionsring bewegen" #: .././db/io.c:61 msgid "show position ring or move to a specific entry" msgstr "Positionsring anzeigen oder zu einem bestimmten Eintrag bewegen" #: .././db/io.c:91 #, c-format msgid "can't set block offset to %d\n" msgstr "Blockversatz kann nicht auf %d gesetzt werden\n" #: .././db/io.c:104 msgid "can't pop anything from I/O stack\n" msgstr "vom I/O-Stack kann nichts hervorgeholt werden\n" #: .././db/io.c:132 msgid "" "\n" " Changes the address and data type to the first entry on the stack.\n" "\n" msgstr "" "\n" " Ändert die Adresse und den Datentyp auf den ersten Eintrag auf dem\n" " Stack.\n" "\n" #: .././db/io.c:146 #, c-format msgid "\tbyte offset %lld, length %d\n" msgstr "\tByte Versatz %lld, Länge %d\n" #: .././db/io.c:147 #, c-format msgid "\tbuffer block %lld (fsbno %lld), %d bb%s\n" msgstr "\tPufferblock %lld (fsbno %lld), %d bb%s\n" #: .././db/io.c:151 msgid "\tblock map" msgstr "\tBlockekarte" #: .././db/io.c:156 #, c-format msgid "\tinode %lld, dir inode %lld, type %s\n" msgstr "\tInode %lld, dir Inode %lld, Typ %s\n" #: .././db/io.c:157 .././growfs/xfs_growfs.c:86 .././logprint/log_misc.c:151 #: .././mkfs/xfs_mkfs.c:1666 #, c-format msgid "none" msgstr "keine" #: .././db/io.c:167 msgid "no entries in location ring.\n" msgstr "keine Einträge im Positionsring.\n" #: .././db/io.c:171 msgid " type bblock bblen fsbno inode\n" msgstr " Typ bblock bblen fsbno Inode\n" #: .././db/io.c:225 #, c-format msgid "no such command %s\n" msgstr "kein solcher Befehl -- %s\n" #: .././db/io.c:229 #, c-format msgid "no push form allowed for %s\n" msgstr "keine Verschiebeform für %s erlaubt\n" #: .././db/io.c:253 msgid "" "\n" " Allows you to push the current address and data type on the stack for\n" " later return. 'push' also accepts an additional command to execute after\n" " storing the current address (ex: 'push a rootino' from the superblock).\n" "\n" msgstr "" "\n" " Erlaubt Ihnen die aktuelle Adresse und den Datentyp für eine spätere\n" " Rückgabe auf den Stack zu verschieben. »push« akzeptiert außerdem die\n" " Ausführung eines zusätzlichen Befehls nach dem Speichern der aktuellen\n" " Adresse (z.B.: »push a rootino« von einem Superblock).\n" "\n" #: .././db/io.c:269 .././db/io.c:310 msgid "ring is empty\n" msgstr "Ring ist leer\n" #: .././db/io.c:273 msgid "no further entries\n" msgstr "keine weiteren Einträge\n" #: .././db/io.c:293 msgid "" "\n" " The 'forward' ('f') command moves to the next location in the position\n" " ring, updating the current position and data type. If the current " "location\n" " is the top entry in the ring, then the 'forward' command will have\n" " no effect.\n" "\n" msgstr "" "\n" " Der »forward«-Befehl (»f«) bewegt zum nächsten Ort im Positionsring und\n" " aktualisiert dabei die aktuelle Position und den Datentyp. Wenn der\n" " aktuelle Ort der oberste Eintrag im Ring ist, dann hat der\n" " »forward«-Befehl keine Auswirkung.\n" "\n" #: .././db/io.c:314 msgid "no previous entries\n" msgstr "keine vorherigen Einträge\n" #: .././db/io.c:334 msgid "" "\n" " The 'back' ('b') command moves to the previous location in the position\n" " ring, updating the current position and data type. If the current " "location\n" " is the last entry in the ring, then the 'back' command will have no " "effect.\n" "\n" msgstr "" "\n" " Der »back«-Befehl (»b«) bewegt zum vorherigen Ort im Positionsring und\n" " aktualisiert dabei die aktuelle Position und den Datentyp. Wenn der\n" " aktuelle Ort der letzte Eintrag im Ring ist, dann hat der\n" "»forward«-Befehl keine Auswirkung.\n" "\n" #: .././db/io.c:357 #, c-format msgid "invalid entry: %d\n" msgstr "ungültiger Eintrag: %d\n" #: .././db/io.c:374 #, c-format msgid "" "\n" " The position ring automatically keeps track of each disk location and\n" " structure type for each change of position you make during your xfs_db\n" " session. The last %d most recent entries are kept in the ring.\n" "\n" " To display the current list of ring entries type 'ring' by itself on\n" " the command line. The entry highlighted by an asterisk ('*') is the\n" " current entry.\n" "\n" " To move to another entry in the ring type 'ring ' where is\n" " your desired entry from the ring position list.\n" "\n" " You may also use the 'forward' ('f') or 'back' ('b') commands to move\n" " to the previous or next entry in the ring, respectively.\n" "\n" " Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n" " location implicitly. Use the 'push' and 'pop' commands if you wish to\n" " store a specific location explicitly for later return.\n" "\n" msgstr "" "\n" " Der Positionsring verfolgt automatisch jeden Plattenort und -Strukturtyp\n" " von jeder Positionsänderung, die Sie während einer xfs_db-Sitzung\n" " vornehmen. Die aktuellsten %d Einträge werden im Ring behalten.\n" "\n" " Um die aktuelle Liste der Ringeinträge anzuzeigen tippen Sie\n" " selbstständig »ring« auf der Befehlszeile ein. Der von einem Stern (»*«)\n" " hervorgehobene Eintrag ist der aktuelle Eintrag.\n" "\n" " Um sich zu einem anderen Eintrag im Ring zu bewegen, tippen Sie\n" " »Ring « wobei Ihr gewümschter Eintrag von der\n" " Ringpositionsliste ist.\n" "\n" " Sie könnten außerdem die »forward«- (»f«) oder »back« (»b«) -Befehle\n" " benutzen, um sich zum vorherigen beziehungsweise nächsten Eintrag im Ring\n" " zu bewegen.\n" "\n" " Anmerkung: Anders als bei den »stack«-, »push«- und »pop«-Befehlen,\n" " verfolgt der Ring vorbehaltlos ihrem Ort. Benutzen Sie die »push«- und\n" " »pop«-Befehle, wenn Sie einen bestimmten Ort für eine spätere Rückkehr\n" " ausdrücklich speichern möchten.\n" "\n" #: .././db/io.c:438 .././db/io.c:481 #, c-format msgid "can't seek in filesystem at bb %lld\n" msgstr "im Dateisystem kann nicht bei bb %lld gesucht werden\n" #: .././db/io.c:515 msgid "nothing to write\n" msgstr "nichts zu schreiben\n" #: .././db/io.c:521 #, c-format msgid "incomplete write, block: %lld\n" msgstr "unvollständig geschrieben, Block: %lld\n" #: .././db/io.c:524 #, c-format msgid "write error: %s\n" msgstr "Schreibfehler: %s\n" #: .././db/io.c:529 #, c-format msgid "incomplete read, block: %lld\n" msgstr "unvollständig gelesen, Block: %lld\n" #: .././db/io.c:532 #, c-format msgid "read error: %s\n" msgstr "Lesefehler: %s\n" #: .././db/io.c:548 msgid "set_cur no stack element to set\n" msgstr "set_cur kein Stack-Element zu setzen\n" #: .././db/io.c:554 #, c-format msgid "xfs_db got a bbmap for %lld\n" msgstr "xfs_db hat eine bbmap für %lld\n" #: .././db/io.c:585 msgid "" "\n" " The stack is used to explicitly store your location and data type\n" " for later return. The 'push' operation stores the current address\n" " and type on the stack, the 'pop' operation returns you to the\n" " position and datatype of the top entry on the stack.\n" "\n" " The 'stack' allows explicit location saves, see 'ring' for implicit\n" " position tracking.\n" "\n" msgstr "" "\n" " Der Stack wird benutzt, um Ihren Ort und Datentyp explizit für eine\n" " spätere Rückgabe zu speichern. Die »push«-Operation speichert die\n" " aktuelle Adresse und den Typ auf dem Stack, die»pop«-Operation gibt\n" " Ihnen die Position und den Datentyp des obersten Eintrags auf dem Stack\n" " zurück.\n" "\n" " Der »Stack« erlaubt explizite Ortsspeicherungen. Sehen Sie »ring« für\n" " ausdrückliche Psoitionsvefolgung.\n" "\n" #: .././db/malloc.c:27 #, c-format msgid "%s: out of memory\n" msgstr "%s: außerhalb des Speichers\n" #: .././db/metadump.c:47 msgid "[-e] [-g] [-m max_extent] [-w] [-o] filename" msgstr "[-e] [-g] [-m max_extent] [-w] [-o] Dateiname" #: .././db/metadump.c:48 msgid "dump metadata to a file" msgstr "Metadatenauszug in eine Datei" #: .././db/metadump.c:78 #, c-format msgid "" "\n" " The 'metadump' command dumps the known metadata to a compact file suitable\n" " for compressing and sending to an XFS maintainer for corruption analysis \n" " or xfs_repair failures.\n" "\n" " Options:\n" " -e -- Ignore read errors and keep going\n" " -g -- Display dump progress\n" " -m -- Specify max extent size in blocks to copy (default = %d blocks)\n" " -o -- Don't obfuscate names and extended attributes\n" " -w -- Show warnings of bad metadata information\n" "\n" msgstr "" "\n" " Der »Metadaten«-Befehl macht einen Auszug der bekannten Metadaten in eine\n" " kompakte Datei, die geeignet ist, um komprimiert und an einen\n" " XFS-Betreuer zur Beschädigungsanalyse oder xfs_repair-Ausfälle gesendet\n" " zu werden.\n" "\n" " Optionen:\n" " -e -- Lesefehler ignorieren und am Laufen halten\n" " -g -- Auszugsfortschritt anzeigen\n" " -m -- Maximale Extent-Größe in Blocks zum Kopieren angeben\n" " (Vorgabe = %d Blöcke)\n" " -o -- Namen und erweiterte Attribute nicht verschleiern\n" " -w -- Warnungen von flaschen Metadateninformationen anzeigen\n" "\n" #: .././db/output.c:30 msgid "[stop|start ]" msgstr "[stop|start ]" #: .././db/output.c:31 msgid "start or stop logging to a file" msgstr "Protokollieren in eine Datei starten oder stoppen" #: .././db/output.c:68 #, c-format msgid "logging to %s\n" msgstr "Protokollieren nach %s\n" #: .././db/output.c:70 .././db/output.c:77 msgid "no log file\n" msgstr "kein Protokolldatei\n" #: .././db/output.c:80 #, c-format msgid "already logging to %s\n" msgstr "es wird bereits nach %s protokolliet\n" #: .././db/output.c:84 #, c-format msgid "can't open %s for writing\n" msgstr "%s kann nicht zum Schreiben geöffnet werden\n" #: .././db/output.c:90 msgid "bad log command, ignored\n" msgstr "falscher Protokollbefehl, ignoriert\n" #: .././db/print.c:41 msgid "[value]..." msgstr "[Wert] ..." #: .././db/print.c:42 msgid "print field values" msgstr "Feldwerte ausgeben" #: .././db/print.c:79 #, c-format msgid "no print function for type %s\n" msgstr "keine Ausgabefunktion für Typ %s\n" #: .././db/print.c:153 msgid "(empty)\n" msgstr "(leer)\n" #: .././db/print.c:215 msgid "(empty)" msgstr "(leer)" #: .././db/print.c:275 msgid "no arguments allowed\n" msgstr "keine Argumente erlaubt\n" #: .././db/quit.c:27 msgid "exit xfs_db" msgstr "xfs_db beenden" #: .././db/sb.c:43 msgid "set current address to sb header" msgstr "aktuelle Adresse auf sb-Kopfzeilen setzen" #: .././db/sb.c:45 msgid "[uuid]" msgstr "[uuid]" #: .././db/sb.c:46 msgid "write/print FS uuid" msgstr "FS uuid schreiben/ausgeben" #: .././db/sb.c:48 msgid "[label]" msgstr "[Etikett]" #: .././db/sb.c:49 msgid "write/print FS label" msgstr "FS-Etikett schreiben/ausgeben" #: .././db/sb.c:51 msgid "[feature | [vnum fnum]]" msgstr "[feature | [vnum fnum]]" #: .././db/sb.c:52 msgid "set feature bit(s) in the sb version field" msgstr "Merkmal-Bit(s) im sb-Versionsfeld setzen" #: .././db/sb.c:124 msgid "" "\n" " set allocation group superblock\n" "\n" " Example:\n" "\n" " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" "\n" " Located in the first sector of each allocation group, the superblock\n" " contains the base information for the filesystem.\n" " The superblock in allocation group 0 is the primary. The copies in the\n" " remaining allocation groups only serve as backup for filesystem recovery.\n" " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" "\n" msgstr "" "\n" " Zuweisungsgruppen-Superblock setzen\n\n" "\n" " Beispiel:\n" "\n" " 'sb 7' - setzt Ort auf den 7. Zuweisungsgruppen-Superblock, setzt Typ auf\n" " »sb«\n" "\n" " Im ersten Abschnitt jeder Zuweisungsgruppe gelegen, enthält der\n" " Superblock die Basisinformationen des Dateisystems.\n" " Der Superblock in Zuweisungsgruppe 0 ist der Primäre. Die Kopien in den\n" " verbleibenden Zuweisungsgruppen dienen nur als Sicherung zur\n" " Wiederherstellung des Dateisystems. Die icount/ifree/fdblocks/frextents\n" " werden nur im Superblock 0 aktualisiert.\n" "\n" #: .././db/sb.c:183 #, c-format msgid "can't read superblock for AG %u\n" msgstr "Superblock für AG %u kann nicht gelesen werden\n" #: .././db/sb.c:191 #, c-format msgid "bad sb magic # %#x in AG %u\n" msgstr "falsche magische sb # %#x in AG %u\n" #: .././db/sb.c:196 #, c-format msgid "bad sb version # %#x in AG %u\n" msgstr "falsche sb-Version # %#x in AG %u\n" #: .././db/sb.c:218 msgid "aborting - external log specified for FS with an internal log\n" msgstr "" "Abbruch - externes Protokoll für FS mit einem internen Protokoll angegeben\n" #: .././db/sb.c:224 msgid "aborting - no external log specified for FS with an external log\n" msgstr "" "Abbruch - kein externes Protokoll für FS mit einem externen Protokoll\n" "angegeben\n" #: .././db/sb.c:242 msgid "ERROR: cannot find log head/tail, run xfs_repair\n" msgstr "" "FEHLER: Protokoll head/tail wurde nicht gefunden, führen Sie xfs_repair\n" "aus\n" #: .././db/sb.c:247 #, c-format msgid "" "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running %s. If you are unable to mount the filesystem, then use\n" "the xfs_repair -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n" msgstr "" "FEHLER: Das Dateisystem hat wertvolle Metadaten-Änderungen in einem\n" "Protokoll, das wiederholt werden sollte. Hängen Sie das Dateisystem ein,\n" "um das Protokoll zu wiederholen und hängen Sie es wieder aus before Sie\n" "%s erneut auszuführen. Wenn Sie außer Stande sind, das Dateisystem\n" "einzuhängen, benutzen Sie die xfs_repair-Option -L, um das Protokoll zu\n" "zerstören und versuchen Sie eine Reparatur.\n" "Beachten Sie, dass die Zerstörung des Protokolls Schaden verursachen\n" "kann -- bitte versuchen Sie, das Dateisystem einzuhängen ehe Sie dies tun.\n" #: .././db/sb.c:264 msgid "Clearing log and setting UUID\n" msgstr "Protokoll wird geleert und UUID gesetzt\n" #: .././db/sb.c:273 msgid "ERROR: cannot clear the log\n" msgstr "FEHLER: Protokoll kann nicht geleert werden\n" #: .././db/sb.c:284 msgid "" "\n" " write/print FS uuid\n" "\n" " Example:\n" "\n" " 'uuid' - print UUID\n" " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" " 'uuid generate' - generate and write\n" " 'uuid rewrite' - copy UUID from SB 0\n" "\n" "The print function checks the UUID in each SB and will warn if the UUIDs\n" "differ between AGs (the log is not checked). The write commands will\n" "set the uuid in all AGs to either a specified value, a newly generated\n" "value or the value found in the first superblock (SB 0) respectively.\n" "As a side effect of writing the UUID, the log is cleared (which is fine\n" "on a CLEANLY unmounted FS).\n" "\n" msgstr "" "\n" " FS-uuid schreiben/ausgeben\n" "\n" " Beispiel:\n" "\n" " 'uuid' - gibt UUID aus\n" " 'uuid 01234567-0123-0123-0123-0123456789ab' - schreibt UUID\n" " 'uuid generate' - generiert und schreibt\n" " 'uuid rewrite' - kopiert UUID von SB 0\n" "\n" "Die Ausgabefunktion prüft die UUID in jedem SB und wird warnen, wenn die\n" "UUIDs sich zwischen AGs unterscheiden (das Protokoll ist nicht geprüft).\n" "Die Schreibbefehle werden die UUIDs in allen AGs entweder auf einen\n" "angegebenen Wert, einen neu generierten Wert beziehungsweise den im ersten\n" "Superblock (SB 0) gefundenen Wert setzen. Als ein Nebeneffekt des\n" "Schreibens der UUID wird das Protokoll geleert (was bei einem ORDENTLICH\n" "ausgehängten FS fein ist).\n" "\n" #: .././db/sb.c:336 .././db/sb.c:488 msgid "invalid parameters\n" msgstr "ungültige Parameter\n" #: .././db/sb.c:343 .././db/sb.c:495 .././db/sb.c:631 #, c-format msgid "%s: not in expert mode, writing disabled\n" msgstr "%s: Nicht im Expertenmodus, schreiben ausgeschaltet\n" #: .././db/sb.c:355 msgid "failed to read UUID from AG 0\n" msgstr "Lesen der UUID von AG 0 fehlgeschlagen\n" #: .././db/sb.c:360 #, c-format msgid "old UUID = %s\n" msgstr "alte UUID = %s\n" #: .././db/sb.c:363 msgid "invalid UUID\n" msgstr "ungültige UUID\n" #: .././db/sb.c:372 .././db/sb.c:500 .././db/sb.c:699 msgid "writing all SBs\n" msgstr "Schreiben aller SBs\n" #: .././db/sb.c:375 #, c-format msgid "failed to set UUID in AG %d\n" msgstr "UUID in AG %d zu setzen fehlgeschlagen\n" #: .././db/sb.c:380 #, c-format msgid "new UUID = %s\n" msgstr "neue UUID = %s\n" #: .././db/sb.c:388 #, c-format msgid "failed to read UUID from AG %d\n" msgstr "Lesen der UUID von AG %d fehlgeschlagen\n" #: .././db/sb.c:394 #, c-format msgid "warning: UUID in AG %d differs to the primary SB\n" msgstr "Warnung:UUID in AG %d unterscheidet sich vom primären SB\n" #: .././db/sb.c:405 msgid "warning - external log specified for FS with an internal log\n" msgstr "" "Warnung - externes Protokoll für FS mit einem internen Protokoll angegeben\n" #: .././db/sb.c:408 msgid "warning - no external log specified for FS with an external log\n" msgstr "" "Warnung - kein externes Protokoll für FS mit einem externen Protokoll\n" "angegeben\n" #: .././db/sb.c:413 #, c-format msgid "UUID = %s\n" msgstr "UUID = %s\n" #: .././db/sb.c:424 msgid "" "\n" " write/print FS label\n" "\n" " Example:\n" "\n" " 'label' - print label\n" " 'label 123456789012' - write label\n" " 'label --' - write an empty label\n" "\n" "The print function checks the label in each SB and will warn if the labels\n" "differ between AGs. The write commands will set the label in all AGs to the\n" "specified value. The maximum length of a label is 12 characters - use of a\n" "longer label will result in truncation and a warning will be issued.\n" "\n" msgstr "" "\n" " FS-Etikett schreiben/ausgeben\n" "\n" " Beispiel:\n" "\n" " 'label' - Etikett ausgeben\n" " 'label 123456789012' - Etikett schreiben\n" " 'label --' - ein leeres Etikett schreiben\n" "\n" "Die Ausgabefunktion prüft das Etikett in jedem SB und wird warnen, wenn\n" "sich die Etiketten zwischen AGs unterscheiden. Die Schreibbefehlewerden\n" "Etiketten in allen AGs auf den angegebenen Wert setzen. Die maximale\n" "Länge eine Etiketts ist zwölf Zeichen - Benutzen eines längeren Etiketts\n" "führt zu Kürzung und eine Warnung wird ausgegeben.\n" "\n" #: .././db/sb.c:461 #, c-format msgid "%s: truncating label length from %d to %d\n" msgstr "%s: Etikettlänge von %d auf %d kürzen\n" #: .././db/sb.c:503 #, c-format msgid "failed to set label in AG %d\n" msgstr "Setzen von Etikett in AG %d fehlgeschlagen\n" #: .././db/sb.c:506 #, c-format msgid "new label = \"%s\"\n" msgstr "neues Etikett = »%s«\n" #: .././db/sb.c:513 #, c-format msgid "failed to read label in AG %d\n" msgstr "Lesen von Etikett in AG %d fehlgeschlagen\n" #: .././db/sb.c:519 #, c-format msgid "warning: AG %d label differs\n" msgstr "Warnung: AG %d Etikett unterschiedlich\n" #: .././db/sb.c:521 #, c-format msgid "label = \"%s\"\n" msgstr "Etikett = »%s«\n" #: .././db/sb.c:531 msgid "" "\n" " set/print feature bits in sb version\n" "\n" " Example:\n" "\n" " 'version' - print current feature bits\n" " 'version extflg' - enable unwritten extents\n" " 'version attr1' - enable v1 inline extended attributes\n" " 'version attr2' - enable v2 inline extended attributes\n" " 'version log2' - enable v2 log format\n" "\n" "The version function prints currently enabled features for a filesystem\n" "according to the version field of its primary superblock.\n" "It can also be used to enable selected features, such as support for\n" "unwritten extents. The updated version is written into all AGs.\n" "\n" msgstr "" "\n" " setzen/ausgeben von Merkmal-Bits in sb-Version\n" "\n" " »version« - gibt aktuelle Merkmal-Bis aus\n" " »version extflg« - ungeschriebene Extents einschalten\n" " »version attr1« - v1 erweiterte Inline-Attribute einschalten\n" " »version attr2« - v2 erweiterte Inline-Attribute einschalten\n" " »version log2« - v2 Protokolformat einschalten\n" "\n" "Die Versionsfunktion gibt aktuell eingeschaltete Merkmale für ein\n" "Dateisystem aus, entsprechende dem Versionsfeld seines primären\n" "Superblocks. Es kann außerdem benutzt werden, um ausgewählte Merkmale\n" "einzuschalten, wie etwa Unterstützung für ungeschriebene Bereiche. Die\n" "aktualisierte Version wird in alle AGs geschrieben.\n" "\n" #: .././db/sb.c:650 msgid "unwritten extents flag is already enabled\n" msgstr "Merkaml für ungeschriebene Bereiche ist bereits eingeschaltet\n" #: .././db/sb.c:670 msgid "version 2 log format is already in use\n" msgstr "Protokollformat der Version 2 wird bereits benutzt\n" #: .././db/sb.c:693 #, c-format msgid "%s: invalid version change command \"%s\"\n" msgstr "%s: ungültiger Versionswechselbefehl »%s«\n" #: .././db/sb.c:702 #, c-format msgid "failed to set versionnum in AG %d\n" msgstr "Versionsnummer in AG %d zu setzen fehlgeschlagen\n" #: .././db/sb.c:720 #, c-format msgid "versionnum [0x%x+0x%x] = %s\n" msgstr "versionnum [0x%x+0x%x] = %s\n" #: .././db/type.c:50 msgid "[newtype]" msgstr "[newtype]" #: .././db/type.c:51 msgid "set/show current data type" msgstr "aktuellen Datentyp setzen/anzeigen" #: .././db/type.c:104 #, c-format msgid "current type is \"%s\"\n" msgstr "aktueller Typ ist »%s«\n" #: .././db/type.c:106 msgid "" "\n" " supported types are:\n" " " msgstr "" "\n" " unterstützte Typen sind:\n" " " #: .././db/type.c:121 #, c-format msgid "no such type %s\n" msgstr "kein solcher Typ %s\n" #: .././db/type.c:124 msgid "no current object\n" msgstr "kein aktuelles Objekt\n" #: .././db/write.c:41 msgid "[field or value]..." msgstr "[Feld oder Wert] ..." #: .././db/write.c:42 msgid "write value to disk" msgstr "Wert auf Platte schreiben" #: .././db/write.c:58 msgid "" "\n" " The 'write' command takes on different personalities depending on the\n" " type of object being worked with.\n" "\n" " Write has 3 modes:\n" " 'struct mode' - is active anytime you're looking at a filesystem object\n" " which contains individual fields (ex: an inode).\n" " 'data mode' - is active anytime you set a disk address directly or set\n" " the type to 'data'.\n" " 'string mode' - only used for writing symlink blocks.\n" "\n" " Examples:\n" " Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n" " 'write fname \"hello\\000\"' - write superblock fname.\n" " (note: in struct mode strings are not null terminated)\n" " 'write fname #6669736800' - write superblock fname with " "hex.\n" " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n" " - write superblock uuid.\n" " Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n" " 'write lshift 3' - shift the block 3 bytes to the left\n" " 'write sequence 1 5' - write a cycle of number [1-5] through\n" " the entire block.\n" " String mode: 'write \"This_is_a_filename\" - write null terminated " "string.\n" "\n" " In data mode type 'write' by itself for a list of specific commands.\n" "\n" msgstr "" "\n" " Der »write«-Befehl nimmt abhängig vom Typ des Objekts, mit dem gearbeitet\n" " wird, unterschiedliche Persönlichkeiten an.\n" "\n" " Write hat drei Modi:\n" " »Strukturmodus« - ist jederzeit aktiv, wenn Sie ein\n" " Dateisystemobjekt ansehen, das individuelle\n" " Felder enthält (z.B.: Einen Inode.\n" " »Datenmodus« - ist jederzeit aktiv, wenn Sie eine Plattenadresse\n" " direkt setzen oder den Typ auf »data« setzen.\n" " »Zeichenkettenmodus« - nur benutzt, um symbolische Verweisblöcke zu\n" " schreiben.\n" "\n" " Beispiele:\n" " Strukturmodus: »write core.uid 23« - setzt eine Inode-uid-Feld\n" " auf 23.\n" " »write fname \"hello\\000\"«\n" " - schreibt Superblock fname.\n" " (Anmerkung: Zeichenketten werden in »struct mode« nicht\n" " mit Null beendet)\n" " »write fname #6669736800«\n" " - schreibt Superblock fname\n" " hexadezimal.\n" " »write uuid 00112233-4455-6677-8899-aabbccddeeff«\n" " - schreibt Superblock-uuid.\n" " Datenmodus: »write fill 0xff« - füllt den ganzen Block mit\n" " 0xffs\n" " »write lshift 3« - verschiebt den Block drei\n" " Bytes nach links\n" " »write sequence 1 5« - schreibt einen Zyklus von\n" " Nummern [1-5] durch den\n" " ganzen Block\n" " Zeichenkettenmodus: »write \"This_is_a_filename\"«\n" " - schreibt mit Null beendete\n" " Zeichenkette\n" "\n" " Tippen Sie im Datenmodus »write« ein, um eine Liste spezieller Befehle zu\n" " erhalten.\n" "\n" #: .././db/write.c:95 #, c-format msgid "%s started in read only mode, writing disabled\n" msgstr "%s im Nur-Lese-Modus gestartet, Schreiben ausgeschaltet\n" #: .././db/write.c:107 #, c-format msgid "no handler function for type %s, write unsupported.\n" msgstr "" "keine Funktion zum Behandeln von Typ %s, Schreiben nicht unterstützt.\n" #: .././db/write.c:167 .././db/write.c:196 .././db/write.c:226 #: .././db/write.c:258 .././db/write.c:293 .././db/write.c:342 #: .././db/write.c:371 #, c-format msgid "length (%d) too large for data block size (%d)" msgstr "Länge (%d) zu groß für Datenblockgröße (%d)" #: .././db/write.c:559 msgid "usage: write fieldname value\n" msgstr "Aufruf: write Feldname Wert\n" #: .././db/write.c:565 #, c-format msgid "unable to parse '%s'.\n" msgstr "»%s« kann nicht ausgewertet werden.\n" #: .././db/write.c:579 msgid "parsing error\n" msgstr "Auswertungsfehler\n" #: .././db/write.c:598 #, c-format msgid "unable to convert value '%s'.\n" msgstr "Wert »%s« kann nicht konvertiert werden.\n" #: .././db/write.c:621 msgid "usage (in string mode): write \"string...\"\n" msgstr "Aufruf (im Zeichenkettenmodus): write »Zeichenkette ...«\n" #: .././db/write.c:663 msgid "write: invalid subcommand\n" msgstr "write: ungültiger Unterbefehl\n" #: .././db/write.c:668 #, c-format msgid "write %s: invalid number of arguments\n" msgstr "write %s: ungültige Anzahl von Argumenten\n" #: .././db/write.c:692 msgid "usage: write (in data mode)\n" msgstr "Aufruf: write (im Datenmodus)\n" #: .././db/agf.c:36 msgid "set address to agf header" msgstr "Adresse auf agf-Kopfzeilen setzen" #: .././db/agf.c:79 msgid "" "\n" " set allocation group free block list\n" "\n" " Example:\n" "\n" " agf 2 - move location to AGF in 2nd filesystem allocation group\n" "\n" " Located in the second sector of each allocation group, the AGF\n" " contains the root of two different freespace btrees:\n" " The 'cnt' btree keeps track freespace indexed on section size.\n" " The 'bno' btree tracks sections of freespace indexed on block number.\n" msgstr "" "\n" " Liste freier Blöcke der Zuordnungsgruppe setzen\n" "\n" " Beispiel:\n" "\n" " agf 2 - Ort auf AGF in 2.Dateisystemzuordnungsgruppe setzen.\n" "\n" " Im zweiten Abschnitt jeder Zuordnungsgruppe gelegen, enthält das AGF die\n" " Wurzel zweier unterschiedlicher freespace btrees:\n" " Der »cnt«-btree folgt Abschnitten von freespace, indiziert auf\n" " Blocknummer.\n" #: .././estimate/xfs_estimate.c:76 #, c-format msgid "" "Usage: %s [opts] directory [directory ...]\n" "\t-b blocksize (fundamental filesystem blocksize)\n" "\t-i logsize (internal log size)\n" "\t-e logsize (external log size)\n" "\t-v prints more verbose messages\n" "\t-h prints this usage message\n" "\n" "Note:\tblocksize may have 'k' appended to indicate x1024\n" "\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n" msgstr "" "Aufruf: %s [Optionen] Verzeichnis [Verzeichnis ...]\n" "\t-b Blockgröße (grundlegende Dateisystemblockgröße)\n" "\t-i Protokollgröße (interne Protokollgröße)\n" "\t-e Protokollgröße (externe Protokollgröße)\n" "\t-v gibt detailliertere Nachrichten aus\n" "\t-h gibt diese Aufrufnachricht aus\n" "\n" #: .././estimate/xfs_estimate.c:106 #, c-format msgid "blocksize %llu too small\n" msgstr "Blockgröße %llu zu klein\n" #: .././estimate/xfs_estimate.c:111 #, c-format msgid "blocksize %llu too large\n" msgstr "Blockgröße %llu zu groß\n" #: .././estimate/xfs_estimate.c:118 #, c-format msgid "already have external log noted, can't have both\n" msgstr "externes Protokoll wurde bereits notiert, beide nicht möglich\n" #: .././estimate/xfs_estimate.c:127 #, c-format msgid "already have internal log noted, can't have both\n" msgstr "internes Protokoll wurde bereits notiert, beide nicht möglich\n" #: .././estimate/xfs_estimate.c:157 #, c-format msgid "" "directory bsize blocks megabytes " "logsize\n" msgstr "" "Verzeichnis bsize Blöcke Megabytes " "Protokollgröße\n" #: .././estimate/xfs_estimate.c:171 #, c-format msgid "dirsize=%llu\n" msgstr "dirsize=%llu\n" #: .././estimate/xfs_estimate.c:172 #, fc-format msgid "fullblocks=%llu\n" msgstr "fullblocks=%llu\n" #: .././estimate/xfs_estimate.c:173 #, c-format msgid "isize=%llu\n" msgstr "isize=%llu\n" #: .././estimate/xfs_estimate.c:175 #, c-format msgid "%llu regular files\n" msgstr "%llu reguläre Dateien\n" #: .././estimate/xfs_estimate.c:176 #, c-format msgid "%llu symbolic links\n" msgstr "%llu symbolische Verweise\n" #: .././estimate/xfs_estimate.c:177 #, c-format msgid "%llu directories\n" msgstr "%llu Verzeichnisse\n" #: .././estimate/xfs_estimate.c:178 #, c-format msgid "%llu special files\n" msgstr "%llu Spezialdateien\n" #: .././estimate/xfs_estimate.c:191 #, c-format msgid "%s will take about %.1f megabytes\n" msgstr "%s wird etwa %.lf Megabytes einnehmen\n" #: .././estimate/xfs_estimate.c:198 #, c-format msgid "%-39s %5llu %8llu %10.1fMB %10llu\n" msgstr "%-39s %5llu %8llu %10.1fMB %10llu\n" #: .././estimate/xfs_estimate.c:204 #, c-format msgid "\twith the external log using %llu blocks " msgstr "\tmit dem externen Protokoll belegt %llu Blöcke " #: .././estimate/xfs_estimate.c:206 #, c-format msgid "or about %.1f megabytes\n" msgstr "oder über %.1f Megabytes\n" #: .././fsr/xfs_fsr.c:216 #, c-format msgid "%s: Stats not yet supported for XFS\n" msgstr "%s: Status noch nicht für XFS unterstützt\n" #: .././fsr/xfs_fsr.c:264 .././fsr/xfs_fsr.c:292 #, c-format msgid "%s: could not stat: %s: %s\n" msgstr "%s: kann Status für »%s« nicht abfragen: %s\n" #: .././fsr/xfs_fsr.c:274 #, c-format msgid "%s: cannot read %s\n" msgstr "%s: %s kann nicht gelesen werden\n" #: .././fsr/xfs_fsr.c:306 #, c-format msgid "%s: char special not supported: %s\n" msgstr "%s: Sonderzeichen nicht unterstützt: %s\n" #: .././fsr/xfs_fsr.c:312 #, c-format msgid "%s: cannot defragment: %s: Not XFS\n" msgstr "%s: kann nicht defragmentiert werden: %s: Kein XFS\n" #: .././fsr/xfs_fsr.c:322 #, c-format msgid "%s: not fsys dev, dir, or reg file, ignoring\n" msgstr "%s: nicht fsys dev, dir oder reg-Datei, wird ignoriert\n" #: .././fsr/xfs_fsr.c:337 #, c-format msgid "" "Usage: %s [-d] [-v] [-n] [-s] [-g] [-t time] [-p passes] [-f leftf] [-m " "mtab]\n" " %s [-d] [-v] [-n] [-s] [-g] xfsdev | dir | file ...\n" "\n" "Options:\n" " -n Do nothing, only interesting with -v. Not\n" " effective with in mtab mode.\n" " -s\t\tPrint statistics only.\n" " -g Print to syslog (default if stdout not a tty).\n" " -t time How long to run in seconds.\n" " -p passes\tNumber of passes before terminating global re-org.\n" " -f leftoff Use this instead of %s.\n" " -m mtab Use something other than /etc/mtab.\n" " -d Debug, print even more.\n" " -v\t\tVerbose, more -v's more verbose.\n" msgstr "" "Aufruf: %s [-d] [-v] [-n] [-s] [-g] [-t Zeit] [-p Durchläufe] [-f leftf] \n" " [-m mtab] %s [-d] [-v] [-n] [-s] [-g] xfsdev | Verz. | Datei ...\n" "\n" "Optionen:\n" " -n Nichts tun, nur interessant mit -v. Im mtab-Modus\n" " nicht effektiv.\n" " -s\t\tNur Statistiken ausgeben.\n" " -g Ausgabe in's Syslog (Vorgabe, wenn stdout kein tty).\n" " -t Zeit Ausführdauer in Sekunden.\n" " -p Durchläufe Anzahl der Durchläufe vor Beenden der globalen\n" " Reorganisation.\n" " -f leftoff Benutzen Sie dies anstelle von %s.\n" " -m mtab Etwas anderes als /etc/mtab benutzen.\n" " -d Fehlersuche, noch mehr ausgeben.\n" " -v\t\tDetailliert, mehr vs - mehr Details.\n" #: .././fsr/xfs_fsr.c:368 #, c-format msgid "could not open mtab file: %s\n" msgstr "mtab-Datei könnte nicht geöffnet werden: %s\n" #: .././fsr/xfs_fsr.c:374 .././fsr/xfs_fsr.c:406 #, c-format msgid "out of memory: %s\n" msgstr "außerhalb des Speichers: %s\n" #: .././fsr/xfs_fsr.c:397 #, c-format msgid "Skipping %s: not mounted rw\n" msgstr "%s wird übersprungen: Nicht rw-eingehängt\n" #: .././fsr/xfs_fsr.c:411 #, c-format msgid "out of memory on realloc: %s\n" msgstr "außerhalb des Speichers bei realloc: %s\n" #: .././fsr/xfs_fsr.c:422 #, c-format msgid "strdup(%s) failed\n" msgstr "strdup(%s) fehlgeschlagen\n" #: .././fsr/xfs_fsr.c:432 #, c-format msgid "no rw xfs file systems in mtab: %s\n" msgstr "keine rw-XFS-Dateisysteme in mtab: %s\n" #: .././fsr/xfs_fsr.c:436 #, c-format msgid "Found %d mounted, writable, XFS filesystems\n" msgstr "%d eingehängte, schreibbare XFS-Dateisysteme gefunden\n" #: .././fsr/xfs_fsr.c:466 #, c-format msgid "%s: open failed\n" msgstr "%s: Öffnen fehlgeschlagen\n" #: .././fsr/xfs_fsr.c:481 #, c-format msgid "Can't use %s: mode=0%o own=%d nlink=%d\n" msgstr "%s kann nicht benutzt werden: Modus=0%o Besitzer=%d nlink=%d\n" #: .././fsr/xfs_fsr.c:501 #, c-format msgid "could not read %s, starting with %s\n" msgstr "%s kann nicht gelesen werden, es wird mit %s gestartet\n" #: .././fsr/xfs_fsr.c:538 #, c-format msgid "START: pass=%d ino=%llu %s %s\n" msgstr "START: Durchlauf=%d ino=%llu %s %s\n" #: .././fsr/xfs_fsr.c:555 #, c-format msgid "Completed all %d passes\n" msgstr "Alle %d Durchläufe wurden komplettiert\n" #: .././fsr/xfs_fsr.c:565 msgid "couldn't fork sub process:" msgstr "Unterprozess kann nicht verzweigt werden:" #: .././fsr/xfs_fsr.c:602 #, c-format msgid "open(%s) failed: %s\n" msgstr "Öffnen (%s) fehlgeschlagen: %s\n" #: .././fsr/xfs_fsr.c:609 #, c-format msgid "write(%s) failed: %s\n" msgstr "Schreiben (%s) fehlgeschlagen: %s\n" #: .././fsr/xfs_fsr.c:616 #, c-format msgid "%s startpass %d, endpass %d, time %d seconds\n" msgstr "%s Durchlaufstart %d, Durchlaufende %d, Zeit %d Sekunden\n" #: .././fsr/xfs_fsr.c:638 #, c-format msgid "%s start inode=%llu\n" msgstr "%s Start-Inode=%llu\n" #: .././fsr/xfs_fsr.c:643 #, c-format msgid "unable to get handle: %s: %s\n" msgstr "es konnte kein »handle« ermittelt werden: %s: %s\n" #: .././fsr/xfs_fsr.c:649 #, c-format msgid "unable to open: %s: %s\n" msgstr "konnte nicht geöffnet werden: %s: %s\n" #: .././fsr/xfs_fsr.c:655 #, c-format msgid "Skipping %s: could not get XFS geometry\n" msgstr "%s wird übersprungen: XFS-Geometrie konnte nicht ermittelt werden\n" #: .././fsr/xfs_fsr.c:687 #, c-format msgid "could not open: inode %llu\n" msgstr "kann nicht geöffnet werden: Inode %llu\n" #: .././fsr/xfs_fsr.c:717 #, c-format msgid "%s: xfs_bulkstat: %s\n" msgstr "%s: xfs_bulkstat: %s\n" #: .././fsr/xfs_fsr.c:743 #, c-format msgid "%s: Directory defragmentation not supported\n" msgstr "%s: Verzeichnis-Defragmentierung nicht unterstützt\n" #: .././fsr/xfs_fsr.c:762 #, c-format msgid "unable to construct sys handle for %s: %s\n" msgstr "sys-handle für %s kann nicht konstruiert werden: %s\n" #: .././fsr/xfs_fsr.c:773 #, c-format msgid "unable to open sys handle for %s: %s\n" msgstr "sys-handle für %s kann nicht geöffnet werden: %s\n" #: .././fsr/xfs_fsr.c:779 #, c-format msgid "unable to get bstat on %s: %s\n" msgstr "bstat auf %s kann nicht ermittelt werden: %s\n" #: .././fsr/xfs_fsr.c:787 #, c-format msgid "unable to open handle %s: %s\n" msgstr "handle %s kann nicht geöffnet werden: %s\n" #: .././fsr/xfs_fsr.c:795 #, c-format msgid "Unable to get geom on fs for: %s\n" msgstr "geom auf fs kann nicht ermittelt werden für: %s\n" #: .././fsr/xfs_fsr.c:844 #, c-format msgid "sync failed: %s: %s\n" msgstr "sync fehlgeschlagen: %s: %s\n" #: .././fsr/xfs_fsr.c:850 #, c-format msgid "%s: zero size, ignoring\n" msgstr "%s: Größe null, wird ignoriert\n" #: .././fsr/xfs_fsr.c:869 #, c-format msgid "locking check failed: %s\n" msgstr "Prüfen der Sperre fehlgeschlagen: %s\n" #: .././fsr/xfs_fsr.c:876 #, c-format msgid "mandatory lock: %s: ignoring\n" msgstr "verbindliche Sperre: %s: wird ignoriert\n" #: .././fsr/xfs_fsr.c:889 #, c-format msgid "unable to get fs stat on %s: %s\n" msgstr "fs-stat auf %s kann nicht ermittelt werden: %s\n" #: .././fsr/xfs_fsr.c:896 #, c-format msgid "insufficient freespace for: %s: size=%lld: ignoring\n" msgstr "unzureichender freier Speicher für: %s: Größe=%lld: wird ignoriert\n" #: .././fsr/xfs_fsr.c:903 #, c-format msgid "failed to get inode attrs: %s\n" msgstr "Ermitteln von Inode-attrs fehlgeschlagen: %s\n" #: .././fsr/xfs_fsr.c:908 #, c-format msgid "%s: immutable/append, ignoring\n" msgstr "%s: unveränderlich/anhängen, wird ignoriert\n" #: .././fsr/xfs_fsr.c:913 #, c-format msgid "%s: marked as don't defrag, ignoring\n" msgstr "%s: als nicht zu defragmentieren markiert, wird ignoriert\n" #: .././fsr/xfs_fsr.c:919 #, c-format msgid "cannot get realtime geometry for: %s\n" msgstr "Echtzeitgeometrie kann nicht ermittelt werden für: %s\n" #: .././fsr/xfs_fsr.c:924 #, c-format msgid "low on realtime free space: %s: ignoring file\n" msgstr "geringer freier Echtzeit-Raum: %s: Datei wird ignoriert\n" #: .././fsr/xfs_fsr.c:931 #, c-format msgid "cannot open: %s: Permission denied\n" msgstr "kann nicht geöffnet werden: %s: Erlaubnis verweigert\n" #: .././fsr/xfs_fsr.c:985 #, c-format msgid "%s already fully defragmented.\n" msgstr "%s ist bereits vollständig defragmentiert.\n" #: .././fsr/xfs_fsr.c:990 #, c-format msgid "%s extents=%d can_save=%d tmp=%s\n" msgstr "%s extents=%d can_save=%d tmp=%s\n" #: .././fsr/xfs_fsr.c:996 #, c-format msgid "could not open tmp file: %s: %s\n" msgstr "tmp-Datei kann nicht geöffnet werden: %s: %s\n" #: .././fsr/xfs_fsr.c:1005 #, c-format msgid "could not set ATTR on tmp: %s:\n" msgstr "ATTR auf tmp kann nicht gesetzt werden: %s:\n" #: .././fsr/xfs_fsr.c:1010 #, c-format msgid "%s set temp attr\n" msgstr "%s setzt temp attr\n" #: .././fsr/xfs_fsr.c:1016 #, c-format msgid "could not set inode attrs on tmp: %s\n" msgstr "Inode-attrs auf tmp können nicht gesetzt werden: %s\n" #: .././fsr/xfs_fsr.c:1024 #, c-format msgid "could not get DirectIO info on tmp: %s\n" msgstr "DirekIO-Information auf tmp kann nicht ermittelt werden: %s\n" #: .././fsr/xfs_fsr.c:1040 #, c-format msgid "DEBUG: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n" msgstr "FEHLERSUCHE: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n" #: .././fsr/xfs_fsr.c:1047 #, c-format msgid "could not allocate buf: %s\n" msgstr "buf kann nicht zugewiesen werden: %s\n" #: .././fsr/xfs_fsr.c:1058 #, c-format msgid "could not open fragfile: %s : %s\n" msgstr "fragfile kann nicht geöffnet werden: %s : %s\n" #: .././fsr/xfs_fsr.c:1075 #, c-format msgid "could not trunc tmp %s\n" msgstr "tmp %s kann nicht gekürzt werden\n" #: .././fsr/xfs_fsr.c:1090 #, c-format msgid "could not pre-allocate tmp space: %s\n" msgstr "tmp-Raum kann nicht vorab zugewiesen werden: %s\n" #: .././fsr/xfs_fsr.c:1101 msgid "Couldn't rewind on temporary file\n" msgstr "es konnte auf temporäre Datei zurückgesetzt werden\n" #: .././fsr/xfs_fsr.c:1110 #, c-format msgid "Temporary file has %d extents (%d in original)\n" msgstr "Temporäre Datei hat %d extents (%d im Original)\n" #: .././fsr/xfs_fsr.c:1113 #, c-format msgid "No improvement will be made (skipping): %s\n" msgstr "Es wird keine Verbesserung vorgenommen (übersprungen): %s\n" #: .././fsr/xfs_fsr.c:1157 #, c-format msgid "bad read of %d bytes from %s: %s\n" msgstr "fehlerhaftes Lesen von %d Bytes auf %s: %s\n" #: .././fsr/xfs_fsr.c:1161 .././fsr/xfs_fsr.c:1195 #, c-format msgid "bad write of %d bytes to %s: %s\n" msgstr "fehlerhaftes Schreiben von %d Bytes auf %s: %s\n" #: .././fsr/xfs_fsr.c:1178 #, c-format msgid "bad write2 of %d bytes to %s: %s\n" msgstr "fehlerhaftes write2 von %d Bytes auf %s: %s\n" #: .././fsr/xfs_fsr.c:1183 #, c-format msgid "bad copy to %s\n" msgstr "fehlerhafte Kopie auf %s\n" #: .././fsr/xfs_fsr.c:1218 #, c-format msgid "failed to fchown tmpfile %s: %s\n" msgstr "fchown tmpfile fehlgeschlagen: %s: %s\n" #: .././fsr/xfs_fsr.c:1229 #, c-format msgid "%s: file type not supported\n" msgstr "%s: Dateityp nicht unterstützt\n" #: .././fsr/xfs_fsr.c:1233 #, c-format msgid "%s: file modified defrag aborted\n" msgstr "%s: Datei geändert, Defragmentierung abgebrochen\n" #: .././fsr/xfs_fsr.c:1238 #, c-format msgid "%s: file busy\n" msgstr "%s: Datei wird benutzt\n" #: .././fsr/xfs_fsr.c:1240 #, c-format msgid "XFS_IOC_SWAPEXT failed: %s: %s\n" msgstr "XFS_IOC_SWAPEXT fehlgeschlagen: %s: %s\n" #: .././fsr/xfs_fsr.c:1249 #, c-format msgid "extents before:%d after:%d %s %s\n" msgstr "extents vorher: %d nachher: %d %s %s\n" #: .././fsr/xfs_fsr.c:1275 #, c-format msgid "tmp file name too long: %s\n" msgstr "tmp-Dateiname zu lang: %s\n" #: .././fsr/xfs_fsr.c:1324 #, c-format msgid "realloc failed: %s\n" msgstr "realloc fehlgeschlagen: %s\n" #: .././fsr/xfs_fsr.c:1337 #, c-format msgid "malloc failed: %s\n" msgstr "malloc fehlgeschlagen: %s\n" #: .././fsr/xfs_fsr.c:1367 #, c-format msgid "failed reading extents: inode %llu" msgstr "Lesen der Extents fehlgeschlagen: Inode %llu" #: .././fsr/xfs_fsr.c:1417 msgid "failed reading extents" msgstr "Lesen der Extents fehlgeschlagen" #: .././fsr/xfs_fsr.c:1534 .././fsr/xfs_fsr.c:1548 #, c-format msgid "tmpdir already exists: %s\n" msgstr "tmpdir exisitiert bereits: %s\n" #: .././fsr/xfs_fsr.c:1537 #, c-format msgid "could not create tmpdir: %s: %s\n" msgstr "tmpdir könnte nicht erstellt werden: %s: %s\n" #: .././fsr/xfs_fsr.c:1550 #, c-format msgid "cannot create tmpdir: %s: %s\n" msgstr "tmpdir kann nicht erstellt werden: %s: %s\n" #: .././fsr/xfs_fsr.c:1588 .././fsr/xfs_fsr.c:1596 #, c-format msgid "could not remove tmpdir: %s: %s\n" msgstr "tmpdir könnte nicht entfernt werden: %s: %s\n" #: .././growfs/xfs_growfs.c:34 #, c-format msgid "" "Usage: %s [options] mountpoint\n" "\n" "Options:\n" "\t-d grow data/metadata section\n" "\t-l grow log section\n" "\t-r grow realtime section\n" "\t-n don't change anything, just show geometry\n" "\t-I allow inode numbers to exceed %d significant bits\n" "\t-i convert log from external to internal format\n" "\t-t alternate location for mount table (/etc/mtab)\n" "\t-x convert log from internal to external format\n" "\t-D size grow data/metadata section to size blks\n" "\t-L size grow/shrink log section to size blks\n" "\t-R size grow realtime section to size blks\n" "\t-e size set realtime extent size to size blks\n" "\t-m imaxpct set inode max percent to imaxpct\n" "\t-V print version information\n" msgstr "" "Aufruf: %s [Optionen] Einhängepunkt\n" "\n" "Optionen:\n" "\t-d Daten-/Metadaten-Bereich vergrößern\n" "\t-l Protokoll-Bereich vergrößern\n" "\t-r Echtzeit-Bereich vergrößern\n" "\t-n nichts ändern, nur Geometrie anzeigen\n" "\t-I Inode-Nummern erlauben %d signifikante Bits zu übersteigen\n" "\t-i Protokoll vom externen auf das interne Format umwandeln\n" "\t-t alternativer Ort der Einhängepunkt-Tabelle (/etc/mtab)\n" "\t-x Protokoll vom internen auf das externe Format umwandeln\n" "\t-D Größe Daten-/Metadaten-Bereich auf blks-Größe vergrößern\n" "\t-L Größe vergrößern/verkleinern des Protokoll-Bereiches auf blks-Größe\n" "\t-R Größe Echtzeit-Bereich auf blks-Größe vergrößern\n" "\t-e Größe Echtezeit-Umfang auf blks-Größe setzen\n" "\t-m imaxpct Inodes auf maximal imaxcpt Prozent setzen\n" "\t-V Versions-Information anzeigen\n" #: .././growfs/xfs_growfs.c:68 #, c-format msgid "" "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d\n" "log =%-22s bsize=%-6u blocks=%u, version=%u\n" " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n" "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n" msgstr "" "Metadaten =%-22s isize=%-6u agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u\n" "Daten =%-22s bsize=%-6u Blöcke=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "Benennung =Version %-14u bsize=%-6u ascii-ci=%d\n" "Protokoll =%-22s bsize=%-6u Blöcke=%u, Version=%u\n" " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n" "Echtzeit =%-22s extsz=%-6u Blöcke=%llu, rtextents=%llu\n" #: .././growfs/xfs_growfs.c:83 .././growfs/xfs_growfs.c:448 #: .././growfs/xfs_growfs.c:449 msgid "internal" msgstr "Intern" #: .././growfs/xfs_growfs.c:83 .././growfs/xfs_growfs.c:86 #: .././growfs/xfs_growfs.c:448 .././growfs/xfs_growfs.c:449 msgid "external" msgstr "extern" #: .././growfs/xfs_growfs.c:199 #, c-format msgid "%s: %s is not a mounted XFS filesystem\n" msgstr "%s: %s ist kein eingehängtes XFS-Dateisystem\n" #: .././growfs/xfs_growfs.c:216 .././io/open.c:170 #, c-format msgid "%s: specified file [\"%s\"] is not on an XFS filesystem\n" msgstr "%s: angegebene Datei [»%s«] ist kein XFS-Dateisystem\n" #: .././growfs/xfs_growfs.c:233 #, c-format msgid "%s: cannot determine geometry of filesystem mounted at %s: %s\n" msgstr "" "%s: Geometrie des auf %s eingehängten Dateisystems kann nicht ermittelt\n" "werden: %s\n" #: .././growfs/xfs_growfs.c:268 #, c-format msgid "%s: failed to access data device for %s\n" msgstr "%s: Zugriff auf Datenträger für %s fehlgeschlagen\n" #: .././growfs/xfs_growfs.c:273 #, c-format msgid "%s: failed to access external log for %s\n" msgstr "%s: Zugriff auf externes Protokoll für %s fehlgeschlagen.\n" #: .././growfs/xfs_growfs.c:279 #, c-format msgid "%s: failed to access realtime device for %s\n" msgstr "%s: Zugriff auf Echtzeit-Gerät für %s fehlgeschlagen.\n" #: .././growfs/xfs_growfs.c:315 #, c-format msgid "data size %lld too large, maximum is %lld\n" msgstr "Datengröße %lld zu groß, Maximum ist %lld\n" #: .././growfs/xfs_growfs.c:325 #, c-format msgid "data size %lld too small, old size is %lld\n" msgstr "Datengröße %lld zu klein, alte Größe ist %lld\n" #: .././growfs/xfs_growfs.c:333 #, c-format msgid "data size unchanged, skipping\n" msgstr "Datengröße unverändert, wird übersprungen\n" #: .././growfs/xfs_growfs.c:336 #, c-format msgid "inode max pct unchanged, skipping\n" msgstr "»inode max pct« unverändert, wird übersprungen\n" #: .././growfs/xfs_growfs.c:343 .././growfs/xfs_growfs.c:382 #: .././growfs/xfs_growfs.c:417 #, c-format msgid "%s: growfs operation in progress already\n" msgstr "%s: growfs-Operation wird immer noch ausgeführt.\n" #: .././growfs/xfs_growfs.c:347 #, c-format msgid "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n" msgstr "%s: XFS_IOC_FSGROWFSDATA xfsctl fehlgeschlagen: %s\n" #: .././growfs/xfs_growfs.c:363 #, c-format msgid "realtime size %lld too large, maximum is %lld\n" msgstr "Echtzeit-Größe %lld zu groß, Maximum ist %lld\n" #: .././growfs/xfs_growfs.c:369 #, c-format msgid "realtime size %lld too small, old size is %lld\n" msgstr "Echtzeit-Größe %lld zu klein, alte Größe ist %lld\n" #: .././growfs/xfs_growfs.c:375 #, c-format msgid "realtime size unchanged, skipping\n" msgstr "Echtzeit-Größe unverändert, wird übersprungen\n" #: .././growfs/xfs_growfs.c:386 #, c-format msgid "%s: realtime growth not implemented\n" msgstr "%s: Echtzeit-Wachstum nicht implementiert\n" #: .././growfs/xfs_growfs.c:390 #, c-format msgid "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n" msgstr "%s: XFS_IOC_FSGROWFSRT xfsctl fehlgeschlagen: %s\n" #: .././growfs/xfs_growfs.c:411 #, c-format msgid "log size unchanged, skipping\n" msgstr "Protokoll-Größe unverändert, wird übersprungen\n" #: .././growfs/xfs_growfs.c:421 #, c-format msgid "%s: log growth not supported yet\n" msgstr "%s: Protokoll-Wachstum nicht implementiert\n" #: .././growfs/xfs_growfs.c:425 #, c-format msgid "%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n" msgstr "%s: XFS_IOC_FSGROWFSLOG xfsctl fehlgeschlagen: %s\n" #: .././growfs/xfs_growfs.c:433 #, c-format msgid "%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n" msgstr "%s: XFS_IOC_FSGEOMETRY xfsctl fehlgeschlagen: %s\n" #: .././growfs/xfs_growfs.c:438 #, c-format msgid "data blocks changed from %lld to %lld\n" msgstr "Datenblöcke von %lld auf %lld geändert.\n" #: .././growfs/xfs_growfs.c:441 #, c-format msgid "inode max percent changed from %d to %d\n" msgstr "Maximale Inode-Prozentzahl von %d auf %d geändert\n" #: .././growfs/xfs_growfs.c:444 #, c-format msgid "log blocks changed from %d to %d\n" msgstr "Protokollblöcke von %d auf %d geändert\n" #: .././growfs/xfs_growfs.c:447 #, c-format msgid "log changed from %s to %s\n" msgstr "Protokoll von %s auf %s geändert\n" #: .././growfs/xfs_growfs.c:451 #, c-format msgid "realtime blocks changed from %lld to %lld\n" msgstr "Echtzeit-Blöcke von %lld auf %lld geändert\n" #: .././growfs/xfs_growfs.c:454 #, c-format msgid "realtime extent size changed from %d to %d\n" msgstr "Echtzeit-Umfang von %d auf %d geändert\n" #: .././io/attr.c:59 #, c-format msgid "" "\n" " displays the set of extended inode flags associated with the current file\n" "\n" " Each individual flag is displayed as a single character, in this order:\n" " r -- file data is stored in the realtime section\n" " p -- file has preallocated extents (cannot be changed using chattr)\n" " i -- immutable, file cannot be modified\n" " a -- append-only, file can only be appended to\n" " s -- all updates are synchronous\n" " A -- the access time is not updated for this inode\n" " d -- do not include this file in a dump of the filesystem\n" " t -- child created in this directory has realtime bit set by default\n" " P -- child created in this directory has parents project ID by default\n" " n -- symbolic links cannot be created in this directory\n" " e -- for non-realtime files, observe the inode extent size value\n" " E -- children created in this directory inherit the extent size value\n" " f -- do not include this file when defragmenting the filesystem\n" " S -- enable filestreams allocator for this directory\n" "\n" " Options:\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, but only list attributes on directories\n" " -a -- show all flags which can be set alongside those which are set\n" " -v -- verbose mode; show long names of flags, not single characters\n" "\n" msgstr "" "\n" " zeigt den Satz von erweiterten Inode-Markierungen an, die zu der\n" " aktuellen Datei zugehörig sind.\n" "\n" " Jede einzelne Markierung wird als einzelner Buchstabe in dieser\n" " Reihenfolge angezeigt:\n" " r -- Dateiinhalt ist im Echtzeit-Bereich gespeichert\n" " p -- Datei hat vorher zugeteilten Umfang (kann nicht mit chattr\n" " geändert werden)\n" " i -- unveränderlich, Datei kann nicht verändert werden\n" " a -- nur anhängen, Datei kann nur daran angehängt werden\n" " s -- alle Aktualisierungen sind synchron\n" " A -- die Zugriffszeit für diesen Inode ist nicht aktualisiert\n" " d -- diese Datei nicht in die Ausgabe des Dateisystems einschließen\n" " t -- das in diesem Verzeichnis erzeugte Kind hat standardmäßig ein\n" " gesetztes Echtzeit-Bit.\n" " P -- das in diesem Verzeichnis erzeugte Kind hat standardmäßig die\n" " Projekt-ID der Eltern.\n" " n -- in diesem Verzeichnis können keine symbolischen Verweise erstellt\n" " werden\n" " e -- für Nicht-Echtzeit-Dateien wird die Größe des Inode-Umfangs beachtet\n" " E -- in diesem Verzeichnis erzeugt Kinder erben die Größe des Umfangs\n" " f -- diese Datei nicht bei der Defragmentierung des Dateisystems\n" " einschließen\n" "\n" " Optionen:\n" " -R -- rekursiv absteigend (nützlich, wenn die aktuelle Datei ein\n" " Verzeichnis ist)\n" " -D -- rekursiv absteigend, aber nur die Attribute von Verzeichnissen\n" " auflisten\n" " -a -- alle Merkmale zeigen, die neben denen gesetzt werden können, die\n" " gesetzt sind.\n" " -v -- gesprächiger Modus; zeige lange Namen der Merkmale, keine einzelnen\n" " Zeichen\n" "\n" #: .././io/attr.c:90 #, c-format msgid "" "\n" " modifies the set of extended inode flags associated with the current file\n" "\n" " Examples:\n" " 'chattr +a' - sets the append-only flag\n" " 'chattr -a' - clears the append-only flag\n" "\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, only modifying attributes on directories\n" " +/-r -- set/clear the realtime flag\n" " +/-i -- set/clear the immutable flag\n" " +/-a -- set/clear the append-only flag\n" " +/-s -- set/clear the sync flag\n" " +/-A -- set/clear the no-atime flag\n" " +/-d -- set/clear the no-dump flag\n" " +/-t -- set/clear the realtime inheritance flag\n" " +/-P -- set/clear the project ID inheritance flag\n" " +/-n -- set/clear the no-symbolic-links flag\n" " +/-e -- set/clear the extent-size flag\n" " +/-E -- set/clear the extent-size inheritance flag\n" " +/-f -- set/clear the no-defrag flag\n" " +/-S -- set/clear the filestreams allocator flag\n" " Note1: user must have certain capabilities to modify immutable/append-" "only.\n" " Note2: immutable/append-only files cannot be deleted; removing these files\n" " requires the immutable/append-only flag to be cleared first.\n" " Note3: the realtime flag can only be set if the filesystem has a realtime\n" " section, and the (regular) file must be empty when the flag is set.\n" "\n" msgstr "" "\n" " verändert den Satz von erweiterten Inode-Merkmalen, die zu der\n" " aktuellen Datei zugehörig sind.\n" "\n" " Beispiele:\n" " »chattr +a« - setzt das Nur-anhängen-Merkmal\n" " »chattr -a« - löscht das Nur-anhängen-Merkmal\n" "\n" " -R -- rekursiv absteigend (nützlich, wenn die aktuelle Datei ein\n" " Verzeichnis ist)\n" " -D -- rekursiv absteigend, aber nur die Attribute von Verzeichnissen\n" " auflisten\n" " +/-r -- setzen/löschen des Echtzeit-Merkmals\n" " +/-i -- setzen/löschen des Unveränderlich-Merkmals\n" " +/-a -- setzen/löschen des Nur-anhängen-Merkmals\n" " +/-s -- setzen/löschen des Sync-Merkmals\n" " +/-A -- setzen/löschen des No-atime-Merkmals\n" " +/-d -- setzen/löschen des No-dump-Merkmals\n" " +/-t -- setzen/löschen des Echtzeit-Vererbungs-Merkmals\n" " +/-P -- setzen/löschen des Projekt-ID-Vererbungs-Merkmals\n" " +/-n -- setzen/löschen des Kein-symbolischer-Verweis-Merkmals\n" " +/-e -- setzen/löschen des Erweiterte-Größe-Merkmals\n" " +/-E -- setzen/löschen des Erweiterte-Größe-Vererbungs-Merkmals\n" " +/-f -- setzen/löschen des Nicht-Defragmentierungs-Merkmals\n" " +/-S -- setzen/löschen des Datenstrom-Zuteiler-Merkmals\n" " Anmerkung1: Der Anwender muss gewisse Fähigkeiten haben, um das zu ändern,\n" " das unveränderlich oder zum Nur-Ändern ist.\n" " Anmerkung2: Unveränderliche-/Nur-Ändern-Dateien können nicht gelöscht\n" " werden; diese Dateien zu entfernen erfordert das vorherige\n" " Löschen des Unveränderlich-/Nur-Ändern-Merkmals.\n" " Anmerkung3: Das Echtzeit-Merkmal kann nur gesetzt werden, wenn das\n" " Dateisystem einen Echtzeit-Bereich hat, und die (reguläre)\n" " Datei muss leer sein, wenn das Merkmal gesetzt wird.\n" "\n" #: .././io/attr.c:171 .././io/attr.c:247 .././io/open.c:403 .././io/open.c:475 #: .././io/open.c:599 .././io/open.c:621 .././libxfs/init.c:110 #: .././mkfs/proto.c:284 .././quota/project.c:118 .././quota/project.c:163 #: .././quota/project.c:210 #, c-format msgid "%s: cannot open %s: %s\n" msgstr "%s: %s kann nicht geöffnet werden: %s\n" #: .././io/attr.c:174 .././io/attr.c:221 .././io/attr.c:250 .././io/attr.c:321 #: .././quota/project.c:122 .././quota/project.c:168 .././quota/project.c:215 #, c-format msgid "%s: cannot get flags on %s: %s\n" msgstr "%s: Es werden keine Merkmale von %s erlangt: %s\n" #: .././io/attr.c:256 .././io/attr.c:327 #, c-format msgid "%s: cannot set flags on %s: %s\n" msgstr "%s: Markierungen auf %s können nicht gesetzt werden: %s\n" #: .././io/attr.c:291 .././io/attr.c:305 #, c-format msgid "%s: unknown flag\n" msgstr "%s: unbekannte Markierung\n" #: .././io/attr.c:311 #, c-format msgid "%s: bad chattr command, not +/-X\n" msgstr "%s: schlechter chattr-Befehl, nicht +/-X\n" #: .././io/attr.c:336 msgid "chattr" msgstr "chattr" #: .././io/attr.c:338 msgid "[-R|-D] [+/-" msgstr "[-R|-D] [+/-" #: .././io/attr.c:343 msgid "change extended inode flags on the currently open file" msgstr "erweiterte Inode-Markierungen bei der derzeit offenen Datei ändern" #: .././io/attr.c:346 msgid "lsattr" msgstr "lsattr" #: .././io/attr.c:348 msgid "[-R|-D|-a|-v]" msgstr "[-R|-D|-a|-v]" #: .././io/attr.c:353 msgid "list extended inode flags set on the currently open file" msgstr "" "gesetzte erweiterte Inode-Markierungen bei der derzeit offenen Dateianzeigen" #: .././io/fadvise.c:31 #, c-format msgid "" "\n" " advise the page cache about expected I/O patterns on the current file\n" "\n" " Modifies kernel page cache behaviour when operating on the current file.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_FADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_FADV_DONTNEED) [*]\n" " -n -- data will be accessed once (POSIX_FADV_NOREUSE) [*]\n" " -r -- expect random page references (POSIX_FADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_FADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_FADV_WILLNEED) [*]\n" " Notes: these interfaces are not supported in Linux kernels before 2.6.\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED and NOREUSE are equivalent, and force the maximum readahead.\n" "\n" msgstr "" "\n" " benachrichtigt den Zwischenspeicher über voraussichtliche I/O-Muster der\n" " aktuellen Datei\n" "\n" " Verändert das Verhalten des Kernelseiten-Zwischenspeichers während der\n" " Bearbeitung der vorliegenden Datei.\n" " Die Bereichs-Argumente werden von einigen Benachrichtigungs-Befehlen\n" " ([*] unten) benötigt. Ohne Argumente ist die POSIX_FADV_NORMAL-" "Benachrichtigung impliziert.\n" " -d -- diese Seiten werden nicht benötigt (POSIX_FADV_DONTNEED) [*]\n" " -n -- auf die Daten wird einmal zugegriffen (POSIX_FADV_NOREUSE) [*]\n" " -r -- erwartet zufällige Seiten Referenzen (POSIX_FADV_RANDOM)\n" " -s -- erwartet fortlaufende Seiten-Referenzen (POSIX_FADV_SEQUENTIAL)\n" " -w -- möchte diese Seiten (POSIX_FADV_WILLNEED) [*]\n" " Anmerkungen: Diese Schnittstellen werden nicht von Linux-Kerneln vor 2.6.\n" " unterstützt. NORMAL stellt die Standard-Vorauslesen-" "Einstellung für diese Datei ein.\n" " RANDOM stellt die Vorauslesen-Einstellung für diese Datei auf Null.\n" " SEQUENTIAL setzt die doppelte Standard-Vorauslesen-Einstellung für diese\n" " Datei ein.\n" " WILLNEED und NOREUSE sind gleichbedeutend und erzwingen maximales\n" " Vorauslesen.\n" "\n" #: .././io/fadvise.c:93 .././io/madvise.c:87 .././io/mincore.c:48 #: .././io/sendfile.c:126 .././io/prealloc.c:49 .././io/pwrite.c:284 #: .././io/mmap.c:206 .././io/mmap.c:301 .././io/mmap.c:387 .././io/mmap.c:546 #, c-format msgid "non-numeric offset argument -- %s\n" msgstr "nicht-numerisches Versatz-Argument -- %s\n" #: .././io/fadvise.c:100 .././io/madvise.c:94 .././io/mincore.c:54 #: .././io/pread.c:330 .././io/pread.c:338 .././io/sendfile.c:133 #: .././io/prealloc.c:54 .././io/pwrite.c:290 .././io/mmap.c:212 #: .././io/mmap.c:308 .././io/mmap.c:394 .././io/mmap.c:553 #, c-format msgid "non-numeric length argument -- %s\n" msgstr "nicht-numerisches Längen-Argument -- %s\n" #: .././io/fadvise.c:118 msgid "fadvise" msgstr "fadvise" #: .././io/fadvise.c:123 msgid "[-dnrsw] [off len]" msgstr "[-dnrsw] [off len]" #: .././io/fadvise.c:124 msgid "advisory commands for sections of a file" msgstr "Benachrichtigungsbefehl für Bereiche einer Datei" #: .././io/file.c:39 #, c-format msgid "%c%03d%c %-14s (%s,%s,%s,%s%s%s%s)\n" msgstr "%c%03d%c %-14s (%s,%s,%s,%s%s%s%s)\n" #: .././io/file.c:41 msgid "foreign" msgstr "fremd" #: .././io/file.c:41 msgid "xfs" msgstr "xfs" #: .././io/file.c:42 .././io/open.c:82 msgid "sync" msgstr "synchronisieren" #: .././io/file.c:42 .././io/open.c:82 msgid "non-sync" msgstr "nicht synchronisieren" #: .././io/file.c:43 .././io/open.c:83 msgid "direct" msgstr "direkt" #: .././io/file.c:43 .././io/open.c:83 msgid "non-direct" msgstr "nicht direkt" #: .././io/file.c:44 .././io/open.c:84 msgid "read-only" msgstr "Nur-lesen" #: .././io/file.c:44 .././io/open.c:84 msgid "read-write" msgstr "Nur-schreiben" #: .././io/file.c:45 .././io/open.c:85 msgid ",real-time" msgstr "Echtzeit" #: .././io/file.c:46 .././io/open.c:86 msgid ",append-only" msgstr "Nur-anhängen" #: .././io/file.c:47 .././io/open.c:87 msgid ",non-block" msgstr "Nicht-Block" #: .././io/file.c:81 .././io/sendfile.c:103 .././quota/path.c:112 #, c-format msgid "value %d is out of range (0-%d)\n" msgstr "Wert %d ist außerhalb des Bereichs (0-%d)\n" #: .././io/file.c:92 msgid "file" msgstr "Datei" #: .././io/file.c:93 msgid "f" msgstr "f" #: .././io/file.c:94 .././quota/path.c:126 msgid "[N]" msgstr "[N]" #: .././io/file.c:99 msgid "set the current file" msgstr "derzeitige Datei setzen" #: .././io/file.c:101 .././quota/path.c:133 msgid "print" msgstr "ausgeben" #: .././io/file.c:102 .././quota/path.c:134 msgid "p" msgstr "p" #: .././io/file.c:108 msgid "list current open files and memory mappings" msgstr "gibt derzeit offene Dateien und Speicherauszüge an" #: .././io/fsync.c:54 msgid "fsync" msgstr "fsync" #: .././io/fsync.c:55 .././repair/progress.c:430 .././repair/progress.c:440 #: .././repair/progress.c:456 .././repair/progress.c:474 #: .././repair/progress.c:489 msgid "s" msgstr "s" #: .././io/fsync.c:59 msgid "calls fsync(2) to flush all in-core file state to disk" msgstr "" "ruft fsync(2) auf, um alle Dateistatusse aus dem Kern auf die\n" "Platte zu leeren" #: .././io/fsync.c:61 msgid "fdatasync" msgstr "fdatasync" #: .././io/fsync.c:62 msgid "ds" msgstr "ds" #: .././io/fsync.c:66 msgid "calls fdatasync(2) to flush the files in-core data to disk" msgstr "" "ruft fsync(2) auf, um alle Dateiinhalte aus dem Kern auf die\n" "Platte zu leeren" #: .././io/getrusage.c:112 msgid "getrusage" msgstr "getrusage" #: .././io/getrusage.c:113 msgid "g" msgstr "g" #: .././io/getrusage.c:118 msgid "report process resource usage" msgstr "Bericht, Prozess, Ressource, Aufruf" #: .././io/imap.c:53 #, c-format msgid "ino %10llu count %2d mask %016llx\n" msgstr "ino %10llu Anzahl %2d Maske %016llx\n" #: .././io/imap.c:67 msgid "imap" msgstr "imap" #: .././io/imap.c:71 msgid "[nentries]" msgstr "[nentries]" #: .././io/imap.c:73 msgid "inode map for filesystem of current file" msgstr "Inode-Karte für das Dateisystem der " #: .././io/init.c:35 #, c-format msgid "Usage: %s [-adFfmrRstx] [-p prog] [-c cmd]... file\n" msgstr "Aufruf: %s [-adFfmrRstx] [-p Programm] [-c Befehl]... Datei\n" #: .././io/init.c:98 .././io/mmap.c:168 .././io/mmap.c:175 .././io/mmap.c:178 #: .././io/open.c:281 #, c-format msgid "no files are open, try 'help open'\n" msgstr "es sind keine Dateien geöffnet, versuchen sie »help open«\n" #: .././io/init.c:102 .././io/mmap.c:167 .././io/mmap.c:174 #, c-format msgid "no mapped regions, try 'help mmap'\n" msgstr "keine kartierten Bereiche, versuchen sie »help open«\n" #: .././io/init.c:108 #, c-format msgid "foreign file active, %s command is for XFS filesystems only\n" msgstr "Fremde Datei aktiv, der %s-Befehl ist nur für das XFS-Dateisystem\n" #: .././io/init.c:153 .././io/open.c:303 #, c-format msgid "non-numeric mode -- %s\n" msgstr "nicht-numerischer Modus -- %s\n" #: .././io/inject.c:109 #, c-format msgid "" "\n" " inject errors into the filesystem of the currently open file\n" "\n" " Example:\n" " 'inject readagf' - cause errors on allocation group freespace reads\n" "\n" " Causes the kernel to generate and react to errors within XFS, provided\n" " the XFS kernel code has been built with debugging features enabled.\n" " With no arguments, displays the list of error injection tags.\n" "\n" msgstr "" "\n" " speist Fehler in das Dateisystem der aktuell geöffneten Datei ein\n" "\n" " Beispiel:\n" " »inject readagf« - ruft Fehler hervor beim Lesen des für die Gruppe\n" " reservierten freien Raumes hervor\n" "\n" " Veranlasst den Kernel zu generieren und auf Fehler im XFS zu reagieren,\n" " vorausgesetzt, der Kernel-Kode wurde mit eingeschalteten\n" " Fehlersuche-Merkmalen erzeugt. Ohne Argumente wird eine Liste der\n" " Fehler-Einspeisungs-Kennzeichen angezeigt.\n" "\n" #: .././io/inject.c:135 #, c-format msgid "no such tag -- %s\n" msgstr "kein solches Kennzeichen -- %s\n" #: .././io/inject.c:151 msgid "inject" msgstr "einspeisen" #: .././io/inject.c:156 msgid "[tag ...]" msgstr "[Kennzeichen ...]" #: .././io/inject.c:157 msgid "inject errors into a filesystem" msgstr "Fehler in ein Dateisystem einspeisen" #: .././io/madvise.c:32 #, c-format msgid "" "\n" " advise the page cache about access patterns expected for a mapping\n" "\n" " Modifies page cache behavior when operating on the current mapping.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_MADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_MADV_DONTNEED) [*]\n" " -r -- expect random page references (POSIX_MADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_MADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_MADV_WILLNEED) [*]\n" " Notes:\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED forces the maximum readahead.\n" "\n" msgstr "" "\n" " teilt dem Seiten-Zwischenspeicher die erwarteten Zugriffs-Vorlagen für\n" " eine Kartierung mit\n" "\n" " Ändert das Verhalten des Seiten-Zwischenspeichers beim Operieren auf der\n" " gegenwärtigen Kartierung. Die Bereichs-Argumente werden von einigen\n" " Ankündigungs-Befehlen benötigt([*] unten).\n" " Ohne Argumente ist die POSIX_MADV_NORMAL-Benachrichtigung impliziert.\n" " -d -- diese Seiten werden nicht benötigt (POSIX_MADV_DONTNEED) [*]\n" " -r -- erwartet zufällige Seiten Referenzen (POSIX_MADV_RANDOM)\n" " -s -- erwartet fortlaufende Seiten-Referenzen (POSIX_MADV_SEQUENTIAL)\n" " -w -- möchte diese Seiten (POSIX_MADV_WILLNEED) [*]\n" " NORMAL stellt die Standard-Vorauslesen-Einstellung für diese Datei ein.\n" " RANDOM stellt die Vorauslesen-Einstellung für diese Datei auf Null.\n" " SEQUENTIAL setzt die doppelte Standard-Vorauslesen-Einstellung für diese\n" " Datei ein.\n" " WILLNEED und NOREUSE sind gleichbedeutend und erzwingen maximales\n" " Vorauslesen.\n" "\n" #: .././io/madvise.c:116 msgid "madvise" msgstr "madvise" #: .././io/madvise.c:117 msgid "ma" msgstr "ma" #: .././io/madvise.c:122 msgid "[-drsw] [off len]" msgstr "[-drsw] [off len]" #: .././io/madvise.c:123 msgid "give advice about use of memory" msgstr "einen Rat über den Gebrauch des Speichers geben" #: .././io/mincore.c:87 .././io/mincore.c:97 #, c-format msgid "0x%lx %lu pages (%llu : %lu)\n" msgstr "0x%lx %lu Seiten (%llu : %lu)\n" #: .././io/mincore.c:111 msgid "mincore" msgstr "mincore" #: .././io/mincore.c:112 msgid "mi" msgstr "mi" #: .././io/mincore.c:117 msgid "[off len]" msgstr "[off len]" #: .././io/mincore.c:118 msgid "find mapping pages that are memory resident" msgstr "Kartierungsseiten finden, die speicherresident sind" #: .././io/pread.c:32 #, c-format msgid "" "\n" " reads a range of bytes in a specified block size from the given offset\n" "\n" " Example:\n" " 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n" "\n" " Reads a segment of the currently open file, optionally dumping it to the\n" " standard output stream (with -v option) for subsequent inspection.\n" " The reads are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different pattern is requested.\n" " -B -- read backwards through the range from offset (backwards N bytes)\n" " -F -- read forwards through the range of bytes from offset (default)\n" " -v -- be verbose, dump out buffers (used when reading forwards)\n" " -R -- read at random offsets in the range of bytes\n" " -Z N -- zeed the random number generator (used when reading randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" " When in \"random\" mode, the number of read operations will equal the\n" " number required to do a complete forward/backward scan of the range.\n" " Note that the offset within the range is chosen at random each time\n" " (an offset may be read more than once when operating in this mode).\n" "\n" msgstr "" "\n" " liest einen Bereich von Bytes in einer angegeben Block-Größe vom gegebenen\n" " Versatz\n" "\n" " Beispiel:\n" " »pread -v 512 20« - Auszug von gelesenen 20 Bytes aus 512 Bytes in die\n" " Datei\n" "\n" " Liest einen Ausschnitt der derzeit offenen Datei, leert sie optional in " "den\n" " Standard-Ausgabe-Datenstrom (mit »-v-Option«) für die nachfolgende\n" " Überprüfung. Das Lesen wird, vom Versatz beginnend, in fortlaufenden\n" " Blöcken mit durch die »-b«-Option einstellbarer Blockgröße ausgeführt\n" " (Standard-Blockgröße ist 4096 Bytes), außer wenn ein anderes Muster\n" " angefordert ist.\n" " -B -- liest vom Versatz rückwärts durch den Bereich (Rückwärts N Bytes)\n" " -F -- liest vom Versatz vorwärts durch den Bereich (Standard)\n" " -v -- detaillierte Ausgabe, Puffer leeren (beim Vorwärtslesen benutzt)\n" " -R -- von zufälligem Versatz im Bereich der Bytes lesen\n" " -Z N -- »zeedet« den Zufallszahlengenerator (benutzt beim zufälligen Lesen)\n" " (Heh, Zorry, die -s-/-S-Argumente sind in Benutzung durch pwrite)\n" " Im »Zufalls«-Modus entspricht die Anzahl der Leseoperationen der benötigten\n" " Anzahl, um einen kompletten Vor-/Rückwärtsscan des Bereiches zu machen.\n" " Merken Sie sich, dass der Versatz innerhalb des Bereiches jedesmal " "zufällig\n" " gewählt wird (ein Versatz könnte mehr als einmal beim Ausführen dieses\n" " Modus gelesen werden).\n" "\n" #: .././io/pread.c:286 .././io/pwrite.c:217 #, c-format msgid "non-numeric bsize -- %s\n" msgstr "nicht-numerische bsize -- %s\n" #: .././io/pread.c:315 .././io/pwrite.c:251 .././io/pwrite.c:270 #: .././io/mmap.c:530 #, c-format msgid "non-numeric seed -- %s\n" msgstr "Nicht-numerische Füllzeichen -- %s\n" #: .././io/pread.c:375 #, c-format msgid "read %lld/%lld bytes at offset %lld\n" msgstr "%lld/%lld Bytes lesen beim Versatz %lld lesen\n" #: .././io/pread.c:377 .././io/sendfile.c:163 .././io/pwrite.c:336 #, c-format msgid "%s, %d ops; %s (%s/sec and %.4f ops/sec)\n" msgstr "%s, %d ops; %s (%s/Sek und %.4f ops/Sek)\n" #: .././io/pread.c:390 msgid "pread" msgstr "pread" #: .././io/pread.c:391 msgid "r" msgstr "r" #: .././io/pread.c:396 msgid "[-b bs] [-v] off len" msgstr "[-b bs] [-v] off len" #: .././io/pread.c:397 msgid "reads a number of bytes at a specified offset" msgstr "liest eine Anzahl von Bytes beim angegebenen Versatz" #: .././io/resblks.c:39 #, c-format msgid "non-numeric argument -- %s\n" msgstr "nicht-numerisches Argument -- %s\n" #: .././io/resblks.c:51 #, c-format msgid "reserved blocks = %llu\n" msgstr "reservierte Blöcke = %llu\n" #: .././io/resblks.c:53 #, c-format msgid "available reserved blocks = %llu\n" msgstr "verfügbare reservierte Blöcke = %llu\n" #: .././io/resblks.c:61 msgid "resblks" msgstr "resblks" #: .././io/resblks.c:66 msgid "[blocks]" msgstr "[Blöcke]" #: .././io/resblks.c:68 msgid "get and/or set count of reserved filesystem blocks" msgstr "Anzahl derreservierten Dateisystem-Blöcke angeben und/oder setzen" #: .././io/sendfile.c:32 #, c-format msgid "" "\n" " transfer a range of bytes from the given offset between files\n" "\n" " Example:\n" " 'send -f 2 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Copies data between one file descriptor and another. Because this copying\n" " is done within the kernel, sendfile does not need to transfer data to and\n" " from user space.\n" " -f -- specifies an input file from which to source data to write\n" " -i -- specifies an input file name from which to source data to write.\n" " An offset and length in the source file can be optionally specified.\n" "\n" msgstr "" "\n" " einen Bereich von Bytes von gegebenen Versatz zwischen Dateien übertragen\n" "\n" " Beispiel:\n" " »send -f 2 512 20« - überträge 20 von 512 Bytes in die offene Datei\n" "\n" " Kopiert Daten zwischen einem Datei-Deskriptor und einem anderen. Weil\n" " dieses Kopieren innerhalb des Kernels erledigt wird, müssen keine Daten " "der\n" " Sendedatei zum und vom Benutzerraum übertragen werden.\n" " -f -- gibt eine Eingabedatei an, aus der die Quelldaten zu schreiben sind.\n" " -i -- gibt einen Eingabedateinamen an, von dem die Quelldaten zu schreiben\n" " sind.\n" " Optional kann ein Versatz und eine Länge in der Quelldatei angegeben\n" " werden.\n" "\n" #: .././io/sendfile.c:161 #, c-format msgid "sent %lld/%lld bytes from offset %lld\n" msgstr "sende %lld/%lld Bytes vom Versatz %lld\n" #: .././io/sendfile.c:179 msgid "sendfile" msgstr "sendfile" #: .././io/sendfile.c:180 msgid "send" msgstr "senden" #: .././io/sendfile.c:186 msgid "-i infile | -f N [off len]" msgstr "-i infile | -f N [off len]" #: .././io/sendfile.c:188 msgid "Transfer data directly between file descriptors" msgstr "Daten direkt zwischen Datei-Deskriptoren übertragen" #: .././io/shutdown.c:54 msgid "shutdown" msgstr "herunterfahren" #: .././io/shutdown.c:59 msgid "[-f]" msgstr "[-f]" #: .././io/shutdown.c:61 msgid "shuts down the filesystem where the current file resides" msgstr "fährt das Dateisystem herunter auf dem die aktuelle Datei liegt" #: .././io/truncate.c:38 #, c-format msgid "non-numeric truncate argument -- %s\n" msgstr "nicht-numerisches Kürzungs-Argument -- %s\n" #: .././io/truncate.c:52 msgid "truncate" msgstr "kürzen" #: .././io/truncate.c:53 msgid "t" msgstr "t" #: .././io/truncate.c:58 .././quota/state.c:520 msgid "off" msgstr "aus" #: .././io/truncate.c:60 msgid "truncates the current file at the given offset" msgstr "kürzt die aktuelle Datei am gegebenen Versatz" #: .././io/freeze.c:37 #, c-format msgid "%s: cannot freeze filesystem at %s: %s\n" msgstr "%s: Dateisystem kann nicht bei %s gesperrt werden: %s\n" #: .././io/freeze.c:54 #, c-format msgid "%s: cannot unfreeze filesystem mounted at %s: %s\n" msgstr "%s: das auf %s einhängte Dateisystem kann nicht entsperrt werden: %s\n" #: .././io/freeze.c:65 msgid "freeze" msgstr "sperren" #: .././io/freeze.c:70 msgid "freeze filesystem of current file" msgstr "Dateisystem der aktuellen Datei sperren" #: .././io/freeze.c:72 msgid "thaw" msgstr "auftauen" #: .././io/freeze.c:77 msgid "unfreeze filesystem of current file" msgstr "Dateisystem der aktuellen Datei entsperren" #: .././io/prealloc.c:165 msgid "allocsp" msgstr "allocsp" #: .././io/prealloc.c:170 .././io/prealloc.c:178 .././io/prealloc.c:186 #: .././io/prealloc.c:194 msgid "off len" msgstr "off len" #: .././io/prealloc.c:171 msgid "allocates zeroed space for part of a file" msgstr "stellt genullten Speicher für einen Teil der Datei bereit" #: .././io/prealloc.c:173 msgid "freesp" msgstr "freesp" #: .././io/prealloc.c:179 msgid "frees space associated with part of a file" msgstr "leert Speicher, der mit einem Teil einer Datei verbunden ist" #: .././io/prealloc.c:181 msgid "resvsp" msgstr "resvsp" #: .././io/prealloc.c:188 msgid "reserves space associated with part of a file" msgstr "reserviert Speicher, der mit einem Teil einer Datei verbunden ist" #: .././io/prealloc.c:190 msgid "unresvsp" msgstr "unresvsp" #: .././io/prealloc.c:197 msgid "frees reserved space associated with part of a file" msgstr "" "gibt reservierten Speicher frei, der mit einem Teil einer Datei verbunden ist" #: .././io/prealloc.c:205 msgid "falloc" msgstr "falloc" #: .././io/prealloc.c:210 msgid "[-k] off len" msgstr "[-k] [off len]" #: .././io/prealloc.c:212 msgid "allocates space associated with part of a file via fallocate" msgstr "" "weist Speicher zu, der mit einem Teil der Datei über fallocate verbunden ist" #: .././io/pwrite.c:31 #, c-format msgid "" "\n" " writes a range of bytes (in block size increments) from the given offset\n" "\n" " Example:\n" " 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Writes into a segment of the currently open file, using either a buffer\n" " filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n" " The writes are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different write pattern is requested.\n" " -S -- use an alternate seed number for filling the write buffer\n" " -i -- input file, source of data to write (used when writing forward)\n" " -d -- open the input file for direct IO\n" " -s -- skip a number of bytes at the start of the input file\n" " -w -- call fdatasync(2) at the end (included in timing results)\n" " -W -- call fsync(2) at the end (included in timing results)\n" " -B -- write backwards through the range from offset (backwards N bytes)\n" " -F -- write forwards through the range of bytes from offset (default)\n" " -R -- write at random offsets in the specified range of bytes\n" " -Z N -- zeed the random number generator (used when writing randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" "\n" msgstr "" "\n" " schreibt einen Bereich von Bytes (Erhöhungen in Blockgröße) vom gegebenen\n" " Versatz\n" "\n" " Beispiel:\n" " »pwite 512 20« - schreibt 20 Bytes aus 512 Bytes in die Datei\n" "\n" " Schreibt unter Benutzung eines Puffers, der mit einem Mustersatz oder mit\n" " aus einer Eingabedatei gelesenen Daten gefüllt wurde, in einen Ausschnitt\n" " der derzeit offenen Datei. Das Lesen wird, vom Versatz beginnend, in " "fortlaufenden\n" " Blöcken mit durch die »-b«-Option einstellbarer Blockgröße ausgeführt\n" " (Standard-Blockgröße ist 4096 Bytes), außer wenn ein anderes Muster\n" " angefordert ist.\n" " -S -- alternative Füllnummer benutzen um den Schreibpuffer zu füllen\n" " -i -- Eingabedatei, Datenquelle zum Schreiben (benutzt, wenn vorwärts\n" " geschrieben wird)\n" " -d -- Eingabedatei für direktes IO öffnen\n" " -s -- eine Anzahl von Bytes am Anfang der Eingabedatei überspringen\n" " -w -- am Ende fdatasync(2) aufrufen (einschließlich zeitlicher " "Resultate)\n" " -W -- am Ende fsync(2) aufrufen (einschließlich zeitlicher Resultate)\n" " -B -- liest vom Versatz rückwärts durch den Bereich (Rückwärts N Bytes)\n" " -F -- liest vom Versatz vorwärts durch den Bereich (Standard)\n" " -R -- von zufälligem Versatz im Bereich der Bytes lesen\n" " -Z N -- »zeedet« den Zufallszahlengenerator (benutzt beim zufälligen Lesen)\n" " (Heh, Zorry, die -s-/-S-Argumente sind in Benutzung durch pwrite)\n" "\n" #: .././io/pwrite.c:244 #, c-format msgid "non-numeric skip -- %s\n" msgstr "nicht-numerische überspringen -- %s\n" #: .././io/pwrite.c:334 #, c-format msgid "wrote %lld/%lld bytes at offset %lld\n" msgstr "schrieb %lld/%lld Bytes ab Versatz %lld\n" #: .././io/pwrite.c:352 msgid "pwrite" msgstr "pwrite" #: .././io/pwrite.c:353 msgid "w" msgstr "w" #: .././io/pwrite.c:359 msgid "[-i infile [-d] [-s skip]] [-b bs] [-S seed] [-wW] off len" msgstr "[-i infile [-d] [-s überspringen]] [-b bs] [-S seed] [-wW] off len" #: .././io/pwrite.c:361 msgid "writes a number of bytes at a specified offset" msgstr "schreibt ein Anzahl von Bytes ab dem angegebenen Versatz" #: .././io/bmap.c:30 #, c-format msgid "" "\n" " prints the block mapping for an XFS file's data or attribute forks\n" " Example:\n" " 'bmap -vp' - tabular format verbose map, including unwritten extents\n" "\n" " bmap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -d -- suppresses a DMAPI read event, offline portions shown as holes.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " Note: the bmap for non-regular files can be obtained provided the file\n" " was opened appropriately (in particular, must be opened read-only).\n" "\n" msgstr "" "\n" " gibt die Block-Kartierung für die Daten- oder Attribus-Verzweigungen einer\n" " XFS-Datei aus\n" " Beispiel:\n" " »bmap -vp« - aussagekräftige Karte im Tabellenformat, einschließlich\n" " ungeschriebenem Umfang\n" "\n" " »bmap« schreibt die Karte der Plattenblöcke, die von der derzeitigen Datei\n" " belegt werden.\n" " Die Karte listet jeden Bereich, der von der Datei belegt wird, sowie \n" " Regionen in der Datei, die keine zugehörigen Blöcke (Löcher) haben auf.\n" " Standardmäßig nimmt jede Zeile der Liste die folgende Form an:\n" " Bereich: [Startversatz..Endversatz]: Startblock..Endblock\n" " Löcher sind durch den Ersatz von Startblock..Endblock durch »Loch«\n" " markiert.\n" " Alle Datei-Offsets und Plattenblöcke sind Einheiten aus 512-Byte-Blöcken.\n" " -a -- gibt die Attributs-Verzweigungs-Karte statt der\n" " Daten-Verzweigung aus.\n" " -d -- unterdrückt ein DMAPI-Lese-Ereignis, Offline-Teile werden als Löcher\n" " betrachtet.\n" " -l -- zeigt außerdem die Länge von jedem Bereich in 512-Byte Blöcken.\n" " Anmerkung: Das »bmap« für irreguläre Dateien kann bereitgestellt werden,\n" " statt der Datei die passend geöffnet wurde (im Einzelnen darf sie\n" " Nur-Lesend geöffnet werden)\n" "\n" #: .././io/bmap.c:120 #, c-format msgid "%s: can't get geometry [\"%s\"]: %s\n" msgstr "%s: Geometrie [»%s«] kann nicht ermittelt werden: %s\n" #: .././io/bmap.c:128 #, c-format msgid "%s: cannot read attrs on \"%s\": %s\n" msgstr "%s: attrs auf »%s« können nicht gelesen werden: %s\n" #: .././io/bmap.c:146 #, c-format msgid "%s: malloc of %d bytes failed.\n" msgstr "%s: Speicherallokation von %d Bytes fehlgeschlagen.\n" #: .././io/bmap.c:194 #, c-format msgid "%s: xfsctl(XFS_IOC_GETBMAPX) iflags=0x%x [\"%s\"]: %s\n" msgstr "%s: xfsctl(XFS_IOC_GETBMAPX) iflags=0x%x [\"%s\"]: %s\n" #: .././io/bmap.c:225 #, c-format msgid "%s: cannot realloc %d bytes\n" msgstr "%s: %d Bytes können nicht realloziert werden.\n" #: .././io/bmap.c:234 #, c-format msgid "%s: no extents\n" msgstr "%s: keine Bereiche\n" #: .././io/bmap.c:248 .././io/bmap.c:376 #, c-format msgid "hole" msgstr "Loch" #: .././io/bmap.c:257 #, c-format msgid " %lld blocks\n" msgstr "%lld Blöcke\n" #: .././io/bmap.c:336 msgid "EXT" msgstr "EXT" #: .././io/bmap.c:337 msgid "FILE-OFFSET" msgstr "DATEI-VERSATZ" #: .././io/bmap.c:338 msgid "RT-BLOCK-RANGE" msgstr "RT-BLOCK-AUSWAHL" #: .././io/bmap.c:338 msgid "BLOCK-RANGE" msgstr "BLOCK-AUSWAHL" #: .././io/bmap.c:339 msgid "AG" msgstr "AG" #: .././io/bmap.c:340 msgid "AG-OFFSET" msgstr "AG-VERSATZ" #: .././io/bmap.c:341 msgid "TOTAL" msgstr "GESAMT" #: .././io/bmap.c:342 msgid " FLAGS" msgstr "MARKIERUNGEN" #: .././io/bmap.c:410 #, c-format msgid " FLAG Values:\n" msgstr "MARKIERUNGS-Werte:\n" #: .././io/bmap.c:411 #, c-format msgid " %*.*o Unwritten preallocated extent\n" msgstr " %*.*o Ungeschriebener vorher zugeteiler Bereich\n" #: .././io/bmap.c:413 #, c-format msgid " %*.*o Doesn't begin on stripe unit\n" msgstr " %*.*o Beginnt nicht auf der Stripe-Einheit\n" #: .././io/bmap.c:415 #, c-format msgid " %*.*o Doesn't end on stripe unit\n" msgstr " %*.*o Endet nicht auf der Stripe-Einheit\n" #: .././io/bmap.c:417 #, c-format msgid " %*.*o Doesn't begin on stripe width\n" msgstr " %*.*o Beginnt nicht auf der Stripe-Breite\n" #: .././io/bmap.c:419 #, c-format msgid " %*.*o Doesn't end on stripe width\n" msgstr " %*.*o Endet nicht auf der Stripe-Breite\n" #: .././io/bmap.c:430 msgid "bmap" msgstr "bmap" #: .././io/bmap.c:435 msgid "[-adlpv] [-n nx]" msgstr "[-adlpv] [-n nx]" #: .././io/bmap.c:436 msgid "print block mapping for an XFS file" msgstr "Blockkarte für eine XFS-Datei ausgeben" #: .././io/mmap.c:76 #, c-format msgid "offset (%lld) is before start of mapping (%lld)\n" msgstr "Versatz (%lld) liegt vor dem Start der Kartierung (%lld)\n" #: .././io/mmap.c:82 #, c-format msgid "offset (%lld) is beyond end of mapping (%lld)\n" msgstr "Versatz (%lld) liegt hinter dem Ende der Kartierung (%lld)\n" #: .././io/mmap.c:87 #, c-format msgid "range (%lld:%lld) is beyond mapping (%lld:%ld)\n" msgstr "Bereich (%lld:%lld) liegt außerhalb der Kartierung (%lld:%ld)\n" #: .././io/mmap.c:93 #, c-format msgid "offset address (%p) is not page aligned\n" msgstr "Versatz-Adresse (%p) ist nicht an der Seite ausgerichtet\n" #: .././io/mmap.c:133 #, c-format msgid "" "\n" " maps a range within the current file into memory\n" "\n" " Example:\n" " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n" "\n" " Memory maps a range of a file for subsequent use by other xfs_io commands.\n" " With no arguments, mmap shows the current mappings. The current mapping\n" " can be set by using the single argument form (mapping number or address).\n" " If two arguments are specified (a range), a new mapping is created and the\n" " following options are available:\n" " -r -- map with PROT_READ protection\n" " -w -- map with PROT_WRITE protection\n" " -x -- map with PROT_EXEC protection\n" " If no protection mode is specified, all are used by default.\n" "\n" msgstr "" "\n" " bildet einen Bereich innerhalb der aktuellen Datei im Speicher ab.\n" "\n" " Beispiel:\n" " »mmap -rw 0 1m« - bildet ein Megabyte vom Anfang der aktuellen Datei ab\n" "\n" " Speicher eines Dateibereiches für eine nachfolgende Benutzung durch andere\n" " xfs-io-Befehle abbilden.\n" " Ohne Argumente zeigt mmap die derzeitige Kartierung. Die derzeitige\n" " Kartierung kann durch Benutzung einer einzelnen Argument-Form\n" " (Kartierungsnummer oder Adresse) gesetzt werden.\n" " Wenn zwei Argumente angegeben wurden (ein Bereich) wird eine neue\n" " Kartierung erstellt und die folgenden Optionen sind verfügbar:\n" " -r -- Karte mit PROT_READ-Schutz\n" " -w -- Karte mit PROT_WRITE-Schutz\n" " -x -- Karte mit PROT_EXEC-Schutz\n" " Wenn kein Schutz-Modus angegeben wurde, werden standardmäßig alle benutzt.\n" "\n" #: .././io/mmap.c:254 #, c-format msgid "" "\n" " flushes a range of bytes in the current memory mapping\n" "\n" " Writes all modified copies of pages over the specified range (or entire\n" " mapping if no range specified) to their backing storage locations. Also,\n" " optionally invalidates so that subsequent references to the pages will be\n" " obtained from their backing storage locations (instead of cached copies).\n" " -a -- perform asynchronous writes (MS_ASYNC)\n" " -i -- invalidate mapped pages (MS_INVALIDATE)\n" " -s -- perform synchronous writes (MS_SYNC)\n" "\n" msgstr "" "\n" " leert einen Bereich von Bytes in der aktuellen Speicher-Kartierung\n" "\n" " Schreibt alle veränderten Seitenkopien über den angegebenen Bereich (oder \n" " die vollständige Kartierung, wenn kein Bereich angegeben wurde) auf ihre\n" " zusätzlichen Speicherorte. Außerdem werden optional alle außer Kraft\n" " gesetzt, so dass nachfolgende Verweise von den zusätzlichen Speicherorten\n" " (anstelle der Kopien im Zwischenspeicher) erhalten werden.\n" " -a -- asynchrones Schreiben ausführen (MS_ASYNC)\n" " -i -- kartierte Seiten ungültig erklären (MS_INVALIDATE)\n" " -s -- synchrones Schreiben ausführen (MS_SYNC)\n" "\n" #: .././io/mmap.c:330 #, c-format msgid "" "\n" " reads a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n" "\n" " Accesses a range of the current memory mapping, optionally dumping it to\n" " the standard output stream (with -v option) for subsequent inspection.\n" " -f -- verbose mode, dump bytes with offsets relative to start of file.\n" " -r -- reverse order; start accessing from the end of range, moving " "backward\n" " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n" " The accesses are performed sequentially from the start offset by default.\n" " Notes:\n" " References to whole pages following the end of the backing file results\n" " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n" " on various filesystem conditions, including quota exceeded errors, and\n" " for physical device errors (such as unreadable disk blocks). No attempt\n" " has been made to catch signals at this stage...\n" "\n" msgstr "" "\n" " liest einen Bereich von Bytes in die aktuelle Speicherkartierung\n" "\n" " Beispiel:\n" " »mread -v 512 20« - Auszug von gelesenen 20 Bytes von 512 Bytes in die\n" " Kartierung\n" "\n" " Greift auf einen Bereich der aktuellen Speicherkartierung zu oder gibt\n" " sie optional zum Standard-Ausgabe-Strom aus (mit der »-v«-Option) für die\n" " nachfolgende Überprüfung.\n" " -f -- detaillierte Ausgabe - gibt Bytes mit relativem Versatz zum Anfang\n" " der Datei aus.\n" " -r -- umgekehrte Reihenfolge; Zugriff vom Ende des Bereiches beginnen und\n" " rückwärts bewegen.\n" " -v -- detaillierte Ausgabe - gibt Bytes mit relativem Versatz zum Anfang\n" " der Kartierung aus.\n" " Standardmäßig werden die Zugriffe der Reihe nach vom Versatz des Anfangs\n" " durchgeführt.\n" " Anmerkungen:\n" " Bezieht sich auf die ganzen Seiten, die dem Ende der\n" " Zusatzdatei-Ergebnisse bei der Zusendung des SIGBUS-Signals folgen.\n" " SIGBUS-Signale können außerdem unter unterschiedlichen\n" " Dateisystem-Bedingungen gesandt werden, einschließlich\n" " Quota-Überschreitungs-Fehlern und physischen Gerätefehlern (wie\n" " unlesbaren Platten-Blocks). Es wurde kein Versuch unternommen auf dieser\n" " Ebene Signale abzufangen...\n" "\n" #: .././io/mmap.c:494 #, c-format msgid "" "\n" " dirties a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n" "\n" " Stores a byte into memory for a range within a mapping.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -S -- use an alternate seed character\n" " -r -- reverse order; start storing from the end of range, moving backward\n" " The stores are performed sequentially from the start offset by default.\n" "\n" msgstr "" "\n" " verunreinigt einen Bereich von Bytes in die aktuelle Speicherkartierung\n" "\n" " Beispiel:\n" " »mwrite 512 20« - schreibt 20 Bytes von 512 Bytes a in die aktuelle\n" " Kartierung\n" "\n" " Speichert ein Byte in den Speicher für einen Bereich innerhalb einer \n" " Kartierung. Der Standard-Speicherwert ist »X«, das wiederholt wird um \n" " den angegebenen Bereich zu füllen.\n" " -S -- verwende ein anderes Füllzeichen\n" " -r -- umgekehrte Reihenfolge; Speichern vom Ende des Bereiches beginnen\n" " und rückwärts bewegen.\n" " Standardmäßig wird der Reihe nach vom Versatz des Anfangs gespeichert.\n" "\n" #: .././io/mmap.c:580 msgid "mmap" msgstr "mmap" #: .././io/mmap.c:581 msgid "mm" msgstr "mm" #: .././io/mmap.c:586 msgid "[N] | [-rwx] [off len]" msgstr "[N] | [-rwx] [off len]" #: .././io/mmap.c:588 msgid "mmap a range in the current file, show mappings" msgstr "mmap eines Bereiches der aktuellen Datei, Kartierungen anzeigen" #: .././io/mmap.c:591 msgid "mread" msgstr "mread" #: .././io/mmap.c:592 msgid "mr" msgstr "mr" #: .././io/mmap.c:597 msgid "[-r] [off len]" msgstr "[-r] [off len]" #: .././io/mmap.c:599 msgid "reads data from a region in the current memory mapping" msgstr "liest Daten aus einer Region der derzeitigen Speicherkartierung" #: .././io/mmap.c:602 msgid "msync" msgstr "msync" #: .././io/mmap.c:603 msgid "ms" msgstr "ms" #: .././io/mmap.c:608 msgid "[-ais] [off len]" msgstr "[-ais] [off len]" #: .././io/mmap.c:609 msgid "flush a region in the current memory mapping" msgstr "leere eine Region der derzeitigen Speicherkartierung" #: .././io/mmap.c:612 msgid "munmap" msgstr "munmap" #: .././io/mmap.c:613 msgid "mu" msgstr "mu" #: .././io/mmap.c:618 msgid "unmaps the current memory mapping" msgstr "die aktuelle Speicherkartierung entladen" #: .././io/mmap.c:620 msgid "mwrite" msgstr "mwrite" #: .././io/mmap.c:621 msgid "mw" msgstr "mw" #: .././io/mmap.c:626 msgid "[-r] [-S seed] [off len]" msgstr "[-r] [-S seed] [off len]" #: .././io/mmap.c:628 msgid "writes data into a region in the current memory mapping" msgstr "schreibt Daten in eine Region der derzeitigen Speicherkartierung" #: .././io/open.c:53 msgid "socket" msgstr "Socket" #: .././io/open.c:55 msgid "directory" msgstr "Verzeichnis" #: .././io/open.c:57 msgid "char device" msgstr "zeichenorientiertes Gerät" #: .././io/open.c:59 msgid "block device" msgstr "blockorientiertes Gerät" #: .././io/open.c:61 msgid "regular file" msgstr "reguläre Datei" #: .././io/open.c:63 msgid "symbolic link" msgstr "symbolischer Verweis" #: .././io/open.c:65 msgid "fifo" msgstr "fifo" #: .././io/open.c:80 .././io/open.c:725 #, c-format msgid "fd.path = \"%s\"\n" msgstr "fd.path = \"%s\"\n" #: .././io/open.c:81 #, c-format msgid "fd.flags = %s,%s,%s%s%s%s\n" msgstr "fd.flags = %s,%s,%s%s%s%s\n" #: .././io/open.c:91 #, c-format msgid "stat.ino = %lld\n" msgstr "stat.ino = %lld\n" #: .././io/open.c:92 #, c-format msgid "stat.type = %s\n" msgstr "stat.type = %s\n" #: .././io/open.c:93 #, c-format msgid "stat.size = %lld\n" msgstr "stat.size = %lld\n" #: .././io/open.c:94 #, c-format msgid "stat.blocks = %lld\n" msgstr "stat.blocks = %lld\n" #: .././io/open.c:96 #, c-format msgid "stat.atime = %s" msgstr "stat.atime = %s" #: .././io/open.c:97 #, c-format msgid "stat.mtime = %s" msgstr "stat.mtime = %s" #: .././io/open.c:98 #, c-format msgid "stat.ctime = %s" msgstr "stat.ctime = %s" #: .././io/open.c:107 #, c-format msgid "fsxattr.xflags = 0x%x " msgstr "fsxattr.xflags = 0x%x " #: .././io/open.c:109 #, c-format msgid "fsxattr.projid = %u\n" msgstr "fsxattr.projid = %u\n" #: .././io/open.c:110 #, c-format msgid "fsxattr.extsize = %u\n" msgstr "fsxattr.extsize = %u\n" #: .././io/open.c:111 #, c-format msgid "fsxattr.nextents = %u\n" msgstr "fsxattr.nextents = %u\n" #: .././io/open.c:112 #, c-format msgid "fsxattr.naextents = %u\n" msgstr "fsxattr.naextents = %u\n" #: .././io/open.c:117 #, c-format msgid "dioattr.mem = 0x%x\n" msgstr "dioattr.mem = 0x%x\n" #: .././io/open.c:118 #, c-format msgid "dioattr.miniosz = %u\n" msgstr "dioattr.miniosz = %u\n" #: .././io/open.c:119 #, c-format msgid "dioattr.maxiosz = %u\n" msgstr "dioattr.maxiosz = %u\n" #: .././io/open.c:243 #, c-format msgid "" "\n" " opens a new file in the requested mode\n" "\n" " Example:\n" " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n" "\n" " Opens a file for subsequent use by all of the other xfs_io commands.\n" " With no arguments, open uses the stat command to show the current file.\n" " -F -- foreign filesystem file, disallow XFS-specific commands\n" " -a -- open with the O_APPEND flag (append-only mode)\n" " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n" " -f -- open with O_CREAT (create the file if it doesn't exist)\n" " -m -- permissions to use in case a new file is created (default 0600)\n" " -n -- open with O_NONBLOCK\n" " -r -- open with O_RDONLY, the default is O_RDWR\n" " -s -- open with O_SYNC\n" " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n" " -R -- mark the file as a realtime XFS file immediately after opening it\n" " Note1: usually read/write direct IO requests must be blocksize aligned;\n" " some kernels, however, allow sectorsize alignment for direct IO.\n" " Note2: the bmap for non-regular files can be obtained provided the file\n" " was opened correctly (in particular, must be opened read-only).\n" "\n" msgstr "" "\n" " öffnet eine Datei in der angeforderten Weise\n" "\n" " Beispiel:\n" " »open -cd /tmp/data« - erstellt/öffnet Datei zum Lesen/Schreiben für\n" " direkte IO\n" "\n" " Öffnet eine Datei zum anschließenden Gebrauch durch alle anderen\n" " XFS-Befehle\n" " Ohne Argumente benutzt »Öffnen« den »stat«-Befehl um die aktuelle Datei\n" " anzuzeigen.\n" " -F -- Datei eines fremden Dateisystems, erlaube keine XFS-spezifischen\n" " Befehle\n" " -a -- öffne mit der O_APPEND-Markierung (Nur-anhängen-Modus)\n" " -d -- öffne mit O_DIRECT (nicht gepufferte IO, vermerkt\n" " Ausrichtungsbeschränkungen)\n" " -f -- öffne mit O_CREAT (erstellt die Datei, wenn es sie nicht gibt)\n" " -m -- Rechte, die bei der Erstellung neuer Dateien gesetzt werden\n" " (Vorgabe 0600)\n" " -n -- öffne mit O_NONBLOCK\n" " -r -- öffne mit O_RDONLY, Vorgabe ist O_RDWR\n" " -s -- öffne mit O_SYNC\n" " -t -- öffne mit O_TRUNC (Datei auf die Länge Null kürzen, wenn es sie gibt\n" " -R -- Datei direkt nach dem Öffnen als Echtzeit-XFS-Datei markieren.\n" " Anmerkung1: Direkte Lese-/Schreib-IO-Abfragen müssen üblicherweise an der\n" " Blockgröße ausgerichtet werden. Einige Kernel erlauben jedoch\n" " Ausrichtung an der Sektorgröße für direktes IO.\n" " Anmerkung2: Das »bmap« für irreguläre Dateien kann bereitgestellt werden,\n" " statt der Datei die passend geöffnet wurde (im Einzelnen darf\n" " sie Nur-Lesend geöffnet werden)\n" "\n" #: .././io/open.c:380 #, c-format msgid "" "\n" " displays the project identifier associated with the current path\n" "\n" " Options:\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, but only list projects on directories\n" "\n" msgstr "" "\n" " zeigt die Projektkennung, die mit dem derzeitigen Pfad verbunden wird\n" "\n" " Optionen:\n" " -R -- rekursiv absteigend (nützlich, wenn die aktuelle Datei ein\n" " Verzeichnis ist)\n" " -D -- rekursiv absteigend, aber nur die Attribute von Verzeichnissen\n" " auflisten\n" "\n" #: .././io/open.c:446 #, c-format msgid "projid = %u\n" msgstr "projid = %u\n" #: .././io/open.c:454 #, c-format msgid "" "\n" " modifies the project identifier associated with the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying projects on directories\n" "\n" msgstr "" "\n" " zeigt die Projektkennung, die mit dem derzeitigen Pfad verbunden wird\n" "\n" " -R -- rekursiv absteigend (nützlich, wenn die aktuelle Datei ein\n" " Verzeichnis ist)\n" " -D -- rekursiv absteigend, aber nur die Attribute von Verzeichnissen\n" " auflisten\n" "\n" #: .././io/open.c:513 #, c-format msgid "invalid project ID -- %s\n" msgstr "Falsche Projekt-ID -- %s\n" #: .././io/open.c:529 #, c-format msgid "" "\n" " report or modify preferred extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying extsize on directories\n" "\n" msgstr "" "\n" " zeigt oder ändert die vorgesehene Größe des Extents (in Bytes) des\n" " aktuellen Verzeichnisses\n" "\n" " -R -- rekursiv absteigend (nützlich, wenn der aktuelle Pfad ein\n" " Verzeichnis ist)\n" " -D -- rekursiv absteigend, nur die »extsize« von Verzeichnissen ändern\n" "\n" #: .././io/open.c:572 #, c-format msgid "invalid target file type - file %s\n" msgstr "ungültiger Ziel-Dateityp - Datei %s\n" #: .././io/open.c:658 #, c-format msgid "non-numeric extsize argument -- %s\n" msgstr "nicht-numerisches »extsize«-Argument -- %s\n" #: .././io/open.c:705 #, c-format msgid "invalid setfl argument -- '%c'\n" msgstr "ungültiges »setfl«-Argument -- »%c«\n" #: .././io/open.c:729 #, c-format msgid "statfs.f_bsize = %lld\n" msgstr "statfs.f_bsize = %lld\n" #: .././io/open.c:730 #, c-format msgid "statfs.f_blocks = %lld\n" msgstr "statfs.f_blocks = %lld\n" #: .././io/open.c:732 #, c-format msgid "statfs.f_frsize = %lld\n" msgstr "statfs.f_frsize = %lld\n" #: .././io/open.c:734 #, c-format msgid "statfs.f_bavail = %lld\n" msgstr "statfs.f_bavail = %lld\n" #: .././io/open.c:736 #, c-format msgid "statfs.f_files = %lld\n" msgstr "statfs.f_files = %lld\n" #: .././io/open.c:737 #, c-format msgid "statfs.f_ffree = %lld\n" msgstr "statfs.f_ffree = %lld\n" #: .././io/open.c:744 #, c-format msgid "geom.bsize = %u\n" msgstr "geom.bsize = %u\n" #: .././io/open.c:745 #, c-format msgid "geom.agcount = %u\n" msgstr "geom.agcount = %u\n" #: .././io/open.c:746 #, c-format msgid "geom.agblocks = %u\n" msgstr "geom.agblocks = %u\n" #: .././io/open.c:747 #, c-format msgid "geom.datablocks = %llu\n" msgstr "geom.datablocks = %llu\n" #: .././io/open.c:749 #, c-format msgid "geom.rtblocks = %llu\n" msgstr "geom.rtblocks = %llu\n" #: .././io/open.c:751 #, c-format msgid "geom.rtextents = %llu\n" msgstr "geom.rtextents = %llu\n" #: .././io/open.c:753 #, c-format msgid "geom.rtextsize = %u\n" msgstr "geom.rtextsize = %u\n" #: .././io/open.c:754 #, c-format msgid "geom.sunit = %u\n" msgstr "geom.sunit = %u\n" #: .././io/open.c:755 #, c-format msgid "geom.swidth = %u\n" msgstr "geom.swidth = %u\n" #: .././io/open.c:760 #, c-format msgid "counts.freedata = %llu\n" msgstr "counts.freedata = %llu\n" #: .././io/open.c:762 #, c-format msgid "counts.freertx = %llu\n" msgstr "counts.freertx = %llu\n" #: .././io/open.c:764 #, c-format msgid "counts.freeino = %llu\n" msgstr "counts.freeino = %llu\n" #: .././io/open.c:766 #, c-format msgid "counts.allocino = %llu\n" msgstr "counts.allocino = %llu\n" #: .././io/open.c:775 msgid "open" msgstr "öffnen" #: .././io/open.c:776 msgid "o" msgstr "o" #: .././io/open.c:781 msgid "[-acdrstx] [path]" msgstr "[-acdrstx] [Pfad]" #: .././io/open.c:782 msgid "open the file specified by path" msgstr "öffne die Datei, die durch den Pfad gegeben ist" #: .././io/open.c:785 msgid "stat" msgstr "stat" #: .././io/open.c:790 msgid "[-v]" msgstr "[-v]" #: .././io/open.c:791 msgid "statistics on the currently open file" msgstr "Statistiken über die derzeit geöffnete Datei" #: .././io/open.c:793 msgid "close" msgstr "schließen" #: .././io/open.c:794 msgid "c" msgstr "c" #: .././io/open.c:799 msgid "close the current open file" msgstr "die derzeit offene Datei schließen" #: .././io/open.c:801 msgid "setfl" msgstr "setfl" #: .././io/open.c:803 msgid "[-adx]" msgstr "[-adx]" #: .././io/open.c:806 msgid "set/clear append/direct flags on the open file" msgstr "setzen-/löschen- anhängen-/direkt-Markierungen auf die offene Datei" #: .././io/open.c:808 msgid "statfs" msgstr "statfs" #: .././io/open.c:812 msgid "statistics on the filesystem of the currently open file" msgstr "Statistiken über das Dateisystem der derzeit offenen Datei" #: .././io/open.c:814 msgid "chproj" msgstr "chproj" #: .././io/open.c:816 msgid "[-D | -R] projid" msgstr "[-D | -R] projid" #: .././io/open.c:821 msgid "change project identifier on the currently open file" msgstr "ändert Projekt-Kennzeichnung der derzeit offenen Datei" #: .././io/open.c:824 msgid "lsproj" msgstr "lsproj" #: .././io/open.c:826 msgid "[-D | -R]" msgstr "[-D | -R]" #: .././io/open.c:831 msgid "list project identifier set on the currently open file" msgstr "" "zeigt die für die derzeit offene Datei gesetzten Projekt-Kennzeichnungen" #: .././io/open.c:834 msgid "extsize" msgstr "extsize" #: .././io/open.c:836 msgid "[-D | -R] [extsize]" msgstr "[-D | -R] [extsize]" #: .././io/open.c:841 msgid "get/set preferred extent size (in bytes) for the open file" msgstr "gib/setze bevorzugte Extent-Größe (in Bytes) für die offene Datei" #: .././io/parent.c:49 #, c-format msgid "%s%s" msgstr "%s%s" #: .././io/parent.c:54 #, c-format msgid "inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n" msgstr "Inode-Pfad für Inode: %llu ist falsch - Pfad »%s« gibt es nicht\n" #: .././io/parent.c:58 #, c-format msgid "path \"%s\" does not stat for inode: %llu; err = %s\n" msgstr "Pfad »%s« enthält keinen Status für Inode: %llu; err = %s\n" #: .././io/parent.c:67 #, c-format msgid "path \"%s\" found\n" msgstr "Pfad »%s« nicht gefunden\n" #: .././io/parent.c:73 #, c-format msgid "inode-path for inode: %llu is incorrect - wrong inode#\n" msgstr "Inode-Pfad für Inode: %llu ist falsch - falscher Inode#\n" #: .././io/parent.c:77 .././io/parent.c:107 #, c-format msgid "ino mismatch for path \"%s\" %llu vs %llu\n" msgstr "ino für Pfad »%s« stimmt nicht überein %llu gegen %llu\n" #: .././io/parent.c:85 #, c-format msgid "inode number match: %llu\n" msgstr "Inode-Nummer stimmt überein: %llu\n" #: .././io/parent.c:95 #, c-format msgid "parent path \"%s\" does not stat: %s\n" msgstr "Elternpfad »%s« enthält keinen Status: %s\n" #: .././io/parent.c:103 #, c-format msgid "inode-path for inode: %llu is incorrect - wrong parent inode#\n" msgstr "Inode-Pfad für Inode: %llu ist falsch - falscher Eltern-Inode#\n" #: .././io/parent.c:116 #, c-format msgid "parent ino match for %llu\n" msgstr "Eltern-»ino« stimmt überein für %llu\n" #: .././io/parent.c:137 #, c-format msgid "parentpaths failed for ino %llu: %s\n" msgstr "»parentpaths« fehlgeschlagen für »ino« %llu: %s\n" #: .././io/parent.c:148 #, c-format msgid "inode-path for inode: %llu is missing\n" msgstr "Inode-Pfad für Inode: %llu fehlt\n" #: .././io/parent.c:171 #, c-format msgid "can't stat mount point \"%s\": %s\n" msgstr "Status für Einhängepunkt »%s« kann nicht abgefragt werden: %s\n" #: .././io/parent.c:192 #, c-format msgid "failed to get bulkstat information for inode %llu\n" msgstr "Bulkstat-Information für Inode %llu zu bekommen ist fehlgeschlagen\n" #: .././io/parent.c:198 #, c-format msgid "failed to get valid bulkstat information for inode %llu\n" msgstr "" "gültige Bulkstat-Information für Inode %llu zu bekommen ist\n" "fehlgeschlagen\n" #: .././io/parent.c:210 #, c-format msgid "checking inode %llu\n" msgstr "Inode %llu wird geprüft\n" #: .././io/parent.c:224 #, c-format msgid "syssgi bulkstat failed: %s\n" msgstr "syssgi bulkstat fehlgeschlagen:%s\n" #: .././io/parent.c:246 #, c-format msgid "unable to open \"%s\" for jdm: %s\n" msgstr "außerstande »%s« für jdm zu öffnen: %s\n" #: .././io/parent.c:256 #, c-format msgid "unable to allocate buffers: %s\n" msgstr "außerstande Puffer zu allozieren: %s\n" #: .././io/parent.c:265 #, c-format msgid "num errors: %d\n" msgstr "»num«-Fehler: %d\n" #: .././io/parent.c:267 #, c-format msgid "succeeded checking %llu inodes\n" msgstr "Prüfung von %llu Inodes erfolgreich\n" #: .././io/parent.c:277 #, c-format msgid "p_ino = %llu\n" msgstr "p_ino = %llu\n" #: .././io/parent.c:278 #, c-format msgid "p_gen = %u\n" msgstr "p_gen = %u\n" #: .././io/parent.c:279 #, c-format msgid "p_reclen = %u\n" msgstr "p_reclen = %u\n" #: .././io/parent.c:281 #, c-format msgid "p_name = \"%s%s\"\n" msgstr "p_name = »%s%s«\n" #: .././io/parent.c:283 #, c-format msgid "p_name = \"%s\"\n" msgstr "p_name = »%s«\n" #: .././io/parent.c:305 #, c-format msgid "%s: failed path_to_fshandle \"%s\": %s\n" msgstr "%s: path_to_fshandle »%s« fehlgeschlagen: %s\n" #: .././io/parent.c:312 #, c-format msgid "%s: path_to_handle failed for \"%s\"\n" msgstr "%s: path_to_handle fehlgeschlagen für»%s«\n" #: .././io/parent.c:319 #, c-format msgid "%s: unable to allocate parent buffer: %s\n" msgstr "%s: außerstande Eltern-Puffer zu allozieren: %s\n" #: .././io/parent.c:340 #, c-format msgid "%s: %s call failed for \"%s\": %s\n" msgstr "%s: %s-Aufruf fehlgeschlagen für »%s«: %s\n" #: .././io/parent.c:349 #, c-format msgid "%s: inode-path is missing\n" msgstr "%s: Inode-Pfad fehlt\n" #: .././io/parent.c:380 #, c-format msgid "file argument, \"%s\", is not in a mounted XFS filesystem\n" msgstr "Datei-Argument »%s« ist nicht in einem eingehängten XFS-Dateisystem\n" #: .././io/parent.c:420 #, c-format msgid "" "\n" " list the current file's parents and their filenames\n" "\n" " -c -- check the current file's file system for parent consistency\n" " -p -- list the current file's parents and their full paths\n" " -v -- verbose mode\n" "\n" msgstr "" "\n" " liste die Eltern der derzeitigen Datei und ihre Dateinamen auf\n" "\n" " -c -- prüfe das Dateisystem der derzeitigen Datei auf Vollständigkeit der\n" " Eltern\n" " -p -- liste die Eltern der derzeitigen Datei und ihre vollständigen\n" " Dateinamen auf\n" " -v -- detaillierte Ausgabe\n" "\n" #: .././io/parent.c:432 msgid "parent" msgstr "Eltern" #: .././io/parent.c:436 msgid "[-cpv]" msgstr "[-cpv]" #: .././io/parent.c:438 msgid "print or check parent inodes" msgstr "Eltern-Inodes ausgeben oder prüfen" #: .././libxcmd/command.c:85 #, c-format msgid "bad argument count %d to %s, expected at least %d arguments\n" msgstr "falsche Argument-Anzahl %d für %s, mindestens %d Argumente erwartet\n" #: .././libxcmd/command.c:89 #, c-format msgid "bad argument count %d to %s, expected %d arguments\n" msgstr "falsche Argument-Anzahl %d für %s, %d Argumente erwartet\n" #: .././libxcmd/command.c:93 #, c-format msgid "bad argument count %d to %s, expected between %d and %d arguments\n" msgstr "" "falsche Argument-Anzahl %d für %s, zwischen %d und %d Argumente erwartet\n" #: .././libxcmd/command.c:155 #, c-format msgid "cannot strdup command '%s': %s\n" msgstr "strdup-Befehl »%s« konnte nicht ausgeführt werden: %s\n" #: .././libxcmd/command.c:171 .././libxcmd/command.c:189 #, c-format msgid "command \"%s\" not found\n" msgstr "Befehl »%s« nicht gefunden\n" #: .././libxcmd/help.c:86 msgid "help" msgstr "Hilfe" #: .././libxcmd/help.c:87 msgid "?" msgstr "?" #: .././libxcmd/quit.c:36 msgid "quit" msgstr "beenden" #: .././libxcmd/quit.c:37 msgid "q" msgstr "q" #: .././libxcmd/quit.c:42 msgid "exit the program" msgstr "das Programm beenden" #: .././libxcmd/paths.c:77 #, c-format msgid "%s: warning - out of memory\n" msgstr "%s: Warnung - außerhalb des Speichers\n" #: .././libxcmd/paths.c:85 #, c-format msgid "%s: warning - cannot find %s: %s\n" msgstr "%s: Warnung - %s kann nicht gefunden werden: %s\n" #: .././libxcmd/paths.c:251 #, c-format msgid "%s: getmntinfo() failed: %s\n" msgstr "%s: getmntinfo() fehlgeschlagen: %s\n" #: .././libxcmd/paths.c:331 #, c-format msgid "%s: cannot find mount point for path `%s': %s\n" msgstr "%s: Einhängepunkt für Pfad »%s« kann nicht gefunden werden: %s\n" #: .././libxcmd/paths.c:367 #, c-format msgid "%s: cannot initialise path table: %s\n" msgstr "%s: Pfad-Tabelle kann nicht initialisiert werden: %s\n" #: .././libxcmd/paths.c:382 #, c-format msgid "%s: cannot setup path for mount %s: %s\n" msgstr "%s: Pfad zum Einhängen von %s kann nicht eingerichtet werden: %s\n" #: .././libxcmd/paths.c:395 #, c-format msgid "%s: no mount table yet, so no projects\n" msgstr "%s: noch keine Einhänge-Tabelle, deshalb keine Projekte\n" #: .././libxcmd/paths.c:402 #, c-format msgid "%s: cannot setup path for project %s: %s\n" msgstr "%s: der Pfad für Projekt %s kann nicht eingerichtet werden: %s\n" #: .././libxcmd/paths.c:433 #, c-format msgid "%s: cannot setup path for project dir %s: %s\n" msgstr "" "%s: der Pfad für Projektverzeichnis %s kann nicht eingerichtet werden: %s\n" #: .././libxfs/darwin.c:41 #, c-format msgid "%s: error opening the device special file \"%s\": %s\n" msgstr "%s: Fehler beim Öffnen der gerätspezifischen Datei »%s«: %s\n" #: .././libxfs/darwin.c:48 #, c-format msgid "%s: can't tell if \"%s\" is writable: %s\n" msgstr "%s: ob Datei %s schreibbar ist, kann nicht gesagt werden: %s\n" #: .././libxfs/darwin.c:76 .././libxfs/freebsd.c:116 .././libxfs/irix.c:58 #: .././libxfs/linux.c:138 #, c-format msgid "%s: cannot stat the device file \"%s\": %s\n" msgstr "%s: kann Status für Gerätedatei »%s« nicht abfragen: %s\n" #: .././libxfs/darwin.c:86 #, c-format msgid "%s: can't determine device size: %s\n" msgstr "%s: Gerätgröße kann nicht bestimmt werden: %s\n" #: .././libxfs/darwin.c:139 .././libxfs/freebsd.c:198 .././libxfs/irix.c:106 #: .././libxfs/linux.c:216 #, c-format msgid "%s: can't determine memory size\n" msgstr "%s: Speichergröße kann nicht bestimmt werden\n" #: .././libxfs/freebsd.c:49 #, c-format msgid "%s: %s possibly contains a mounted filesystem\n" msgstr "%s: %s enthält möglicherweise ein eingehängtes Dateisystem\n" #: .././libxfs/freebsd.c:60 .././libxfs/linux.c:67 #, c-format msgid "%s: %s contains a mounted filesystem\n" msgstr "%s: %s enthält ein eingehängtes Dateisystem\n" #: .././libxfs/freebsd.c:75 .././libxfs/linux.c:85 #, c-format msgid "%s: %s contains a possibly writable, mounted filesystem\n" msgstr "" "%s: %s enthält ein möglicherweise beschreibbares eingehängtes Dateisystem\n" #: .././libxfs/freebsd.c:89 .././libxfs/linux.c:99 #, c-format msgid "%s: %s contains a mounted and writable filesystem\n" msgstr "%s: %s enthält ein eingehängtes und beschreibbares Dateisystem\n" #: .././libxfs/freebsd.c:129 #, c-format msgid "%s: Not a device or file: \"%s\"n" msgstr "%s: Kein Gerät oder Datei: »%s«n" #: .././libxfs/freebsd.c:136 #, c-format msgid "%s: DIOCGMEDIASIZE failed on \"%s\": %s\n" msgstr "%s: DIOCGMEDIASIZE fehlgeschlagen in »%s«: %s\n" #: .././libxfs/freebsd.c:143 #, c-format msgid "%s: DIOCGSECTORSIZE failed on \"%s\": %s\n" msgstr "%s: DIOCGSECTORSIZE fehlgeschlagen in »%s«: %s\n" #: .././libxfs/rdwr.c:40 #, c-format msgid "%s: %s can't memalign %d bytes: %s\n" msgstr "%s: %s konnte nicht memalign %d Bytes: %s\n" #: .././libxfs/rdwr.c:50 #, c-format msgid "%s: %s seek to offset %llu failed: %s\n" msgstr "%s: %s auf Versatz %llu zu positionieren fehlgeschlagen: %s\n" #: .././libxfs/rdwr.c:60 #, c-format msgid "%s: %s write failed: %s\n" msgstr "%s: %s schreiben fehlgeschlagen: %s\n" #: .././libxfs/rdwr.c:64 #, c-format msgid "%s: %s not progressing?\n" msgstr "%s: %s nicht durchführen?\n" #: .././libxfs/rdwr.c:319 #, c-format msgid "%s: %s can't memalign %u bytes: %s\n" msgstr "%s: %s konnte nicht memalign %u Bytes: %s\n" #: .././libxfs/rdwr.c:459 #, c-format msgid "%s: read failed: %s\n" msgstr "%s: lesen fehlgeschlagen: %s\n" #: .././libxfs/rdwr.c:502 #, c-format msgid "%s: pwrite failed: %s\n" msgstr "%s: pwrite fehlgeschlagen: %s\n" #: .././libxfs/rdwr.c:509 #, c-format msgid "%s: error - wrote only %d of %d bytes\n" msgstr "%s: Fehler - nur %d von %d Bytes wurden geschrieben\n" #: .././libxfs/trans.c:33 #, c-format msgid "%s: xact calloc failed (%d bytes): %s\n" msgstr "%s: xact calloc fehlgeschlagen (%d Bytes): %s\n" #: .././libxfs/trans.c:597 #, c-format msgid "%s: warning - itobp failed (%d)\n" msgstr "%s: Warnung - itobp fehlgeschlagen (%d)\n" #: .././libxfs/trans.c:605 #, c-format msgid "%s: warning - iflush_int failed (%d)\n" msgstr "%s: Warnung - iflush_int fehlgeschlagen (%d)\n" #: .././libxfs/trans.c:684 .././libxfs/trans.c:790 #, c-format msgid "%s: unrecognised log item type\n" msgstr "%s: nicht erkannter Protokoll-Element-Typ\n" #: .././libxfs/util.c:697 #, c-format msgid "%s: cannot reserve space: %s\n" msgstr "%s: Speicher konnte nicht reserviert werden: %s\n" #: .././libxfs/kmem.c:15 #, c-format msgid "%s: zone init failed (%s, %d bytes): %s\n" msgstr "%s: Zoneninitialisierung fehlgeschlagen (%s, %d Bytes): %s\n" #: .././libxfs/kmem.c:32 #, c-format msgid "%s: zone alloc failed (%s, %d bytes): %s\n" msgstr "%s: zuweisen von Zone fehlgeschlagen(%s, %d Bytes): %s\n" #: .././libxfs/kmem.c:56 #, c-format msgid "%s: malloc failed (%d bytes): %s\n" msgstr "%s: malloc fehlgeschlagen (%d Bytes): %s\n" #: .././libxfs/kmem.c:77 #, c-format msgid "%s: realloc failed (%d bytes): %s\n" msgstr "%s: realloc fehlgeschlagen (%d Bytes): %s\n" #: .././libxfs/linux.c:114 #, c-format msgid "%s: %s - cannot set blocksize on block device %s: %s\n" msgstr "" "%s: %s - Blockgröße auf blockorientiertem Gerät %s kann nicht gesetzt\n" "werden: %s\n" #: .././libxfs/linux.c:161 #, c-format msgid "%s: can't determine device size\n" msgstr "%s: Größe des Gerätes kann nicht bestimmt werden\n" #: .././libxfs/linux.c:169 #, c-format msgid "%s: warning - cannot get sector size from block device %s: %s\n" msgstr "" "%s: Warnung - Sektorgröße des blockorientierten Gerätes %s kann nicht\n" "erlangt werden: %s\n" #: .././libxfs/init.c:80 .././libxfs/init.c:179 #, c-format msgid "%s: %s: device %lld is not open\n" msgstr "%s: %s: Gerät %lld ist nicht geöffnet\n" #: .././libxfs/init.c:116 #, c-format msgid "%s: cannot stat %s: %s\n" msgstr "%s: kann Status für »%s« nicht abfragen: %s\n" #: .././libxfs/init.c:141 #, c-format msgid "%s: device %lld is already open\n" msgstr "%s: Gerät %lld ist bereits geöffnet\n" #: .././libxfs/init.c:154 #, c-format msgid "%s: %s: too many open devices\n" msgstr "%s: %s: zu viele offene Geräte\n" #: .././libxfs/init.c:197 #, c-format msgid "%s: can't find a character device matching %s\n" msgstr "%s: zeichenorientiertes Gerät, das auf %s passt wird nicht gefunden\n" #: .././libxfs/init.c:203 #, c-format msgid "%s: can't find a block device matching %s\n" msgstr "%s: blockorientiertes Gerät, das auf %s passt wird nicht gefunden\n" #: .././libxfs/init.c:318 #, c-format msgid "%s: can't get size for data subvolume\n" msgstr "%s: Größe des Daten des Unterdatenträgers kann nicht erlangt werden\n" #: .././libxfs/init.c:323 #, c-format msgid "%s: can't get size for log subvolume\n" msgstr "" "%s: Größe des Protokolls für Unterdatenträger kann nicht erlangt werden\n" #: .././libxfs/init.c:328 #, c-format msgid "%s: can't get size for realtime subvolume\n" msgstr "%s: Größe des Echtzeit-Unterdatenträgers kann nicht erlangt werden\n" #: .././libxfs/init.c:424 #, c-format msgid "%s: cannot read realtime bitmap inode (%d)\n" msgstr "%s: Echtzeit-Bitmap-Inode (%d) kann nicht gelesen werden\n" #: .././libxfs/init.c:434 #, c-format msgid "%s: cannot read realtime summary inode (%d)\n" msgstr "%s: Echtzeit-Zusammenfassungs-Inode (%d) kann nicht gelesen werden\n" #: .././libxfs/init.c:458 #, c-format msgid "%s: filesystem has a realtime subvolume\n" msgstr "%s: Dateisystem hat einen Echtzeit-Unterdatenträger\n" #: .././libxfs/init.c:480 #, c-format msgid "%s: realtime init - %llu != %llu\n" msgstr "%s: Echtzeitinitialisierung - %llu != %llu\n" #: .././libxfs/init.c:488 #, c-format msgid "%s: realtime size check failed\n" msgstr "%s: Prüfen der Echtzeit-Größe fehlgeschlagen\n" #: .././libxfs/init.c:590 #, c-format msgid "%s: size check failed\n" msgstr "%s: Prüfen der Größe fehlgeschlagen\n" #: .././libxfs/init.c:599 #, c-format msgid "%s: WARNING - filesystem uses v1 dirs,limited functionality provided.\n" msgstr "" "%s: WARNUNG - Dateisystem benutzt v1 dirs, begrenzte Funktionalität\n" "bereitgestellt.\n" #: .././libxfs/init.c:619 #, c-format msgid "%s: data size check failed\n" msgstr "%s: Prüfen der Datengröße fehlgeschlagen\n" #: .././libxfs/init.c:632 #, c-format msgid "%s: log size checks failed\n" msgstr "%s: Prüfen der Protokollgröße fehlgeschlagen\n" #: .././libxfs/init.c:643 #, c-format msgid "%s: realtime device init failed\n" msgstr "%s: Initialisieren von Echtzeitgerät fehlgeschlagen\n" #: .././libxfs/init.c:651 #, c-format msgid "%s: failed to alloc %ld bytes: %s\n" msgstr "%s: Zuweisen von %ld Bytes fehlgeschlagen: %s\n" #: .././libxfs/init.c:665 #, c-format msgid "%s: cannot read root inode (%d)\n" msgstr "%s: Wurzel-Inode (%d) kann nicht gelesen werden\n" #: .././libxfs/init.c:685 #, c-format msgid "%s: cannot init perag data (%d)\n" msgstr "%s: perag-Daten (%d) konnten nicht initialisiert werden\n" #: .././libxlog/util.c:37 #, c-format msgid "" "* ERROR: mismatched uuid in log\n" "* SB : %s\n" "* log: %s\n" msgstr "" "* FEHLER: uuid stimmt im Protokoll nicht überein\n" "* SB : %s\n" "* Protokoll : %s\n" #: .././libxlog/util.c:50 #, c-format msgid "" "\n" "LOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n" msgstr "" "\n" "LOG REC AT LSN Zyklus %d Block %d (0x%x, 0x%x)\n" #: .././libxlog/util.c:58 #, c-format msgid "* ERROR: bad magic number in log header: 0x%x\n" msgstr "* FEHLER: falsche Magische Zahl in Protokoll-Kopf: 0x%x\n" #: .././libxlog/util.c:67 #, c-format msgid "* ERROR: log format incompatible (log=%d, ours=%d)\n" msgstr "* FEHLER: Protokollformat inkompatibel (Protokoll=%d, ours=%d)\n" #: .././libxlog/util.c:77 .././libxlog/util.c:89 msgid "Bad log" msgstr "Falsches Protokoll" #: .././logprint/log_copy.c:44 .././logprint/log_dump.c:43 #, c-format msgid "%s: read error (%lld): %s\n" msgstr "%s: Lesefehler (%lld): %s\n" #: .././logprint/log_copy.c:49 .././logprint/log_dump.c:48 #, c-format msgid "%s: physical end of log at %lld\n" msgstr "%s: physisches Ende des Protokolls bei %lld\n" #: .././logprint/log_copy.c:53 #, c-format msgid "%s: short read? (%lld)\n" msgstr "%s: kurzes Lesen? (%lld)\n" #: .././logprint/log_copy.c:60 #, c-format msgid "%s: write error (%lld): %s\n" msgstr "%s: Schreibfehler (%lld): %s\n" #: .././logprint/log_copy.c:65 #, c-format msgid "%s: short write? (%lld)\n" msgstr "%s: kurzes Schreiben? (%lld)\n" #: .././logprint/log_dump.c:56 #, c-format msgid "%6lld HEADER Cycle %d tail %d:%06d len %6d ops %d\n" msgstr "%6lld HEADER Zyklus %d Ende %d:%06d Länge %6d ops %d\n" #: .././logprint/log_dump.c:67 #, c-format msgid "[%05lld - %05lld] Cycle 0x%08x New Cycle 0x%08x\n" msgstr "[%05lld - %05lld] Zyklus 0x%08x Neuer Zyklus 0x%08x\n" #: .././logprint/log_misc.c:131 #, c-format msgid "Oper (%d): tid: %x len: %d clientid: %s " msgstr "Oper (%d): tid: %x len: %d clientid: %s " #: .././logprint/log_misc.c:136 #, c-format msgid "flags: " msgstr "Markierungen: " #: .././logprint/log_misc.c:230 #, c-format msgid " Not enough data to decode further\n" msgstr " Nicht genug Daten, um weiter zu entschlüsseln\n" #: .././logprint/log_misc.c:234 #, c-format msgid " type: %s tid: %x num_items: %d\n" msgstr " Typ: %s tid: %x num_items: %d\n" #: .././logprint/log_misc.c:276 #, c-format msgid "" "#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d flags: 0x%x\n" msgstr "" "#regs: %d Start-blkno: %lld (0x%llx) Länge: %d bmap Größe: %d " "Markierungen: 0x%x\n" #: .././logprint/log_misc.c:282 #, c-format msgid "#regs: %d Not printing rest of data\n" msgstr "#regs: %d Rest der Daten wird nicht ausgegeben\n" #: .././logprint/log_misc.c:299 #, c-format msgid "SUPER BLOCK Buffer: " msgstr "SUPER-BLOCK-Puffer: " #: .././logprint/log_misc.c:301 .././logprint/log_misc.c:363 #: .././logprint/log_misc.c:389 #, c-format msgid "Out of space\n" msgstr "Außerhalb des Raums\n" #: .././logprint/log_misc.c:309 #, c-format msgid "icount: %lld ifree: %lld " msgstr "icount: %lld ifree: %lld " #: .././logprint/log_misc.c:313 #, c-format msgid "fdblks: %lld frext: %lld\n" msgstr "fdblks: %lld frext: %lld\n" #: .././logprint/log_misc.c:319 #, c-format msgid "AGI Buffer: XAGI " msgstr "AGI Buffer: XAGI " #: .././logprint/log_misc.c:322 #, c-format msgid "out of space\n" msgstr "Außerhalb des Raums\n" #: .././logprint/log_misc.c:325 #, c-format msgid "ver: %d " msgstr "ver: %d " #: .././logprint/log_misc.c:327 #, c-format msgid "seq#: %d len: %d cnt: %d root: %d\n" msgstr "seq#: %d Länge: %d cnt: %d Wurzel: %d\n" #: .././logprint/log_misc.c:332 #, c-format msgid "level: %d free#: 0x%x newino: 0x%x\n" msgstr "Stufe: %d free#: 0x%x newino: 0x%x\n" #: .././logprint/log_misc.c:342 #, c-format msgid "AGI unlinked data skipped " msgstr "AGI-Verweis gelöst, Daten übersprungen" #: .././logprint/log_misc.c:343 #, c-format msgid "(CONTINUE set, no space)\n" msgstr "(FORTFAHREN gesetzt, kein Raum)\n" #: .././logprint/log_misc.c:349 #, c-format msgid "bucket[%d - %d]: " msgstr "bucket[%d - %d]: " #: .././logprint/log_misc.c:361 #, c-format msgid "AGF Buffer: XAGF " msgstr "AGF Puffer: XAGF " #: .././logprint/log_misc.c:366 #, c-format msgid "ver: %d seq#: %d len: %d \n" msgstr "ver: %d seq#: %d Länge: %d \n" #: .././logprint/log_misc.c:370 #, c-format msgid "root BNO: %d CNT: %d\n" msgstr "Wurzel BNO: %d CNT: %d\n" #: .././logprint/log_misc.c:373 #, c-format msgid "level BNO: %d CNT: %d\n" msgstr "Stufe BNO: %d CNT: %d\n" #: .././logprint/log_misc.c:376 #, c-format msgid "1st: %d last: %d cnt: %d freeblks: %d longest: %d\n" msgstr "1.: %d letzter: %d cnt: %d freeblks: %d längster: %d\n" #: .././logprint/log_misc.c:386 #, c-format msgid "DQUOT Buffer: DQ " msgstr "DQUOT Puffer: DQ " #: .././logprint/log_misc.c:393 #, c-format msgid "ver: %d flags: 0x%x id: %d \n" msgstr "ver: %d Markierungen: 0x%x id: %d \n" #: .././logprint/log_misc.c:396 #, c-format msgid "blk limits hard: %llu soft: %llu\n" msgstr "blk harte Limits: %llu weiche: %llu\n" #: .././logprint/log_misc.c:399 #, c-format msgid "blk count: %llu warns: %d timer: %d\n" msgstr "blk Anzahl: %llu Warnungen: %d Zeitnehmer: %d\n" #: .././logprint/log_misc.c:403 #, c-format msgid "ino limits hard: %llu soft: %llu\n" msgstr "ino harte Limits: %llu weiche: %llu\n" #: .././logprint/log_misc.c:406 #, c-format msgid "ino count: %llu warns: %d timer: %d\n" msgstr "ino-Anzahl: %llu Warnungen: %d Zeitnehmer: %d\n" #: .././logprint/log_misc.c:412 #, c-format msgid "BUF DATA\n" msgstr "BUF DATEN\n" #: .././logprint/log_misc.c:454 #, c-format msgid "EFD: #regs: %d num_extents: %d id: 0x%llx\n" msgstr "EFD: #regs: %d num_extents: %d id: 0x%llx\n" #: .././logprint/log_misc.c:461 #, c-format msgid "EFD: Not enough data to decode further\n" msgstr "EFD: Nicht genug Daten, um weiter zu entschlüsseln\n" #: .././logprint/log_misc.c:481 .././logprint/log_misc.c:490 #, c-format msgid "%s: xlog_print_trans_efi: malloc failed\n" msgstr "%s: xlog_print_trans_efi: malloc fehlgeschlagen\n" #: .././logprint/log_misc.c:498 #, c-format msgid "EFI: #regs: %d num_extents: %d id: 0x%llx\n" msgstr "EFI: #regs: %d num_extents: %d id: 0x%llx\n" #: .././logprint/log_misc.c:525 #, c-format msgid "QOFF: #regs: %d flags: 0x%x\n" msgstr "QOFF: #regs: %d Markierungen: 0x%x\n" #: .././logprint/log_misc.c:528 #, c-format msgid "QOFF: Not enough data to decode further\n" msgstr "QOFF: Nicht genug Daten, um weiter zu entschlüsseln\n" #: .././logprint/log_misc.c:537 #, c-format msgid "INODE CORE\n" msgstr "INODE CORE\n" #: .././logprint/log_misc.c:538 #, c-format msgid "magic 0x%hx mode 0%ho version %d format %d\n" msgstr "magischer 0x%hx Modus 0%ho Version %d Format %d\n" #: .././logprint/log_misc.c:541 #, c-format msgid "nlink %hd uid %d gid %d\n" msgstr "nlink %hd uid %d gid %d\n" #: .././logprint/log_misc.c:543 #, c-format msgid "atime 0x%x mtime 0x%x ctime 0x%x\n" msgstr "atime 0x%x mtime 0x%x ctime 0x%x\n" #: .././logprint/log_misc.c:545 #, c-format msgid "size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n" msgstr "Größe 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n" #: .././logprint/log_misc.c:548 #, c-format msgid "naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n" msgstr "naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n" #: .././logprint/log_misc.c:551 #, c-format msgid "flags 0x%x gen 0x%x\n" msgstr "Markierungen 0x%x gen 0x%x\n" #: .././logprint/log_misc.c:567 #, c-format msgid "SHORTFORM DIRECTORY size %d\n" msgstr "KURZFORM VERZEICHNIS-Größe %d\n" #: .././logprint/log_misc.c:573 #, c-format msgid "SHORTFORM DIRECTORY size %d count %d\n" msgstr "KURZFORM VERZEICHNIS-Größe %d Anzahl %d\n" #: .././logprint/log_misc.c:576 #, c-format msgid ".. ino 0x%llx\n" msgstr ".. ino 0x%llx\n" #: .././logprint/log_misc.c:584 #, c-format msgid "%s ino 0x%llx namelen %d\n" msgstr "%s ino 0x%llx namelen %d\n" #: .././logprint/log_misc.c:616 #, c-format msgid "INODE: " msgstr "INODE: " #: .././logprint/log_misc.c:617 #, c-format msgid "#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n" msgstr "#regs: %d ino: 0x%llx Markierungen: 0x%x dsize: %d\n" #: .././logprint/log_misc.c:620 #, c-format msgid " blkno: %lld len: %d boff: %d\n" msgstr " blkno: %lld Länge: %d boff: %d\n" #: .././logprint/log_misc.c:625 #, c-format msgid "INODE: #regs: %d Not printing rest of data\n" msgstr "INODE: #regs: %d Rest der Daten nicht ausgeben\n" #: .././logprint/log_misc.c:658 #, c-format msgid "EXTENTS inode data\n" msgstr "EXTENTS Inode Daten\n" #: .././logprint/log_misc.c:669 #, c-format msgid "BTREE inode data\n" msgstr "BTREE Inode Daten\n" #: .././logprint/log_misc.c:680 #, c-format msgid "LOCAL inode data\n" msgstr "LOCAL Inode Daten\n" #: .././logprint/log_misc.c:694 #, c-format msgid "EXTENTS inode attr\n" msgstr "EXTENTS Inode attr\n" #: .././logprint/log_misc.c:705 #, c-format msgid "BTREE inode attr\n" msgstr "BTREE Inode attr\n" #: .././logprint/log_misc.c:716 #, c-format msgid "LOCAL inode attr\n" msgstr "LOCAL Inode attr\n" #: .././logprint/log_misc.c:728 #, c-format msgid "DEV inode: no extra region\n" msgstr "DEV Inode: Keine Extraregion\n" #: .././logprint/log_misc.c:733 #, c-format msgid "UUID inode: no extra region\n" msgstr "UUID Inode: Keine Extraregion\n" #: .././logprint/log_misc.c:741 msgid "xlog_print_trans_inode: illegal inode type" msgstr "xlog_print_trans_inode: Illegaler Inode-Typ" #: .././logprint/log_misc.c:769 #, c-format msgid "#regs: %d id: 0x%x" msgstr "#regs: %d id: 0x%x" #: .././logprint/log_misc.c:770 #, c-format msgid " blkno: %lld len: %d boff: %d\n" msgstr " blkno: %lld Länge: %d boff: %d\n" #: .././logprint/log_misc.c:774 #, c-format msgid "DQUOT: #regs: %d Not printing rest of data\n" msgstr "DQUOT: #regs: %d Rest der Daten nicht ausgeben\n" #: .././logprint/log_misc.c:793 #, c-format msgid "DQUOT: magic 0x%hx flags 0%ho\n" msgstr "DQUOT: Magische 0x%hx Markierungen 0%ho\n" #: .././logprint/log_misc.c:821 #, c-format msgid "%s: lseek to %lld failed: %s\n" msgstr "%s: lseek auf %lld fehlgeschlagen: %s\n" #: .././logprint/log_misc.c:864 #, c-format msgid "%s: xlog_print_record: malloc failed\n" msgstr "%s: xlog_print_record: malloc fehlgeschlagen\n" #: .././logprint/log_misc.c:873 #, c-format msgid "%s: xlog_print_record: read error\n" msgstr "%s: xlog_print_record: Lesefehler\n" #: .././logprint/log_misc.c:960 #, c-format msgid "Left over region from split log item\n" msgstr "Übrige Region des geteilten Protkollelements\n" #: .././logprint/log_misc.c:1004 #, c-format msgid "Unmount filesystem\n" msgstr "Dateisystem aushängen\n" #: .././logprint/log_misc.c:1009 #, c-format msgid "%s: unknown log operation type (%x)\n" msgstr "%s: unbekannter Protokolloperationstyp (%x)\n" #: .././logprint/log_misc.c:1044 #, c-format msgid "Header 0x%x wanted 0x%x\n" msgstr "Kopfzeile 0x%x gesucht 0x%x\n" #: .././logprint/log_misc.c:1058 #, c-format msgid "cycle: %d\tversion: %d\t" msgstr "Zyklus: %d\tVersion: %d\t" #: .././logprint/log_misc.c:1064 #, c-format msgid "length of Log Record: %d\tprev offset: %d\t\tnum ops: %d\n" msgstr "Länge des Protokolldatensatzes: %d\tprev Versatz: %d\t\tnum ops: %d\n" #: .././logprint/log_misc.c:1070 .././logprint/log_misc.c:1112 #, c-format msgid "cycle num overwrites: " msgstr "Zyklus Nummer Überschreibungen: " #: .././logprint/log_misc.c:1079 #, c-format msgid "uuid: %s format: " msgstr "uuid: %s Format: " #: .././logprint/log_misc.c:1082 #, c-format msgid "unknown\n" msgstr "unbekannt\n" #: .././logprint/log_misc.c:1085 #, c-format msgid "little endian linux\n" msgstr "kleines Endian-Linux\n" #: .././logprint/log_misc.c:1088 #, c-format msgid "big endian linux\n" msgstr "großes Endian-Linux\n" #: .././logprint/log_misc.c:1091 #, c-format msgid "big endian irix\n" msgstr "großes Endian-Irix\n" #: .././logprint/log_misc.c:1097 #, c-format msgid "h_size: %d\n" msgstr "h_size: %d\n" #: .././logprint/log_misc.c:1109 #, c-format msgid "extended-header: cycle: %d\n" msgstr "extended-header: Zyklus: %d\n" #: .././logprint/log_misc.c:1125 #, c-format msgid "* ERROR: found data after zeroed blocks block=%-21lld *\n" msgstr "* FEHLER: Daten nach genullten Blöcken gefunden Block=%-21lld *\n" #: .././logprint/log_misc.c:1136 #, c-format msgid "* ERROR: header cycle=%-11d block=%-21lld *\n" msgstr "* FEHLER: Kopfzeile Zyklus=%-11d Block=%-21lld *\n" #: .././logprint/log_misc.c:1147 #, c-format msgid "* ERROR: data block=%-21lld *\n" msgstr "* FEHLER: Datenblock=%-21lld *\n" #: .././logprint/log_misc.c:1158 #, c-format msgid "" "* ERROR: for header block=%lld\n" "* not enough hdrs for data length, required num = %d, hdr num = %d\n" msgstr "" "* ERROR: Für Kopfzeilenblock=%lld\n" "* nicht genügend hdrs für Datenlänge, benötigt num = %d, hdr num = %d\n" #: .././logprint/log_misc.c:1164 msgid "Not enough headers for data length." msgstr "Nicht genügend Kopfzeilen für Datenlänge." #: .././logprint/log_misc.c:1174 #, c-format msgid "%s: xlog_print: malloc failed for ext hdrs\n" msgstr "%s: xlog_print: malloc fehlgeschlagen für ext hdrs\n" #: .././logprint/log_misc.c:1220 .././logprint/log_misc.c:1295 #: .././logprint/log_misc.c:1361 .././logprint/log_misc.c:1398 #, c-format msgid "%s: physical end of log\n" msgstr "%s: Physisches Ende des Protokolls\n" #: .././logprint/log_misc.c:1226 .././logprint/log_misc.c:1300 #: .././logprint/log_misc.c:1413 #, c-format msgid "BLKNO: %lld\n" msgstr "BLKNO: %lld\n" #: .././logprint/log_misc.c:1283 #, c-format msgid "%s: problem finding oldest LR\n" msgstr "%s: Problem, das älteste LR zu finden\n" #: .././logprint/log_misc.c:1309 #, c-format msgid "%s: after %d zeroed blocks\n" msgstr "%s: Nach %d genullten Blöcken\n" #: .././logprint/log_misc.c:1373 msgid "illegal value" msgstr "unerlaubter Wert" #: .././logprint/log_misc.c:1379 #, c-format msgid "%s: skipped %d cleared blocks in range: %lld - %lld\n" msgstr "%s: %d geleerte Blöcke übersprungen in Bereich: %lld - %lld\n" #: .././logprint/log_misc.c:1384 #, c-format msgid "%s: totally cleared log\n" msgstr "%s: Gesamtes geleertes Protokoll\n" #: .././logprint/log_misc.c:1389 #, c-format msgid "%s: skipped %d zeroed blocks in range: %lld - %lld\n" msgstr "%s: %d genullte Blöcke übersprungen in Bereich: %lld - %lld\n" #: .././logprint/log_misc.c:1394 #, c-format msgid "%s: totally zeroed log\n" msgstr "%s: Gesamtes genulltes Protokoll\n" #: .././logprint/log_misc.c:1410 msgid "xlog_find_head: bad read" msgstr "xlog_find_head: Falsch gelesen" #: .././logprint/log_misc.c:1466 #, c-format msgid "%s: logical end of log\n" msgstr "%s: Logisches Ende des Protokolls\n" #: .././logprint/log_misc.c:1558 #, c-format msgid "%s: bad size of efi format: %u; expected %u or %u; nextents = %u\n" msgstr "" "%s: Falsche Größe des efi-Formats: %u; erwartet %u oder %u; nextents = %u\n" #: .././logprint/log_print_all.c:98 #, c-format msgid "" "BUF: #regs:%d start blkno:0x%llx len:%d bmap size:%d flags:0x%x\n" msgstr "" "BUF: #regs:%d Start blkno:0x%llx Länge:%d bmap-Größe:%d " "Markierungen:0x%x\n" #: .././logprint/log_print_all.c:108 #, c-format msgid "\tSUPER Block Buffer:\n" msgstr "\tSUPER Block-Puffer:\n" #: .././logprint/log_print_all.c:111 #, c-format msgid "\t\ticount:%Ld ifree:%Ld " msgstr "\t\ticount:%Ld ifree:%Ld " #: .././logprint/log_print_all.c:114 #, c-format msgid "fdblks:%Ld frext:%Ld\n" msgstr "fdblks:%Ld frext:%Ld\n" #: .././logprint/log_print_all.c:117 #, c-format msgid "\t\tsunit:%u swidth:%u\n" msgstr "\t\tsunit:%u swidth:%u\n" #: .././logprint/log_print_all.c:122 #, c-format msgid "\tAGI Buffer: (XAGI)\n" msgstr "\tAGI-Puffer: (XAGI)\n" #: .././logprint/log_print_all.c:125 #, c-format msgid "\t\tver:%d " msgstr "\t\tver:%d " #: .././logprint/log_print_all.c:127 #, c-format msgid "seq#:%d len:%d cnt:%d root:%d\n" msgstr "seq#:%d Länge:%d cnt:%d Wurzel:%d\n" #: .././logprint/log_print_all.c:132 #, c-format msgid "\t\tlevel:%d free#:0x%x newino:0x%x\n" msgstr "\t\tStufe:%d free#:0x%x newino:0x%x\n" #: .././logprint/log_print_all.c:138 #, c-format msgid "\tAGF Buffer: (XAGF)\n" msgstr "\tAGF-Puffer: (XAGF)\n" #: .././logprint/log_print_all.c:141 #, c-format msgid "\t\tver:%d seq#:%d len:%d \n" msgstr "\t\tver:%d seq#:%d Länge:%d \n" #: .././logprint/log_print_all.c:145 #, c-format msgid "\t\troot BNO:%d CNT:%d\n" msgstr "\t\tWurzel-BNO:%d CNT:%d\n" #: .././logprint/log_print_all.c:148 #, c-format msgid "\t\tlevel BNO:%d CNT:%d\n" msgstr "\t\tStufe BNO:%d CNT:%d\n" #: .././logprint/log_print_all.c:151 #, c-format msgid "\t\t1st:%d last:%d cnt:%d freeblks:%d longest:%d\n" msgstr "\t\t1.:%d letzter:%d cnt:%d freeblks:%d längster:%d\n" #: .././logprint/log_print_all.c:160 #, c-format msgid "\tDQUOT Buffer:\n" msgstr "\tDQUOT-Puffer:\n" #: .././logprint/log_print_all.c:163 #, c-format msgid "\t\tUIDs 0x%lx-0x%lx\n" msgstr "\t\tUIDs 0x%lx-0x%lx\n" #: .././logprint/log_print_all.c:168 #, c-format msgid "\tBUF DATA\n" msgstr "\tBUF-DATEN\n" #: .././logprint/log_print_all.c:190 #, c-format msgid "\tQUOTAOFF: #regs:%d type:%s\n" msgstr "\tQUOTAOFF: #regs:%d Typ:%s\n" #: .././logprint/log_print_all.c:205 #, c-format msgid "\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n" msgstr "\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n" #: .././logprint/log_print_all.c:209 #, c-format msgid "\t\tmagic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n" msgstr "\t\tmagische 0x%x\tVersion 0x%x\tID 0x%x (%d)\t\n" #: .././logprint/log_print_all.c:214 #, c-format msgid "\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x\tino_soft 0x%x\n" msgstr "\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x\tino_soft 0x%x\n" #: .././logprint/log_print_all.c:220 #, c-format msgid "\t\tbcount 0x%x (%d) icount 0x%x (%d)\n" msgstr "\t\tbcount 0x%x (%d) icount 0x%x (%d)\n" #: .././logprint/log_print_all.c:225 #, c-format msgid "\t\tbtimer 0x%x itimer 0x%x \n" msgstr "\t\tbtimer 0x%x itimer 0x%x \n" #: .././logprint/log_print_all.c:234 #, c-format msgid "\tCORE inode:\n" msgstr "\tCORE-Inode:\n" #: .././logprint/log_print_all.c:237 #, c-format msgid "\t\tmagic:%c%c mode:0x%x ver:%d format:%d onlink:%d\n" msgstr "\t\tmagische:%c%c Modus:0x%x ver:%d Format:%d onlink:%d\n" #: .././logprint/log_print_all.c:241 #, c-format msgid "\t\tuid:%d gid:%d nlink:%d projid:%d\n" msgstr "\t\tuid:%d gid:%d nlink:%d projid:%d\n" #: .././logprint/log_print_all.c:243 #, c-format msgid "\t\tatime:%d mtime:%d ctime:%d\n" msgstr "\t\tatime:%d mtime:%d ctime:%d\n" #: .././logprint/log_print_all.c:245 #, c-format msgid "\t\tflushiter:%d\n" msgstr "\t\tflushiter:%d\n" #: .././logprint/log_print_all.c:246 #, c-format msgid "\t\tsize:0x%llx nblks:0x%llx exsize:%d nextents:%d anextents:%d\n" msgstr "\t\tsize:0x%llx nblks:0x%llx exsize:%d nextents:%d anextents:%d\n" #: .././logprint/log_print_all.c:250 #, c-format msgid "\t\tforkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x gen:%d\n" msgstr "\t\tforkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x gen:%d\n" #: .././logprint/log_print_all.c:270 #, c-format msgid "\tINODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n" msgstr "\tINODE: #regs:%d ino:0x%llx Markierungen:0x%x dsize:%d\n" #: .././logprint/log_print_all.c:285 #, c-format msgid "\t\tDATA FORK EXTENTS inode data:\n" msgstr "\t\tDATA FORK EXTENTS Inode-Daten:\n" #: .././logprint/log_print_all.c:292 #, c-format msgid "\t\tDATA FORK BTREE inode data:\n" msgstr "\t\tDATA FORK BTREE Inode-Daten:\n" #: .././logprint/log_print_all.c:299 #, c-format msgid "\t\tDATA FORK LOCAL inode data:\n" msgstr "\t\tDATA FORK LOCAL Inode-Daten:\n" #: .././logprint/log_print_all.c:306 #, c-format msgid "\t\tDEV inode: no extra region\n" msgstr "\t\tDEV-Inode: Keine Extraregion\n" #: .././logprint/log_print_all.c:310 #, c-format msgid "\t\tUUID inode: no extra region\n" msgstr "\t\tUUID-Inode: Keine Extraregion\n" #: .././logprint/log_print_all.c:325 #, c-format msgid "\t\tATTR FORK EXTENTS inode data:\n" msgstr "\t\tATTR FORK EXTENTS Inode-Daten:\n" #: .././logprint/log_print_all.c:333 #, c-format msgid "\t\tATTR FORK BTREE inode data:\n" msgstr "\t\tATTR FORK BTREE Inode-Daten:\n" #: .././logprint/log_print_all.c:341 #, c-format msgid "\t\tATTR FORK LOCAL inode data:\n" msgstr "\t\tATTR FORK LOCAL Inode-Daten:\n" #: .././logprint/log_print_all.c:366 #, c-format msgid "\tEFD: #regs: %d num_extents: %d id: 0x%llx\n" msgstr "\tEFD: #regs: %d num_extents: %d id: 0x%llx\n" #: .././logprint/log_print_all.c:390 #, c-format msgid "%s: xlog_recover_print_efi: malloc failed\n" msgstr "%s: xlog_recover_print_efi: malloc fehlgeschlagen\n" #: .././logprint/log_print_all.c:398 #, c-format msgid "\tEFI: #regs:%d num_extents:%d id:0x%llx\n" msgstr "\tEFI: #regs:%d num_extents:%d id:0x%llx\n" #: .././logprint/log_print_all.c:438 #, c-format msgid "xlog_recover_print_logitem: illegal type\n" msgstr "xlog_recover_print_logitem: Illegaler Typ\n" #: .././logprint/log_print_all.c:469 #, c-format msgid "%s: illegal type" msgstr "%s: Illegaler Typ" #: .././logprint/log_print_all.c:477 #, c-format msgid ": cnt:%d total:%d " msgstr ": cnt:%d gesamt:%d " #: .././logprint/log_print_all.c:479 #, c-format msgid "a:0x%lx len:%d " msgstr "a:0x%lx Länge:%d " #: .././logprint/log_print_trans.c:25 #, c-format msgid "TRANS: tid:0x%x type:%s #items:%d trans:0x%x q:0x%lx\n" msgstr "TRANS: tid:0x%x Typ:%s #items:%d trans:0x%x q:0x%lx\n" #: .././logprint/log_print_trans.c:51 #, c-format msgid "%s: failed to find head and tail, error: %d\n" msgstr "%s: Kopf und Ende zu finden fehlgeschlagen, Fehler: %d\n" #: .././logprint/log_print_trans.c:56 #, c-format msgid " log tail: %lld head: %lld state: %s\n" msgstr " Protokollende: %lld Kopf: %lld Status: %s\n" #: .././logprint/log_print_trans.c:62 #, c-format msgid " override tail: %d\n" msgstr " Ende überschreiben: %d\n" #: .././logprint/log_print_trans.c:72 #, c-format msgid "%s: failed in xfs_do_recovery_pass, error: %d\n" msgstr "%s: In xfs_do_recovery_pass fehlgeschlagen, Fehler: %d\n" #: .././logprint/logprint.c:42 #, c-format msgid "" "Usage: %s [options...] \n" "\n" "Options:\n" " -c\t try to continue if error found in log\n" " -C copy the log from the filesystem to filename\n" " -d\t dump the log in log-record format\n" " -f\t specified device is actually a file\n" " -l filename of external log\n" " -n\t don't try and interpret log data\n" " -o\t print buffer data in hex\n" " -s block # to start printing\n" " -v print \"overwrite\" data\n" " -t\t print out transactional view\n" "\t-b in transactional view, extract buffer info\n" "\t-i in transactional view, extract inode info\n" "\t-q in transactional view, extract quota info\n" " -D print only data; no decoding\n" " -V print version information\n" msgstr "" "Aufruf: %s [Optionen ...] \n" "\n" "Optionen:\n" " -c\t versuchen fortzufahren, wenn Fehler im Protokoll\n" " entdeckt wurde\n" " -C das Protokoll vom Dateisystem nach Dateiname kopieren\n" " -d\t Auszug des Protokolls im log-record-Format\n" " -f\t angegebenes Gerät ist derzeit eine Datei\n" " -l Dateiname des externen Protokolls\n" " -n\t Protokolldaten nicht ausprobieren und interpretieren\n" " -o\t Pufferdaten hexadezimal ausgeben\n" " -s Block #, um Ausgabe zu starten\n" " -v »overwrite«-Daten ausgeben\n" " -t\t Transaktionsansicht ausgeben\n" "\t-b in Transaktionsansicht, Pufferinformationen extrahieren\n" "\t-i in Transaktionsansicht, Inodeinformationen extrahieren\n" "\t-q in Transaktionsansicht, Quotainformationen extrahieren\n" " -D Daten nur ausgeben, nicht entschlüsseln\n" " -V Versionsinformationen ausgeben\n" #: .././logprint/logprint.c:75 #, c-format msgid " Can't open device %s: %s\n" msgstr " Gerät %s kann nicht geöffnet werden: %s\n" #: .././logprint/logprint.c:81 #, c-format msgid " read of XFS superblock failed\n" msgstr " Lesen des XFS-Superblocks fehlgeschlagen!\n" #: .././logprint/logprint.c:97 #, c-format msgid "" " external log device not specified\n" "\n" msgstr "" " externes Protokollgerät nicht angegeben\n" "\n" #: .././logprint/logprint.c:112 #, c-format msgid "Can't open file %s: %s\n" msgstr "Datei %s kann nicht geöffnet werden: %s\n" #: .././logprint/logprint.c:212 #, c-format msgid "xfs_logprint:\n" msgstr "xfs_logprint:\n" #: .././logprint/logprint.c:220 #, c-format msgid " data device: 0x%llx\n" msgstr " Datengerät: 0x%llx\n" #: .././logprint/logprint.c:223 #, c-format msgid " log file: \"%s\" " msgstr " Protokolldatei: »%s« " #: .././logprint/logprint.c:225 #, c-format msgid " log device: 0x%llx " msgstr " Protokollgerät: 0x%llx " #: .././logprint/logprint.c:228 #, c-format msgid "" "daddr: %lld length: %lld\n" "\n" msgstr "" "daddr: %lld Länge: %lld\n" "\n" #: .././mkfs/proto.c:60 #, c-format msgid "%s: failed to open %s: %s\n" msgstr "%s: Öffnen von %s fehlgeschlagen: %s\n" #: .././mkfs/proto.c:66 .././mkfs/proto.c:291 #, c-format msgid "%s: read failed on %s: %s\n" msgstr "%s: Lesen auf %s fehlgeschlagen: %s\n" #: .././mkfs/proto.c:71 #, c-format msgid "%s: proto file %s premature EOF\n" msgstr "%s: proto-Datei %s vorzeitiges EOF\n" #: .././mkfs/proto.c:108 msgid "cannot reserve space" msgstr "Speicher kann nicht reserviert werden" #: .././mkfs/proto.c:161 #, c-format msgid "%s: premature EOF in prototype file\n" msgstr "%s: verfrühtes EOF in Prototyp-Datei\n" #: .././mkfs/proto.c:180 msgid "error reserving space for a file" msgstr "Fehler beim Reservieren von Speicher für eine Datei" #: .././mkfs/proto.c:249 msgid "error allocating space for a file" msgstr "Fehler beim Allokieren von Speicher für eine Datei" #: .././mkfs/proto.c:253 #, c-format msgid "%s: cannot allocate space for file\n" msgstr "%s: Speicher für Datei kann nicht alloziert werden\n" #: .././mkfs/proto.c:316 msgid "directory createname error" msgstr "Verzeichnis-Namenserstellungs-Fehler" #: .././mkfs/proto.c:330 msgid "directory create error" msgstr "Verzeichnis-Erstellungsfehler" #: .././mkfs/proto.c:396 .././mkfs/proto.c:408 .././mkfs/proto.c:419 #: .././mkfs/proto.c:426 #, c-format msgid "%s: bad format string %s\n" msgstr "%s: schlechte Format-Zeichenkette %s\n" #: .././mkfs/proto.c:447 .././mkfs/proto.c:486 .././mkfs/proto.c:501 #: .././mkfs/proto.c:513 .././mkfs/proto.c:525 .././mkfs/proto.c:536 msgid "Inode allocation failed" msgstr "Inode-Allokation fehlgeschlagen" #: .././mkfs/proto.c:464 msgid "Inode pre-allocation failed" msgstr "Inode-Vorallokation fehlgeschlagen" #: .././mkfs/proto.c:474 msgid "Pre-allocated file creation failed" msgstr "Erzeugung der vorher zugeteiler Datei fehlgeschlagen" #: .././mkfs/proto.c:556 msgid "Directory creation failed" msgstr "Erstellung des Verzeichnisses fehlgeschlagen" #: .././mkfs/proto.c:580 msgid "Error encountered creating file from prototype file" msgstr "Fehler beim Erstellen einer Datei aus der Prototyp-Datei gefunden" #: .././mkfs/proto.c:630 msgid "Realtime bitmap inode allocation failed" msgstr "Zuweisung des Echtzeit-Bitmap-Inodes fehlgeschlagen" #: .././mkfs/proto.c:648 msgid "Realtime summary inode allocation failed" msgstr "Allokation des Echtzeit-Zusammenfassungs-Inodes fehlgeschlagen" #: .././mkfs/proto.c:675 msgid "Allocation of the realtime bitmap failed" msgstr "Zuweisung des Echtzeit-Bitmaps fehlgeschlagen" #: .././mkfs/proto.c:688 msgid "Completion of the realtime bitmap failed" msgstr "Vervollständigung des Echtzeit-Bitmaps fehlgeschlagen" #: .././mkfs/proto.c:712 msgid "Allocation of the realtime summary failed" msgstr "Allokation der Echtzeit-Zusammenfassung fehlgeschlagen" #: .././mkfs/proto.c:724 msgid "Completion of the realtime summary failed" msgstr "Vervollständigung der Echtzeit-Zusammenfassung fehlgeschlagen" #: .././mkfs/proto.c:741 msgid "Error initializing the realtime space" msgstr "Fehler beim Initialisieren des Echtzeit-Raumes" #: .././mkfs/proto.c:746 msgid "Error completing the realtime space" msgstr "Fehler beim vervollständigen des Echtzeit-Raumes" #: .././mkfs/xfs_mkfs.c:202 #, c-format msgid "data su/sw must not be used in conjunction with data sunit/swidth\n" msgstr "" "su-/sw-Daten müssen in Verbindung mit sunit-/swidth-Daten benutzt werden\n" #: .././mkfs/xfs_mkfs.c:209 #, c-format msgid "both data sunit and data swidth options must be specified\n" msgstr "sunit- und swidth-Optionen müssen beide angegeben werden\n" #: .././mkfs/xfs_mkfs.c:218 #, c-format msgid "data sunit/swidth must not be used in conjunction with data su/sw\n" msgstr "" "sunit-/swidth-Daten müssen in Verbindung mit su-/sw-Daten benutzt werden\n" #: .././mkfs/xfs_mkfs.c:225 #, c-format msgid "both data su and data sw options must be specified\n" msgstr "su- und sw-Optionen müssen beide angegeben werden\n" #: .././mkfs/xfs_mkfs.c:232 #, c-format msgid "data su must be a multiple of the sector size (%d)\n" msgstr "su-Daten müssen ein Vielfaches der Sektorgröße (%d) sein\n" #: .././mkfs/xfs_mkfs.c:243 #, c-format msgid "" "data stripe width (%d) must be a multiple of the data stripe unit (%d)\n" msgstr "" "Datenstreifenbreite (%d) muss ein Vielfaches der Datenstreifeneinheit (%d)\n" "sein\n" #: .././mkfs/xfs_mkfs.c:253 #, c-format msgid "log su should not be used in conjunction with log sunit\n" msgstr "" "su-Protokoll kann nicht in Verbindung mit sunit-Protokoll benutzt werden\n" #: .././mkfs/xfs_mkfs.c:262 #, c-format msgid "log sunit should not be used in conjunction with log su\n" msgstr "" "sunit-Protokoll kann nicht in Verbindung mit su-Protokoll benutzt werden\n" #: .././mkfs/xfs_mkfs.c:279 #, c-format msgid "%s: %s appears to contain an existing filesystem (%s).\n" msgstr "%s: %s scheint ein existierendes Dateisystem zu enthalten (%s).\n" #: .././mkfs/xfs_mkfs.c:285 #, c-format msgid "%s: %s appears to contain a partition table (%s).\n" msgstr "%s: %s scheint eine Partitionstabelle (%s) zu enthalten.\n" #: .././mkfs/xfs_mkfs.c:319 #, c-format msgid "log size %lld is not a multiple of the log stripe unit %d\n" msgstr "Protokollgröße %lld ist kein Vielfaches der Datenstreifeneinheit %d)\n" #: .././mkfs/xfs_mkfs.c:347 #, c-format msgid "Due to stripe alignment, the internal log size (%lld) is too large.\n" msgstr "" "Aufgrund der Streifenausrichtung ist die interne Protokollgröße (%lld) zu " "groß\n" #: .././mkfs/xfs_mkfs.c:349 #, c-format msgid "Must fit within an allocation group.\n" msgstr "Muss in eine Allokationsgruppe passen.\n" #: .././mkfs/xfs_mkfs.c:360 #, c-format msgid "log size %lld blocks too small, minimum size is %d blocks\n" msgstr "Protokollgröße %lld Blöcke zu klein, Mindestgröße ist %d Blöcke\n" #: .././mkfs/xfs_mkfs.c:366 #, c-format msgid "log size %lld blocks too large, maximum size is %lld blocks\n" msgstr "Protokollgröße %lld Blöcke zu groß, maximale Größe ist %lld Blöcke\n" #: .././mkfs/xfs_mkfs.c:372 #, c-format msgid "log size %lld bytes too large, maximum size is %lld bytes\n" msgstr "Protokollgröße %lld Bytes zu groß, maximale Größe ist %lld Bytes\n" #: .././mkfs/xfs_mkfs.c:477 #, c-format msgid "agsize (%lldb) too small, need at least %lld blocks\n" msgstr "agsize (%lldb) zu klein, es werden mindestens %lld Blöcke benötigt\n" #: .././mkfs/xfs_mkfs.c:485 #, c-format msgid "agsize (%lldb) too big, maximum is %lld blocks\n" msgstr "agsize (%lldb) zu groß, maximal %lld Blöcke\n" #: .././mkfs/xfs_mkfs.c:493 #, c-format msgid "agsize (%lldb) too big, data area is %lld blocks\n" msgstr "agsize (%lldb) zu groß, Datenbereich hat %lld Blöcke\n" #: .././mkfs/xfs_mkfs.c:500 #, c-format msgid "too many allocation groups for size = %lld\n" msgstr "zu viele Allokations-Gruppen für Größe = %lld\n" #: .././mkfs/xfs_mkfs.c:502 #, c-format msgid "need at most %lld allocation groups\n" msgstr "es werden höchstens %lld Allokations-Gruppen benötigt\n" #: .././mkfs/xfs_mkfs.c:510 #, c-format msgid "too few allocation groups for size = %lld\n" msgstr "zu wenige Allokations-Gruppen für Größe = %lld\n" #: .././mkfs/xfs_mkfs.c:512 #, c-format msgid "need at least %lld allocation groups\n" msgstr "es werden mindestens %lld Allokations-Gruppen benötigt\n" #: .././mkfs/xfs_mkfs.c:525 #, c-format msgid "last AG size %lld blocks too small, minimum size is %lld blocks\n" msgstr "letzte AG-Größe %lld Blöcke zu klein, Mindestgröße ist %lld Blöcke\n" #: .././mkfs/xfs_mkfs.c:536 #, c-format msgid "%lld allocation groups is too many, maximum is %lld\n" msgstr "%lld Allokations-Gruppen sind zu viel, Maximum ist %lld\n" #: .././mkfs/xfs_mkfs.c:560 #, c-format msgid "error reading existing superblock -- failed to memalign buffer\n" msgstr "" "Fehler beim Lesen des bestehenden Superblocks -- memalign des Puffers\n" "fehlgeschlagen\n" #: .././mkfs/xfs_mkfs.c:566 #, c-format msgid "existing superblock read failed: %s\n" msgstr "Lesen des bestehenden Superblocks fehlgeschlagen: %s\n" #: .././mkfs/xfs_mkfs.c:850 #, c-format msgid "%s: Specify data sunit in 512-byte blocks, no unit suffix\n" msgstr "" "%s: Geben Sie sunit-Daten in 512-Byte-Blöcken an, kein Einheit-Suffix\n" #: .././mkfs/xfs_mkfs.c:866 #, c-format msgid "%s: Specify data swidth in 512-byte blocks, no unit suffix\n" msgstr "" "%s: Geben Sie swidth-Daten in 512-Byte-Blöcken an, kein Einheit-Suffix\n" #: .././mkfs/xfs_mkfs.c:893 #, c-format msgid "%s: Specify data sw as multiple of su, no unit suffix\n" msgstr "%s: Geben Sie sw-Daten als Vielfaches von su an, kein Einheit-Suffix\n" #: .././mkfs/xfs_mkfs.c:1112 #, c-format msgid "Specify log sunit in 512-byte blocks, no size suffix\n" msgstr "Geben Sie sunit-Daten in 512-Byte-Blöcken an, kein Größe-Suffix\n" #: .././mkfs/xfs_mkfs.c:1369 #, c-format msgid "extra arguments\n" msgstr "Extra-Argumente\n" #: .././mkfs/xfs_mkfs.c:1375 #, c-format msgid "cannot specify both %s and -d name=%s\n" msgstr "es kann nicht beides angegeben werden %s und -d Name=%s\n" #: .././mkfs/xfs_mkfs.c:1392 #, c-format msgid "illegal block size %d\n" msgstr "unerlaubte Blockgröße %d\n" #: .././mkfs/xfs_mkfs.c:1411 #, c-format msgid "illegal sector size %d\n" msgstr "unerlaubte Sektorgröße %d\n" #: .././mkfs/xfs_mkfs.c:1416 #, c-format msgid "illegal log sector size %d\n" msgstr "unerlaubte Protokoll-Bereichs-Größe %d\n" #: .././mkfs/xfs_mkfs.c:1426 #, c-format msgid "illegal directory block size %d\n" msgstr "unerlaubte Verzeichnis-Block-Größe %d\n" #: .././mkfs/xfs_mkfs.c:1440 #, c-format msgid "both -d agcount= and agsize= specified, use one or the other\n" msgstr "" "beide -d agcount= und agsize= angegeben, benutzen Sie das eine oder\n" "das andere\n" #: .././mkfs/xfs_mkfs.c:1446 #, c-format msgid "if -d file then -d name and -d size are required\n" msgstr "wenn -d Datei, dann sind -d Name und -d Größe erforderlich\n" #: .././mkfs/xfs_mkfs.c:1455 #, c-format msgid "illegal data length %lld, not a multiple of %d\n" msgstr "unerlaubte Datenlänge %lld, kein Vielfaches von %d\n" #: .././mkfs/xfs_mkfs.c:1461 #, c-format msgid "warning: data length %lld not a multiple of %d, truncated to %lld\n" msgstr "" "Warnung: Datenlänge %lld ist kein Vielfaches von %d, wurde auf %lld gekürzt\n" #: .././mkfs/xfs_mkfs.c:1475 #, c-format msgid "if -l file then -l name and -l size are required\n" msgstr "wenn -l Datei, dann sind -l Name und -l Größe erforderlich\n" #: .././mkfs/xfs_mkfs.c:1484 #, c-format msgid "illegal log length %lld, not a multiple of %d\n" msgstr "unerlaubte Protokolllänge %lld, kein Vielfaches von %d\n" #: .././mkfs/xfs_mkfs.c:1491 #, c-format msgid "warning: log length %lld not a multiple of %d, truncated to %lld\n" msgstr "" "Warnung: Protokolllänge %lld ist kein Vielfaches von %d, wurde auf\n" "%lld gekürzt\n" #: .././mkfs/xfs_mkfs.c:1497 #, c-format msgid "if -r file then -r name and -r size are required\n" msgstr "wenn -r Datei, dann sind -r Name und -r Größe erforderlich\n" #: .././mkfs/xfs_mkfs.c:1506 #, c-format msgid "illegal rt length %lld, not a multiple of %d\n" msgstr "unerlaubte rt-Länge %lld, kein Vielfaches von %d\n" #: .././mkfs/xfs_mkfs.c:1513 #, c-format msgid "warning: rt length %lld not a multiple of %d, truncated to %lld\n" msgstr "" "Warnung: rt-Länge %lld ist kein Vielfaches von %d, wurde auf %lld gekürzt\n" #: .././mkfs/xfs_mkfs.c:1526 #, c-format msgid "illegal rt extent size %lld, not a multiple of %d\n" msgstr "unerlaubte rt-Erweiterungs-Länge %lld, kein Vielfaches von %d\n" #: .././mkfs/xfs_mkfs.c:1532 #, c-format msgid "rt extent size %s too large, maximum %d\n" msgstr "rt-Erweiterungs-Länge %s zu groß, Maximum %d\n" #: .././mkfs/xfs_mkfs.c:1538 #, c-format msgid "rt extent size %s too small, minimum %d\n" msgstr "rt-Erweiterungs-Länge %s zu klein, Minimum %d\n" #: .././mkfs/xfs_mkfs.c:1582 #, c-format msgid "illegal inode size %d\n" msgstr "unerlaubte Inode-Größe %d\n" #: .././mkfs/xfs_mkfs.c:1587 #, c-format msgid "allowable inode size with %d byte blocks is %d\n" msgstr "zulässige Inode-Größe mit %d Byte-Blocks ist %d\n" #: .././mkfs/xfs_mkfs.c:1591 #, c-format msgid "allowable inode size with %d byte blocks is between %d and %d\n" msgstr "zulässige Inode-Größe mit %d Byte-Blocks liegt zwischen %d und %d\n" #: .././mkfs/xfs_mkfs.c:1599 #, c-format msgid "log stripe unit specified, using v2 logs\n" msgstr "logische Stripe-Einheit angegeben, v2-Protokolle werden benutzt\n" #: .././mkfs/xfs_mkfs.c:1617 #, c-format msgid "no device name given in argument list\n" msgstr "in der Argumenten-Liste ist kein Gerätename angegeben\n" #: .././mkfs/xfs_mkfs.c:1642 #, c-format msgid "%s: Use the -f option to force overwrite.\n" msgstr "%s: Benutzen Sie die -f-Option um das Überschreiben zu erzwingen.\n" #: .././mkfs/xfs_mkfs.c:1653 msgid "internal log" msgstr "Internes Protokoll" #: .././mkfs/xfs_mkfs.c:1655 msgid "volume log" msgstr "Datenträger-Protokoll" #: .././mkfs/xfs_mkfs.c:1657 #, c-format msgid "no log subvolume or internal log\n" msgstr "kein Unter-Datenträger-Protokoll oder internes Protokoll\n" #: .././mkfs/xfs_mkfs.c:1664 msgid "volume rt" msgstr "Datenträger rt" #: .././mkfs/xfs_mkfs.c:1669 #, c-format msgid "" "size %s specified for data subvolume is too large, maximum is %lld blocks\n" msgstr "" "für den Unter-Datenträger angegebene Größe %s ist zu groß, Maximum ist %lld\n" "Blöcke\n" #: .././mkfs/xfs_mkfs.c:1676 #, c-format msgid "can't get size of data subvolume\n" msgstr "Datenträgergröße kann nicht ermittelt werden\n" #: .././mkfs/xfs_mkfs.c:1681 #, c-format msgid "size %lld of data subvolume is too small, minimum %d blocks\n" msgstr "" "für den Unter-Datenträger angegebene Größe %lld ist zu klein, Minimum\n" "ist %d Blöcke\n" #: .././mkfs/xfs_mkfs.c:1688 #, c-format msgid "can't have both external and internal logs\n" msgstr "man kann nicht beides, externe und interne Protokolle, haben\n" #: .././mkfs/xfs_mkfs.c:1692 #, c-format msgid "data and log sector sizes must be equal for internal logs\n" msgstr "" "Daten- und Protokollbereichs-Größe müssen für interne Protokolle gleich " "sein\n" #: .././mkfs/xfs_mkfs.c:1698 #, c-format msgid "" "Warning: the data subvolume sector size %u is less than the sector size \n" "reported by the device (%u).\n" msgstr "" "Warnung: Die Datenträger-Sektorengröße %u ist kleiner als die Sektorengröße\n" "die vom Gerät (%u) vermeldet wurde.\n" #: .././mkfs/xfs_mkfs.c:1704 #, c-format msgid "" "Warning: the log subvolume sector size %u is less than the sector size\n" "reported by the device (%u).\n" msgstr "" "Warnung: Die Datenträger-Protokoll-Sektorengröße %u ist kleiner als die\n" "Sektorengröße die vom Gerät (%u) vermeldet wurde.\n" #: .././mkfs/xfs_mkfs.c:1710 #, c-format msgid "" "Warning: the realtime subvolume sector size %u is less than the sector size\n" "reported by the device (%u).\n" msgstr "" "Warnung: Die Datenträger-Echtzeit-Sektorengröße %u ist kleiner als die\n" "Sektorengröße die vom Gerät (%u) vermeldet wurde.\n" #: .././mkfs/xfs_mkfs.c:1724 #, c-format msgid "" "size %s specified for log subvolume is too large, maximum is %lld blocks\n" msgstr "" "für den Protokoll-Unter-Datenträger angegebene Größe %s ist zu groß, " "Maximum\n" "ist %lld Blöcke\n" #: .././mkfs/xfs_mkfs.c:1731 #, c-format msgid "size specified for non-existent log subvolume\n" msgstr "Größe für nicht existierenden Protokoll-Unter-Datenträger angegeben\n" #: .././mkfs/xfs_mkfs.c:1734 #, c-format msgid "size %lld too large for internal log\n" msgstr "Größe %lld zu groß für internes Protokoll\n" #: .././mkfs/xfs_mkfs.c:1761 #, c-format msgid "" "size %s specified for rt subvolume is too large, maximum is %lld blocks\n" msgstr "" "für den rt-Unter-Datenträger angegebene Größe %s ist zu groß, Maximum ist\n" "%lld Blöcke\n" #: .././mkfs/xfs_mkfs.c:1769 #, c-format msgid "size specified for non-existent rt subvolume\n" msgstr "Größe für nicht existierenden rt-Unter-Datenträger angegeben\n" #: .././mkfs/xfs_mkfs.c:1786 #, c-format msgid "agsize (%lld) not a multiple of fs blk size (%d)\n" msgstr "agsize (%lld) kein Vielfaches der »fs blk«-Größe (%d)\n" #: .././mkfs/xfs_mkfs.c:1803 #, c-format msgid "" "%s: Specified data stripe unit %d is not the same as the volume stripe unit %" "d\n" msgstr "" "%s: Angegebene Daten-Stripe-Einheit %d ist nicht die gleiche wie die\n" "Datenträger-Stripe-Einheit %d\n" #: .././mkfs/xfs_mkfs.c:1810 #, c-format msgid "" "%s: Specified data stripe width %d is not the same as the volume stripe " "width %d\n" msgstr "" "%s: Angegebene Daten-Stripe-Breite %d ist nicht die gleiche wie die\n" "Datenträger-Stripe-Breite %d\n" #: .././mkfs/xfs_mkfs.c:1858 #, c-format msgid "agsize rounded to %lld, swidth = %d\n" msgstr "agsize gerundet auf %lld, swidth = %d\n" #: .././mkfs/xfs_mkfs.c:1865 #, c-format msgid "" "Allocation group size (%lld) is not a multiple of the stripe unit (%d)\n" msgstr "" "Zuordnungsgruppengröße (%lld) ist kein Vielfaches der Stripe-Einheit (%d)\n" #: .././mkfs/xfs_mkfs.c:1887 #, c-format msgid "" "Warning: AG size is a multiple of stripe width. This can cause performance\n" "problems by aligning all AGs on the same disk. To avoid this, run mkfs " "with\n" "an AG size that is one stripe unit smaller, for example %llu.\n" msgstr "" "Warnung: AG-Größe ist ein Vielfaches der Stripe-Breite. Dies kann zu\n" "Performance-Problem führen bei Ausrichtung aller AGs auf die gleiche\n" "Platte. Um dies zu vermeiden, führen Sie mkfs mit einer AG-Größe aus, die\n" "ein Stripe kleiner ist, zum Beispiel %llu.\n" #: .././mkfs/xfs_mkfs.c:1912 #, c-format msgid "" "%s: Stripe unit(%d) or stripe width(%d) is not a multiple of the block size(%" "d)\n" msgstr "" "%s: Stripe-Einheit (%d) oder Stripe-Breite (%d) ist kein Vielfaches der\n" "Blockgröße (%d)\n" #: .././mkfs/xfs_mkfs.c:1944 #, c-format msgid "log stripe unit (%d) must be a multiple of the block size (%d)\n" msgstr "" "Protokoll-Stripe-Einheit (%d) muss ein Vielfaches der Blockgröße (%d) sein\n" #: .././mkfs/xfs_mkfs.c:1957 #, c-format msgid "log stripe unit (%d bytes) is too large (maximum is 256KiB)\n" msgstr "Protokoll-Stripe-Einheit (%d Bytes) ist zu groß (Maximum ist 256KiB)\n" #: .././mkfs/xfs_mkfs.c:1960 #, c-format msgid "log stripe unit adjusted to 32KiB\n" msgstr "Protokoll-Stripe-Einheit angepasst auf 32KiB\n" #: .././mkfs/xfs_mkfs.c:1985 #, c-format msgid "internal log size %lld too large, must fit in allocation group\n" msgstr "" "interne Protokollgröße %lld zu groß, muss in die Allokationsgruppe\n" "passen\n" #: .././mkfs/xfs_mkfs.c:1992 #, c-format msgid "log ag number %d too large, must be less than %lld\n" msgstr "Protokoll-»ag«-Nummer %d zu groß, muss kleiner als %lld sein\n" #: .././mkfs/xfs_mkfs.c:2022 #, c-format msgid "" "meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n" " =%-22s sectsz=%-5u attr=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d\n" "log =%-22s bsize=%-6d blocks=%lld, version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n" msgstr "" "Metadaten =%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n" " =%-22s sectsz=%-5u attr=%u\n" "Daten =%-22s bsize=%-6u Blöcke=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "Benennung =Version %-14u bsize=%-6u ascii-ci=%d\n" "Protokoll =%-22s bsize=%-6d Blöcke=%lld, Version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "Echtzeit =%-22s extsz=%-6d Blöcke=%lld, rtextents=%lld\n" #: .././mkfs/xfs_mkfs.c:2138 #, c-format msgid "%s: Growing the data section failed\n" msgstr "%s: Wachsen des Datenbereiches fehlgeschlagen\n" #: .././mkfs/xfs_mkfs.c:2168 #, c-format msgid "%s: filesystem failed to initialize\n" msgstr "%s: Initialisierung des Dateisystems fehlgeschlagen\n" #: .././mkfs/xfs_mkfs.c:2379 #, c-format msgid "%s: root inode created in AG %u, not AG 0\n" msgstr "%s: Wurzel-Inode in AG %u erstellt, nicht AG 0\n" #: .././mkfs/xfs_mkfs.c:2446 #, c-format msgid "Cannot specify both -%c %s and -%c %s\n" msgstr "Beides kann nicht angegeben werden -%c %s und -%c %s\n" #: .././mkfs/xfs_mkfs.c:2457 #, c-format msgid "Illegal value %s for -%s option\n" msgstr "Unerlaubter Wert %s für -%s-Option\n" #: .././mkfs/xfs_mkfs.c:2474 #, c-format msgid "-%c %s option requires a value\n" msgstr "»-%c %s«-Option benötigt einen Wert\n" #: .././mkfs/xfs_mkfs.c:2487 .././repair/xfs_repair.c:170 #, c-format msgid "option respecified\n" msgstr "Option wieder angegeben\n" #: .././mkfs/xfs_mkfs.c:2496 .././repair/xfs_repair.c:177 #, c-format msgid "unknown option -%c %s\n" msgstr "unbekannte Option -%c %s\n" #: .././mkfs/xfs_mkfs.c:2535 #, c-format msgid "blocksize not available yet.\n" msgstr "Blockgröße noch nicht verfügbar.\n" #: .././mkfs/xfs_mkfs.c:2561 #, c-format msgid "" "Usage: %s\n" "/* blocksize */\t\t[-b log=n|size=num]\n" "/* data subvol */\t[-d agcount=n,agsize=n,file,name=xxx,size=num,\n" "\t\t\t (sunit=value,swidth=value|su=num,sw=num),\n" "\t\t\t sectlog=n|sectsize=num\n" "/* inode size */\t[-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2]\n" "/* log subvol */\t[-l agnum=n,internal,size=num,logdev=xxx,version=n\n" "\t\t\t sunit=value|su=num,sectlog=n|sectsize=num,\n" "\t\t\t lazy-count=0|1]\n" "/* label */\t\t[-L label (maximum 12 characters)]\n" "/* naming */\t\t[-n log=n|size=num,version=2|ci]\n" "/* prototype file */\t[-p fname]\n" "/* quiet */\t\t[-q]\n" "/* realtime subvol */\t[-r extsize=num,size=num,rtdev=xxx]\n" "/* sectorsize */\t[-s log=n|size=num]\n" "/* version */\t\t[-V]\n" "\t\t\tdevicename\n" " is required unless -d name=xxx is given.\n" " is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n" " xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n" " is xxx (512 byte blocks).\n" msgstr "" "Aufruf: %s\n" "/* Blockgröße */\t\t[-b log=n|size=num]\n" "/* Unter-Datenträger */\t[-d agcount=n,agsize=n,file,name=xxx,size=num,\n" "\t\t\t (sunit=value,swidth=value|su=num,sw=num),\n" "\t\t\t sectlog=n|sectsize=num\n" "/* Inode-Größe */\t[-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2]\n" "/* Protokoll-Datenträger */\t[-l agnum=n,internal,size=num,\n" "\t\t\t logdev=xxx,version=n\n" "\t\t\t sunit=value|su=num,sectlog=n|sectsize=num,\n" "\t\t\t lazy-count=0|1]\n" "/* Aufschrift */\t\t[-L label (maximal 12 Zeichen)]\n" "/* Benennung */\t\t[-n log=n|size=num,version=2|ci]\n" "/* Prototyp-Datei */\t[-p fname]\n" "/* ohne Ausgabe */\t\t[-q]\n" "/* Echtzeit-Unter-Datenträger */\t[-r extsize=num,size=num,rtdev=xxx]\n" "/* Sektorengröße */\t[-s log=n|size=num]\n" "/* Version */\t\t[-V]\n" "\t\t\tdevicename\n" " wird benötigt, außer wenn -d name=xxx angegeben ist.\n" " is xxx (Bytes), xxxs (Sektoren), xxxb (fs Blöcke), xxxk (xxx KiB),\n" " xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n" " ist xxx (512 Byte-Blöcke).\n" #: .././quota/init.c:48 #, c-format msgid "Usage: %s [-p prog] [-c cmd]... [-d project]... [path]\n" msgstr "Aufruf: %s [-p Programm] [-c Befehl]... [-d Projekt]... [Pfad]\n" #: .././quota/path.c:39 #, c-format msgid "%sFilesystem Pathname\n" msgstr "%sDateisystem Pfadname\n" #: .././quota/path.c:40 msgid " " msgstr " " #: .././quota/path.c:43 #, c-format msgid "%c%03d%c " msgstr "%c%03d%c " #: .././quota/path.c:45 #, c-format msgid "%-19s %s" msgstr "%-19s %s" #: .././quota/path.c:48 #, c-format msgid " (project %u" msgstr " (Projekt %u" #: .././quota/path.c:50 #, c-format msgid ", %s" msgstr ", %s" #: .././quota/path.c:103 #, c-format msgid "No paths are available\n" msgstr "Es sind keine Pfade verfügbar\n" #: .././quota/path.c:124 msgid "path" msgstr "Pfad" #: .././quota/path.c:125 msgid "paths" msgstr "Pfade" #: .././quota/path.c:131 msgid "set current path, or show the list of paths" msgstr "aktuellen Pfad setzen oder Pfadliste anzeigen" #: .././quota/path.c:139 msgid "list known mount points and projects" msgstr "bekannte Einhängepunkte und Projekte auflisten" #: .././quota/edit.c:36 #, c-format msgid "" "\n" " modify quota limits for the specified user\n" "\n" " Example:\n" " 'limit bsoft=100m bhard=110m tanya\n" "\n" " Changes the soft and/or hard block limits, inode limits and/or realtime\n" " block limits that are currently being used for the specified user, group,\n" " or project. The filesystem identified by the current path is modified.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota limits\n" " -p -- modify project quota limits\n" " -u -- modify user quota limits\n" " The block limit values can be specified with a units suffix - accepted\n" " units are: k (kilobytes), m (megabytes), g (gigabytes), and t (terabytes).\n" " The user/group/project can be specified either by name or by number.\n" "\n" msgstr "" "\n" " Quota-Beschränkungen für den angegebenen Anwender ändern\n" "\n" " Beispiel:\n" " 'limit bsoft=100m bhard=110m tanya\n" "\n" "Ändert die Soft-/Hard-Block-Quotas, Inode-Quotas und/oder\n" "Echtzeit-Block-Quotas, die derzeit für den angegebenen Anwender, die\n" "Gruppe oder das Projekt benutzt werden. Das durch den Pfad erkannte\n" "Dateisystem wird geändert.\n" " -d -- setzt die Standardwerte, die benutzt werden, wenn eine Datei neu\n" " erstellt wurde\n" " -g -- ändert Gruppen-Quota-Beschränkungen\n" " -p -- ändert Projekt-Quota-Beschränkungen\n" " -u -- ändert Anwender-Quota-Beschränkungen\n" " Die -block-Quota-Werte können mit einem einheitlichen Suffix\n" " angegeben werden - akzeptierte Einheiten sind: k (Kilobyte),\n" " m (Megabyte), g (Gigabyte) und t (Terabyte). Gruppe, Anwender, Projekt\n" " kann entweder durch Name oder Nummer angegeben werden.\n" "\n" #: .././quota/edit.c:59 #, c-format msgid "" "\n" " modify quota enforcement timeout for the current filesystem\n" "\n" " Example:\n" " 'timer -i 3days'\n" " (soft inode limit timer is changed to 3 days)\n" "\n" " Changes the timeout value associated with the block limits, inode limits\n" " and/or realtime block limits for all users, groups, or projects on the\n" " current filesystem.\n" " As soon as a user consumes the amount of space or number of inodes set as\n" " the soft limit, a timer is started. If the timer expires and the user is\n" " still over the soft limit, the soft limit is enforced as the hard limit.\n" " The default timeout is 7 days.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota timer\n" " -p -- modify project quota timer\n" " -u -- modify user quota timer\n" " -b -- modify the blocks-used timer\n" " -i -- modify the inodes-used timer\n" " -r -- modify the blocks-used timer for the (optional) realtime subvolume\n" " The timeout value is specified as a number of seconds, by default.\n" " However, a suffix may be used to alternatively specify minutes (m),\n" " hours (h), days (d), or weeks (w) - either the full word or the first\n" " letter of the word can be used.\n" "\n" msgstr "" "\n" " Zeitüberschreitung des Erzwingens von Quota-Größen für das derzeitige\n" " Dateisystem ändern\n" "\n" " Beispiel:\n" " 'timer -i 3days'\n" " (weiche Inode-Zeitbeschränkung wird auf drei Tage geändert)\n" "\n" " Ändert den Wert der Zeitbeschränkung, der sich auf Block-, Inode und/oder\n" " Echtzeit-Blockbeschränkungen für alle Nutzer, Gruppen oder Projekte auf " "dem\n" " derzeitigen Dateisystem bezieht.\n" " Sobald ein Anwender einen Anteil am Speicher oder den Inodes belegt, der\n" " als weiche Beschränkung gesetzt ist, wird ein Zeitnehmer gestartet. Wenn\n" " der Zeitnehmer abläuft und der Anwender ist immer noch über der weichen\n" " Beschränkung, wird die weiche Beschränkung als harte Beschränkung\n" " erzwungen.\n" " Die Standard-Zeitbeschränkung beträgt sieben Tage.\n" " -d -- setzt die Standardwerte, wird benutzt, wenn zum ersten Mal eine " "Datei\n" " erstellt wird\n" " -g -- ändert Gruppen-Quota-Zeitnehmer\n" " -p -- ändert Projekt-Quota-Zeitnehmer\n" " -u -- ändert Anwender-Quota-Zeitnehmer\n" " -b -- ändert den für Blöcke benutzten Zeitnehmer\n" " -i -- ändert den für Inodes benutzten Zeitnehmer\n" " -r -- ändert den für Blöcke benutzten Zeitnehmer für den (optionalen)\n" " Echtzeit-Unterdatenträger\n" " Der Zeitüberschreitungswert ist standardmäßig als eine Anzahl von Sekunden\n" " angegeben. Allerdings kann eine Erweiterung angegeben werden um alternativ\n" " Minuten (m), Stunden (h), Tage (d) oder Wochen (w) anzugeben -sowohl das\n" " ganze Wort als auch der erste Buchstabe können benutzt werden.\n" "\n" #: .././quota/edit.c:91 #, c-format msgid "" "\n" " modify the number of quota warnings sent to the specified user\n" "\n" " Example:\n" " 'warn 2 jimmy'\n" " (tell the quota system that two warnings have been sent to user jimmy)\n" "\n" " Changes the warning count associated with the block limits, inode limits\n" " and/or realtime block limits for the specified user, group, or project.\n" " When a user has been warned the maximum number of times allowed, the soft\n" " limit is enforced as the hard limit. It is intended as an alternative to\n" " the timeout system, where the system administrator updates a count of the\n" " number of warnings issued to people, and they are penalised if the " "warnings\n" " are ignored.\n" " -d -- set maximum warning count, which triggers soft limit enforcement\n" " -g -- set group quota warning count\n" " -p -- set project quota warning count\n" " -u -- set user quota warning count\n" " -b -- set the blocks-used warning count\n" " -i -- set the inodes-used warning count\n" " -r -- set the blocks-used warn count for the (optional) realtime subvolume\n" " The user/group/project can be specified either by name or by number.\n" "\n" msgstr "" "\n" " Anzahl der Quota-Warnungen ändern, die zum angegebenen Anwender\n" " gesandt werden\n" "\n" " Beispiel:\n" " 'warn 2 Hans'\n" " (teilt dem Quota-System mit, dass zwei Warnungen an den Anwender Hans\n" " gesandt wurden)\n" " Ändert die Anzahl der Warnungen, die sich auf Block-, Inode und/oder\n" " Echtzeit-Blockbeschränkungen für den angegebenen Nutzer, die Gruppe oder\n" " das Projekt auf dem derzeitigen Dateisystem beziehen.\n" " Wenn ein Anwender die maximale Anzahl von Warnungen erhalten hat, wird die\n" " weiche Beschränkung zu einer harten Beschränkung. Es ist als Alternative\n" " zum Zeitbeschränkungs-System gedacht, bei dem der Systemadministrator die\n" " Anzahl der Warnungen aktualisiert, den Leuten ausgegeben werden und sie\n" " werden bestraft, wenn die Warnungen ignoriert werden.\n" " -d -- maximale Anzahl der Warnungen setzen, die weiche Beschränkungen\n" " auslösen.\n" " -g -- Anzahl der Warnungen für Gruppen-Quotas setzen\n" " -p -- Anzahl der Warnungen für Projekt-Quotas setzen\n" " -u -- Anzahl der Warnungen für Anwender-Quotas setzen\n" " -b -- Anzahl der Warnungen, die von Böcken benutzt werden, setzen\n" " -i -- Anzahl der Warnungen, die von Inodes benutzt werden, setzen\n" " -r -- Anzahl der Warnungen, die von Böcken benutzt werden, für einen\n" " (optionalen) Echtzeit-Unter-Datenträger setzen\n" " Nutzer/Gruppe/Projekt können entweder durch Name oder durch Nummer\n" " angegeben werden\n" "\n" #: .././quota/edit.c:145 #, c-format msgid "%s: cannot set limits: %s\n" msgstr "%s: Beschränkungen können nicht gesetzt werden: %s\n" #: .././quota/edit.c:166 .././quota/edit.c:563 #, c-format msgid "%s: invalid user name: %s\n" msgstr "%s: ungültiger Anwendername: %s\n" #: .././quota/edit.c:189 .././quota/edit.c:580 #, c-format msgid "%s: invalid group name: %s\n" msgstr "%s: ungültiger Gruppenname: %s\n" #: .././quota/edit.c:212 .././quota/edit.c:597 #, c-format msgid "%s: invalid project name: %s\n" msgstr "%s: ungültiger Projektname: %s\n" #: .././quota/edit.c:237 #, c-format msgid "%s: Warning: `%s' in quota blocks is 0 (unlimited).\n" msgstr "%s: Warnung: »%s« in Quota-Blöcken ist 0 (unbegrenzt).\n" #: .././quota/edit.c:326 #, c-format msgid "%s: unrecognised argument %s\n" msgstr "%s: nicht erkanntes Argument %s\n" #: .././quota/edit.c:333 #, c-format msgid "%s: cannot find any valid arguments\n" msgstr "%s: es wurden keine gültigen Argumente gefunden\n" #: .././quota/edit.c:441 #, c-format msgid "%s: fopen on %s failed: %s\n" msgstr "%s: fopen von %s fehlgeschlagen: %s\n" #: .././quota/edit.c:473 #, c-format msgid "%s: cannot set timer: %s\n" msgstr "%s: Zeitnehmer kann nicht eingestellt werden: %s\n" #: .././quota/edit.c:547 #, c-format msgid "%s: cannot set warnings: %s\n" msgstr "%s: Warnungen können nicht gesetzt werden: %s\n" #: .././quota/edit.c:678 msgid "limit" msgstr "Beschränkung" #: .././quota/edit.c:683 msgid "[-gpu] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name" msgstr "[-gpu] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name" #: .././quota/edit.c:684 msgid "modify quota limits" msgstr "Quota-Beschränkungen ändern" #: .././quota/edit.c:687 msgid "restore" msgstr "wieder herstellen" #: .././quota/edit.c:691 .././quota/report.c:33 .././quota/report.c:647 msgid "[-gpu] [-f file]" msgstr "[-gpu] [-f Datei]" #: .././quota/edit.c:692 msgid "restore quota limits from a backup file" msgstr "Quota-Beschränkungen aus einer Sicherungsdatei wiederherstellen" #: .././quota/edit.c:694 msgid "timer" msgstr "Zeitnehmer" #: .././quota/edit.c:698 .././quota/edit.c:706 msgid "[-bir] [-gpu] value -d|id|name" msgstr "[-bir] [-gpu] Ert -d|id|name" #: .././quota/edit.c:699 msgid "get/set quota enforcement timeouts" msgstr "ausgeben/setzen von Zeitbeschränkungen zum Erzwingen von Quotas" #: .././quota/edit.c:702 msgid "warn" msgstr "warnen" #: .././quota/edit.c:707 msgid "get/set enforcement warning counter" msgstr "ausgeben/setzen des Warnungs-Zählers zum Erzwingen" #: .././quota/free.c:29 #, c-format msgid "" "\n" " reports the number of free disk blocks and inodes\n" "\n" " This command reports the number of total, used, and available disk blocks.\n" " It can optionally report the same set of numbers for inodes and realtime\n" " disk blocks, and will report on all known XFS filesystem mount points and\n" " project quota paths by default (see 'print' command for a list).\n" " -b -- report the block count values\n" " -i -- report the inode count values\n" " -r -- report the realtime block count values\n" " -h -- report in a human-readable format\n" " -N -- suppress the header from the output\n" "\n" msgstr "" "\n" " meldet die Anzahl freier Blöcke und Inodes\n" "\n" " Dieser Befehl meldet die Anzahl von allen, den benutzten und den\n" " verfügbaren Plattenblöcken. Er kann wahlweise den gleichen Satz von\n" " Inode-Nummern und Echtzeit-Plattenblöcken melden sowie alle bekannten\n" " XFS-Dateisystem-Einhängepunkte und Standard-Projekt-Quota-Pfade\n" " (»print«-Befehl gibt eine Liste aus).\n" " -b -- Werte für die Block-Anzahl melden\n" " -i -- Werte für die Inode-Anzahl melden\n" " -r -- Werte für die Echtzeit-Block-Anzahl melden\n" " -h -- in einem lesbaren Format ausgeben\n" " -N -- in der Ausgabe die Kopfdaten unterdrücken\n" "\n" #: .././quota/free.c:146 #, c-format msgid "%s: project quota flag not set on %s\n" msgstr "%s: Projekt-Quota-Markierung ist nicht auf %s gesetzt\n" #: .././quota/free.c:155 #, c-format msgid "%s: project ID %u (%s) doesn't match ID %u (%s)\n" msgstr "%s: Projekt-ID %u (%s) entspricht nicht ID %u (%s)\n" #: .././quota/free.c:220 #, c-format msgid "Filesystem " msgstr "Dateisystem" #: .././quota/free.c:220 #, c-format msgid "Filesystem " msgstr "Dateisystem" #: .././quota/free.c:223 #, c-format msgid " Size Used Avail Use%%" msgstr " Größe Benutzt Verfügbar Benutzung%%" #: .././quota/free.c:224 #, c-format msgid " 1K-blocks Used Available Use%%" msgstr " 1K-Blöcke Benutzt Verfügbar Benutzung%%" #: .././quota/free.c:227 #, c-format msgid " Inodes Used Free Use%%" msgstr " Inodes Benutzt Frei Use%%" #: .././quota/free.c:228 #, c-format msgid " Inodes IUsed IFree IUse%%" msgstr " Inodes IUsed IFree IUse%%" #: .././quota/free.c:229 #, c-format msgid " Pathname\n" msgstr " Pfadname\n" #: .././quota/free.c:360 msgid "df" msgstr "df" #: .././quota/free.c:361 .././repair/dir2.c:949 .././repair/dir2.c:1480 msgid "free" msgstr "frei" #: .././quota/free.c:365 msgid "[-bir] [-hn] [-f file]" msgstr "[-bir] [-hn] [-f Datei]" #: .././quota/free.c:366 msgid "show free and used counts for blocks and inodes" msgstr "Anzahl freier und benutzter Blöcke und Inodes anzeigen" #: .././quota/project.c:45 #, c-format msgid "" "\n" " list projects or setup a project tree for tree quota management\n" "\n" " Example:\n" " 'project -c logfiles'\n" " (match project 'logfiles' to a directory, and setup the directory tree)\n" "\n" " Without arguments, report all projects found in the /etc/projects file.\n" " The project quota mechanism in XFS can be used to implement a form of\n" " directory tree quota, where a specified directory and all of the files\n" " and subdirectories below it (i.e. a tree) can be restricted to using a\n" " subset of the available space in the filesystem.\n" "\n" " A managed tree must be setup initially using the -c option with a project.\n" " The specified project name or identifier is matched to one or more trees\n" " defined in /etc/projects, and these trees are then recursively descended\n" " to mark the affected inodes as being part of that tree - which sets inode\n" " flags and the project identifier on every file.\n" " Once this has been done, new files created in the tree will automatically\n" " be accounted to the tree based on their project identifier. An attempt to\n" " create a hard link to a file in the tree will only succeed if the project\n" " identifier matches the project identifier for the tree. The xfs_io " "utility\n" " can be used to set the project ID for an arbitrary file, but this can only\n" " be done by a privileged user.\n" "\n" " A previously setup tree can be cleared from project quota control through\n" " use of the -C option, which will recursively descend the tree, clearing\n" " the affected inodes from project quota control.\n" "\n" " The -c option can be used to check whether a tree is setup, it reports\n" " nothing if the tree is correct, otherwise it reports the paths of inodes\n" " which do not have the project ID of the rest of the tree, or if the inode\n" " flag is not set.\n" "\n" " The -p option can be used to manually specify project path without\n" " need to create /etc/projects file. This option can be used multiple times\n" " to specify multiple paths. When using this option only one projid/name can\n" " be specified at command line. Note that /etc/projects is also used if " "exists.\n" "\n" " The -d option allows to descend at most levels of " "directories\n" " below the command line arguments. -d 0 means only apply the actions\n" " to the top level of the projects. -d -1 means no recursion limit " "(default).\n" "\n" " The /etc/projid and /etc/projects file formats are simple, and described\n" " on the xfs_quota man page.\n" "\n" msgstr "" "\n" " Projekte auflisten oder einen Projektbaum für eine\n" " Baum-Quota-Verwaltung einrichten\n" "\n" " Beispiel:\n" " 'project -c Protokolldateien'\n" " (ordnet das Projekt »Protokolldateien« einem Verzeichnis zu und richtet\n" " den Verzeichnis-Baum ein)\n" "\n" " Ohne Argumente werden alle Projekte ausgegeben, die in der Datei\n" " /etc/projects gefunden werden.\n" " Der Projekt-Quota-Mechanismus von XFS kann benutzt werden um eine\n" " Form von Verzeichnis-Baum-Quotas umzusetzen, bei der ein angegebenes\n" " Verzeichnis und alle Dateien und Unterverzeichnisse unterhalb (z.B. ein \n" " Baum) darauf beschränkt werden können, eine Teilmenge des verfügbaren\n" " Speichers des Dateisystems zu benutzen\n" "\n" " Ein verwalteter Baum muss zuerst unter Benutzung der Option -c mit\n" " einem Projekt eingerichtet werden. Der angebegenen Projektname oder\n" " Bezeichner passt zu einem oder mehreren in /etc/projects definierten\n" " Bäumen und in diese Bäume wird rekursiv abgestiegen um die betroffenen\n" " Inodes durch Setzen von Inode-Kennzeichnungen und dem\n" " Projekt-Bezeichner für jede Datei als Teil des Baumes zu markieren\n" " Wenn dies erledigt ist, werden neu im Baum erstellte Dateien\n" " automatisch auf dem Baum ausgewiesen, der auf ihrem Projekt-Bezeichner\n" " basiert. Ein Versuch einen harten Verweis zu einer Datei im Baum zu\n" " erstellen hat nur Erfolg, wenn der Projekt-Bezeichner mit dem\n" " Projekt-Bezeichner im Baum übereinstimmt. Das »xfs-io«-Programm kann\n" " benutzt werden um eine Projekt-ID für eine beliebige Datei zu setzen,\n" " aber dies kann nur durch einen berechtigen Anwender getan werden.\n" "\n" " Ein vorheriger Einrichtungs-Baum kann mit der Option -C aus der\n" " Projekt-Quota-Kontrolle entfernt werden, die rekursiv den Baum\n" " hinabsteigt und die betroffenen Inodes von der\n" " Projekt-Quota-Kontrolle befreit.\n" "\n" " Die »-c«-Option kann benutzt werden um prüfen, ob ein Baum eingerichtet\n" " ist. Sie gibt nichts aus, wenn der Baum korrekt ist. Andernfalls gibt\n" " sie den Pfad der Inodes an, die nicht die Projekt-ID des restlichen\n" " Baumes hat oder ob die Inode-Kennzeichnung nicht gesetzt ist.\n" "\n" "Die -Option -p kann benutzt werden, um manuell den Projektpfad\n" "anzugeben, ohne dass es nötig ist, die Datei /etc/projects zu erstellen.\n" "Diese Option kann mehrmals benutzt werden, um mehrere Pfade zu erstellen.\n" "Wenn diese Option benutzt wird kann nur eine projid/Name auf der\n" "Befehlszeile angegeben werden. Beachten Sie, dass außerden /etc/projects\n" "benutzt wird, wenn es existiert.\n" "\n" "Die -Option -d erlaub es, die meisten >Tiefe>-Stufen der\n" "Verzeichnisse unterhalb der Befehlszeilenargumente hinabzusteigen.\n" "-d 0 bedeutet, dass nur die Aktionen der obersten Stufe des Projekts\n" "abgefragt werden. d -1 bedeutet keine Rekursionsbeschränkung (Vorgabe).\n" "\n" " Die Formate der Dateien /etc/projid und /etc/projects sind einfach. Sie\n" " werden auf der »xfs_quota«-Handbuchseite beschrieben.\n" "\n" #: .././quota/project.c:108 .././quota/project.c:153 .././quota/project.c:200 #, c-format msgid "%s: cannot stat file %s\n" msgstr "%s: kann Status für »%s« nicht abfragen\n" #: .././quota/project.c:112 .././quota/project.c:157 .././quota/project.c:204 #, c-format msgid "%s: skipping special file %s\n" msgstr "%s: Spezialdatei %s wird übersprungen\n" #: .././quota/project.c:126 #, c-format msgid "%s - project identifier is not set (inode=%u, tree=%u)\n" msgstr "%s - Projekt-Bezeichner ist nicht gesetzt (Inode=%u, Baum=%u)\n" #: .././quota/project.c:130 #, c-format msgid "%s - project inheritance flag is not set\n" msgstr "%s - Projekt-Vererbungs-Markierung ist nicht gesetzt\n" #: .././quota/project.c:178 #, c-format msgid "%s: cannot clear project on %s: %s\n" msgstr "%s: Projekt auf %s kann nicht bereinigt werden: %s\n" #: .././quota/project.c:225 #, c-format msgid "%s: cannot set project on %s: %s\n" msgstr "%s: Projekt auf %s kann nicht gesetzt werden: %s\n" #: .././quota/project.c:240 #, c-format msgid "Checking project %s (path %s)...\n" msgstr "Projekt %s wird geprüft (Pfad %s)...\n" #: .././quota/project.c:244 #, c-format msgid "Setting up project %s (path %s)...\n" msgstr "Projekt-Pfad %s wird eingerichtet (Pfad %s)...\n" #: .././quota/project.c:248 #, c-format msgid "Clearing project %s (path %s)...\n" msgstr "Projekt-Pfad %s wird bereinigt (Pfad %s)...\n" #: .././quota/project.c:271 #, c-format msgid "" "Processed %d (%s and cmdline) paths for project %s with recursion depth %s (%" "d).\n" msgstr "" "Es wurden %d (%s und Befehlszeile) Pfade für Projekt %s mit\n" "Rekursionstiefe %s (%d) verarbeitet.\n" #: .././quota/project.c:273 msgid "infinite" msgstr "unendlich" #: .././quota/project.c:273 msgid "limited" msgstr "beschränkt" #: .././quota/project.c:318 #, c-format msgid "projects file \"%s\" doesn't exist\n" msgstr "Projektdatei »%s« existiert nicht\n" #: .././quota/project.c:325 #, c-format msgid "" "%s: only one projid/name can be specified when using -p , %d found.\n" msgstr "" "%s: Nur ein projid/Name kann angegeben werden, wenn -p benutzt\n" "wird, %d gefunden.\n" #: .././quota/project.c:334 #, c-format msgid "%s - no such project in %s\n" msgstr "%s - kein derartiges Projekt in %s\n" #: .././quota/project.c:348 msgid "tree" msgstr "Baum" #: .././quota/project.c:350 msgid "[-c|-s|-C|-d |-p ] project ..." msgstr "[-c|-s|-C|-d |-p ] Projekt ..." #: .././quota/project.c:353 msgid "check, setup or clear project quota trees" msgstr "Projekt-Quota-Bäume prüfen, einrichten oder bereinigen " #: .././quota/quot.c:55 #, c-format msgid "" "\n" " display a summary of filesystem ownership\n" "\n" " -a -- summarise for all local XFS filesystem mount points\n" " -c -- display three columns giving file size in kilobytes, number of files\n" " of that size, and cumulative total of kilobytes in that size or\n" " smaller file. The last row is used as an overflow bucket and is the\n" " total of all files greater than 500 kilobytes.\n" " -v -- display three columns containing the number of kilobytes not\n" " accessed in the last 30, 60, and 90 days.\n" " -g -- display group summary\n" " -p -- display project summary\n" " -u -- display user summary\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n" msgstr "" "\n" " zeigt eine Übersicht des Eigentums am Dateisystem\n" "\n" " -a -- Summe für alle lokalen XFS-Einhängepunkte bilden\n" " -c -- zeigt drei Spalten mit Dateigröße in Kilobyte, Anzahl der Dateien\n" " mit dieser Größe und zusammengezählter Gesamtzahl von Kilobytes\n" " von Dateien mit dieser Größe oder kleinerer Dateien. Die letzte\n" " Reihe wird als Überlauf benutzt und besteht aus der Gesamtheit\n" " aller Dateien mit mehr als 500 Kilobyte.\n" " -v -- zeigt drei Spalten, die die Anzahl der Kilobytes enthalten, auf\n" " die in den letzten 30, 60 und 90 Tagen nicht zugegriffen wurde.\n" " -g -- Gruppen-Zusammenfassung anzeigen\n" " -p -- Projekt-Zusammenfassung anzeigen\n" " -u -- Benutzer-Zusammenfassung anzeigen\n" " -b -- Anzahl benutzter Blöcke anzeigen\n" " -i -- Anzahl benutzter Inodes anzeigen\n" " -r -- Anzahl benutzter Echtzeit-Blöcke anzeigen\n" " -n -- Übersetzung von Bezeichnern zu Namen überspringen, nur IDs\n" " ausgeben\n" " -N -- einleitende Kopfzeilen unterdrücken\n" " -f -- Ausgabe in eine Datei umleiten\n" " Der (optionale) Benutzer/Gruppe/Projekt an entweder durch Name oder\n" " Nummer (z.B. uid/gid/projid) angegeben werden.\n" "\n" #: .././quota/quot.c:219 #, c-format msgid "%s (%s) %s:\n" msgstr "%s (%s) %s:\n" #: .././quota/quot.c:295 #, c-format msgid "%s (%s):\n" msgstr "%s (%s):\n" #: .././quota/quot.c:300 .././quota/quot.c:304 #, c-format msgid "%d\t%llu\t%llu\n" msgstr "%d\t%llu\t%llu\n" #: .././quota/quot.c:414 msgid "quot" msgstr "quot" #: .././quota/quot.c:418 msgid "[-bir] [-gpu] [-acv] [-f file]" msgstr "[-bir] [-gpu] [-acv] [-f Datei]" #: .././quota/quot.c:419 msgid "summarize filesystem ownership" msgstr "Übersicht des Eigentums am Dateisystem" #: .././quota/quota.c:32 #, c-format msgid "" "\n" " display usage and quota information\n" "\n" " -g -- display group quota information\n" " -p -- display project quota information\n" " -u -- display user quota information\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -v -- increase verbosity in reporting (also dumps zero values)\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n" msgstr "" "\n" " zeige Benutzungs- und Quota-Information\n" "\n" " -g -- zeige Gruppen-Quota-Information\n" " -p -- zeige Projekt-Quota-Information\n" " -u -- zeige Benutzer-Quota-Information\n" " -b -- Anzahl benutzter Blöcke anzeigen\n" " -i -- Anzahl benutzter Inodes anzeigen\n" " -r -- Anzahl benutzter Echtzeit-Blöcke anzeigen\n" " -h -- in für Menschen lesbarem Format ausgeben\n" " -n -- Übersetzung von Bezeichnern zu Namen überspringen, nur IDs\n" " ausgeben\n" " -N -- einleitende Kopfzeilen unterdrücken\n" " -v -- Ausführlichkeit der Ausgabe der Meldungen erhöhen (außerdem\n" " Nullwerte ausgeben)\n" " -f -- Ausgabe in eine Datei umleiten\n" " Der (optionale) Benutzer/Gruppe/Projekt an entweder durch Name oder\n" " Nummer (z.B. uid/gid/projid) angegeben werden.\n" "\n" #: .././quota/quota.c:85 #, c-format msgid "" "Disk quotas for %s %s (%u)\n" "Filesystem%s" msgstr "" "Platten-Quotas für %s %s (%u)\n" "Dateisystem%s" #: .././quota/quota.c:90 #, c-format msgid " Blocks Quota Limit Warn/Time " msgstr " Blöcke Quota Begrenzung Warnung/Zeit" #: .././quota/quota.c:91 #, c-format msgid " Blocks Quota Limit Warn/Time " msgstr " Blöcke Quota Begrenzung Warnung/Zeit " #: .././quota/quota.c:94 #, c-format msgid " Files Quota Limit Warn/Time " msgstr " Dateien Quota Begrenzung Warnung/Zeit" #: .././quota/quota.c:95 #, c-format msgid " Files Quota Limit Warn/Time " msgstr " Dateien Quota Begrenzung Warnung/Zeit " #: .././quota/quota.c:98 #, c-format msgid "Realtime Quota Limit Warn/Time " msgstr "Echtzeit Quota Begrenzung Warnung/Zeit" #: .././quota/quota.c:99 #, c-format msgid " Realtime Quota Limit Warn/Time " msgstr " Echtzeit Quota Begrenzung Warnung/Zeit " #: .././quota/quota.c:235 #, c-format msgid "%s: cannot find user %s\n" msgstr "%s: Benutzer %s kann nicht gefunden werden\n" #: .././quota/quota.c:285 #, c-format msgid "%s: cannot find group %s\n" msgstr "%s: Gruppe %s kann nicht gefunden werden\n" #: .././quota/quota.c:342 #, c-format msgid "%s: must specify a project name/ID\n" msgstr "%s: ein Projektname/ID muss angegeben werden\n" #: .././quota/quota.c:355 #, c-format msgid "%s: cannot find project %s\n" msgstr "%s: Projekt %s kann nicht gefunden werden\n" #: .././quota/quota.c:455 msgid "quota" msgstr "Quota" #: .././quota/quota.c:456 msgid "l" msgstr "l" #: .././quota/quota.c:460 msgid "[-bir] [-gpu] [-hnNv] [-f file] [id|name]..." msgstr "[-bir] [-gpu] [-hnNv] [-f Datei] [id|name]..." #: .././quota/quota.c:461 msgid "show usage and limits" msgstr "zeige Aufruf und Beschränkungen" #: .././quota/report.c:34 .././quota/report.c:648 msgid "dump quota information for backup utilities" msgstr "Auszug der Quota-Information für Sicherungsprogramm anzeigen" #: .././quota/report.c:36 #, c-format msgid "" "\n" " create a backup file which contains quota limits information\n" " -g -- dump out group quota limits\n" " -p -- dump out project quota limits\n" " -u -- dump out user quota limits (default)\n" " -f -- write the dump out to the specified file\n" "\n" msgstr "" "\n" " eine Sicherungsdatei erzeugen, die Quota-Begrenzung-Informationen\n" " enthält\n" " -g -- Auszug von Gruppen-Quota-Begrenzungen\n" " -p -- Auszug von Projekt-Quota-Begrenzungen\n" " -u -- Auszug von Benutzer-Quota-Begrenzungen (Standard)\n" " -f -- den Auszug in eine angegebene Datei schreiben\n" "\n" #: .././quota/report.c:48 msgid "[-bir] [-gpu] [-ahntLNU] [-f file]" msgstr "[-bir] [-gpu] [-ahntLNU] [-f Datei]" #: .././quota/report.c:49 .././quota/report.c:657 msgid "report filesystem quota information" msgstr "Quota-Information des Dateisystems ausgeben" #: .././quota/report.c:51 #, c-format msgid "" "\n" " report used space and inodes, and quota limits, for a filesystem\n" " Example:\n" " 'report -igh'\n" " (reports inode usage for all groups, in an easy-to-read format)\n" " This command is the equivalent of the traditional repquota command, which\n" " prints a summary of the disk usage and quotas for the current filesystem,\n" " or all filesystems.\n" " -a -- report for all mounted filesystems with quota enabled\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the header from the output\n" " -t -- terse output format, hides rows which are all zero\n" " -L -- lower ID bound to report on\n" " -U -- upper ID bound to report on\n" " -g -- report group usage and quota information\n" " -p -- report project usage and quota information\n" " -u -- report user usage and quota information\n" " -b -- report blocks-used information only\n" " -i -- report inodes-used information only\n" " -r -- report realtime-blocks-used information only\n" "\n" msgstr "" "\n" " benutzten Speicher und Inodes und Quota-Beschränkungen für ein\n" " Dateisystem ausgeben\n" " Beispiel:\n" " 'report -igh'\n" " (gibt Inode-Nutzung für alle Gruppen in einfach lesbarem Format aus)\n" " Dieser Befehl entspricht dem traditionellen repquota-Befehl, der eine\n" " Zusammenfassung der Plattenbelegung und Quotas für das derzeitige\n" " Dateisystem oder alle Dateisysteme ausgibt.\n" " -a -- alle eingehängten Dateisysteme mit eingeschaltetem Quota\n" " anzeigen\n" " -h -- Anzeige in einem für Menschen lesbaren Format\n" " -n -- Übersetzung von Bezeichnern zu Namen überspringen, nur IDs\n" " ausgeben\n" " -N -- die Kopfzeilen in der Ausgabe unterdrücken\n" " -t -- kurzes Ausgabeformat, Zeilen, die nur Null enthalten, unterdrücken\n" " -L -- zeigt untere an den Bericht gebundene ID\n" " -U -- zeigt obere an den Bericht gebundene ID\n" " -g -- zeigt Gruppen-Nutzung und Quota-Information\n" " -p -- zeigt Projekt-Nutzung und Quota-Information\n" " -u -- zeigt Benutzer--Nutzung und Quota-Information\n" " -b -- zeigt nur Information über benutzte Blöcke\n" " -i -- zeigt nur Information über benutzte Inodes\n" " -r -- zeigt nur Information über benutzte Echtzeit-Blöcke\n" "\n" #: .././quota/report.c:228 #, c-format msgid "%s quota on %s (%s)\n" msgstr "%s Quota auf %s (%s)\n" #: .././quota/report.c:253 .././quota/report.c:261 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr " Benutzt Weich Hart Warnung/Gnadenfrist" #: .././quota/report.c:254 .././quota/report.c:262 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr " Benutzt Weich Hart Warnung/Gnadenfrist" #: .././quota/report.c:257 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr " Benutzt Weich Hart Warnung/Gnadenfrist" #: .././quota/report.c:258 #, c-format msgid " Used Soft Hard Warn/ Grace " msgstr " Benutzt Weich Hart Warnung/Gnadenfrist" #: .././quota/report.c:643 msgid "dump" msgstr "Ausgabe" #: .././quota/report.c:651 msgid "report" msgstr "Bericht" #: .././quota/report.c:652 msgid "repquota" msgstr "repquota" #: .././quota/report.c:656 msgid "[-bir] [-gpu] [-ahnt] [-f file]" msgstr "[-bir] [-gpu] [-ahnt] [-f Datei]" #: .././quota/state.c:33 #, c-format msgid "" "\n" " turn filesystem quota off, both accounting and enforcement\n" "\n" " Example:\n" " 'off -uv' (switch off user quota on the current filesystem)\n" " This command is the equivalent of the traditional quotaoff command,\n" " which disables quota completely on a mounted filesystem.\n" " Note that there is no 'on' command - for XFS filesystems (with the\n" " exception of the root filesystem on IRIX) quota can only be enabled\n" " at mount time, through the use of one of the quota mount options.\n" "\n" " The state command is useful for displaying the current state. Using\n" " the -v (verbose) option with the 'off' command will display the quota\n" " state for the affected filesystem once the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " Dateisystem-Quota ausschalten, sowohl Kontenführung als auch\n" " Vollstreckung\n" "\n" " Beispiel:\n" " 'off -uv' (schaltet Benutzer-Quota auf dem derzeitigen Dateisystem aus)\n" " Dieser Befehl entspricht dem traditionellen quotaoff-Befehl, der\n" " das Quota auf eingehängten Dateisystemen gänzlich abschaltet\n" " Merken sie sich, dass es keinen »an«-Befehl gibt - für XFS-Dateisysteme\n" " (mit Ausnahme des Wurzel-Dateisystems auf IRIX) kann Quota\n" " zur Einhängezeit durch Benutzung einer der\n" " Einhänge-Quota-Optionen eingeschaltet werden\n" "\n" " Der Status-Befehl ist nützlich zur Anzeige des gegenwärtigen Status.\n" " Die Benutzung der »-v«-Option (detailliert) mit dem »off«-Befehl gibt\n" " den Quota-Status für das betroffene Dateisystem aus, bis der\n" " Arbeitsvorgang komplett ist. Der betroffene Quota-Typ ist\n" " -g (Gruppen), -p (Projekte) oder -u (Benutzer) und Standard ist\n" " Benutzer-Quota (mehrere Typen können angegeben werden).\n" "\n" #: .././quota/state.c:56 #, c-format msgid "" "\n" " query the state of quota on the current filesystem\n" "\n" " This is a verbose status command, reporting whether or not accounting\n" " and/or enforcement are enabled for a filesystem, which inodes are in\n" " use as the quota state inodes, and how many extents and blocks are\n" " presently being used to hold that information.\n" " The quota type is specified via -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " den Status der Quota auf dem aktuellen Dateisystem abfragen\n" "\n" " Dies ist ein detailreicher Status-Befehl, der ausgibt, ob Kontierung\n" " und Vollstreckung für ein Dateisystem, dessen Inodes als\n" " Quota-Status-Inode in Gebrauch sind, eingeschaltet ist oder nicht\n" " und wie viele Erweiterungen und Blöcke derzeit benutzt werden, um diese\n" " Information aufzubewahren.\n" " Der Quota-Typ ist angegeben mittels -g (Gruppen), -p (Projekte)\n" " oder -u (Benutzer) und Standard ist Benutzer-Quota (mehrere\n" " Typen können angegeben werden).\n" "\n" #: .././quota/state.c:72 #, c-format msgid "" "\n" " enable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and has quota accounting enabled, but not\n" " quota enforcement, enforcement can be enabled with this command.\n" " With the -v (verbose) option, the status of the filesystem will be\n" " reported after the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " schaltet Quota-Erzwingung auf einem Dateisystem ein\n" "\n" " Wenn ein Dateisystem eingehängt und Quota eingeschaltet ist, aber keine \n" " Quota-Erzwingung, kann die Erzwingung mit diesem Befehl eingeschaltet\n" " werden. Mit der »-v«-Option (detailliert) wird der Status des\n" " Dateisystems nach Abschluss der Arbeitsgangs angezeigt.\n" " Der betroffene Quota-Typ ist -g (Gruppen), -p (Projekte) oder\n" " -u (Benutzer) und Standard ist Benutzer-Quota (mehrere Typen können\n" " angegeben werden).\n" #: .././quota/state.c:88 #, c-format msgid "" "\n" " disable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and is currently enforcing quota, this\n" " provides a mechanism to switch off the enforcement, but continue to\n" " perform used space (and used inodes) accounting.\n" " The affected quota type is -g (groups), -p (projects) or -u (users).\n" "\n" msgstr "" "\n" " schaltet Quota-Erzwingung auf einem Dateisystem aus\n" "\n" " Wenn ein Dateisystem eingehängt ist und derzeit Quota erzwingt,\n" " stellt dies einen Mechanismus zur Verfügung um die Erzwingung\n" " auszuschalten aber mit der Kontierung von benutztem Speicher (und\n" " benutzter Inodes) fortzufahren.\n" " Der betroffene Quota-Typ ist -g (Gruppen), -p (Projekte) oder\n" " -u (Benutzer).\n" "\n" #: .././quota/state.c:102 #, c-format msgid "" "\n" " remove any space being used by the quota subsystem\n" "\n" " Once quota has been switched 'off' on a filesystem, the space that\n" " was allocated to holding quota metadata can be freed via this command.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " durch das Quota-Untersystem benutzten Speicher freigeben\n" "\n" " Wenn das Quota auf einem Dateisystem ausgeschaltet wurde, kann der\n" " Speicher, der für die Quota-Metadaten zugeteilt wurde mit diesem Befehl\n" " freigegeben werden. Der betroffene Quota-Typ ist -g (Gruppen),\n" " -p (Projekte) oder -u (Benutzer) und Standard ist Benutzer-Quotaierung\n" " (mehrere Typen können angegeben werden)..\n" "\n" #: .././quota/state.c:121 #, c-format msgid "%s quota state on %s (%s)\n" msgstr "%s Quota-Status auf %s (%s)\n" #: .././quota/state.c:123 #, c-format msgid " Accounting: %s\n" msgstr "Kontierung: %s\n" #: .././quota/state.c:123 .././quota/state.c:124 msgid "ON" msgstr "AN" #: .././quota/state.c:123 .././quota/state.c:124 msgid "OFF" msgstr "AUS" #: .././quota/state.c:124 #, c-format msgid " Enforcement: %s\n" msgstr " Vollstreckung: %s\n" #: .././quota/state.c:125 #, c-format msgid " Inode: #%llu (%llu blocks, %lu extents)\n" msgstr " Inode: #%llu (%llu Blöcke, %lu Erweiterungen)\n" #: .././quota/state.c:137 #, c-format msgid "%s grace time: %s\n" msgstr "%s Gnadenfrist: %s\n" #: .././quota/state.c:154 #, c-format msgid "%s quota are not enabled on %s\n" msgstr "%s Quota ist auf %s nicht eingeschaltet\n" #: .././quota/state.c:524 .././quota/state.c:540 .././quota/state.c:548 #: .././quota/state.c:556 msgid "[-gpu] [-v]" msgstr "[-gpu] [-v]" #: .././quota/state.c:525 msgid "permanently switch quota off for a path" msgstr "Quota für den Pfad dauerhaft ausschalten" #: .././quota/state.c:528 msgid "state" msgstr "Status" #: .././quota/state.c:532 msgid "[-gpu] [-a] [-v] [-f file]" msgstr "[-gpu] [-a] [-v] [-f Datei]" #: .././quota/state.c:533 msgid "get overall quota state information" msgstr "umfassende Quota-Information erhalten" #: .././quota/state.c:536 msgid "enable" msgstr "einschalten" #: .././quota/state.c:541 msgid "enable quota enforcement" msgstr "Quota-Erzwingung einschalten" #: .././quota/state.c:544 msgid "disable" msgstr "ausschalten" #: .././quota/state.c:549 msgid "disable quota enforcement" msgstr "Quota-Erzwingung ausschalten" #: .././quota/state.c:552 msgid "remove" msgstr "entfernen" #: .././quota/state.c:557 msgid "remove quota extents from a filesystem" msgstr "Quota-Erweiterungen aus einem Dateisystem entfernen" #: .././quota/util.c:59 #, c-format msgid "[-none-]" msgstr "[-keins-]" #: .././quota/util.c:59 #, c-format msgid "[--none--]" msgstr "[--keins--]" #: .././quota/util.c:62 #, c-format msgid "[------]" msgstr "[------]" #: .././quota/util.c:62 #, c-format msgid "[--------]" msgstr "[--------]" #: .././quota/util.c:66 .././quota/util.c:69 msgid "day" msgstr "Tag" #: .././quota/util.c:66 .././quota/util.c:69 msgid "days" msgstr "Tage" #: .././quota/util.c:194 msgid "Blocks" msgstr "Blöcke" #: .././quota/util.c:194 msgid "Inodes" msgstr "Inodes" #: .././quota/util.c:194 msgid "Realtime Blocks" msgstr "Echtzeit-Blöcke" #: .././quota/util.c:209 msgid "User" msgstr "Benutzer" #: .././quota/util.c:209 msgid "Group" msgstr "Gruppe" #: .././quota/util.c:209 msgid "Project" msgstr "Projekt" #: .././quota/util.c:417 #, c-format msgid "%s: open on %s failed: %s\n" msgstr "%s: Öffnen auf %s fehlgeschlagen: %s\n" #: .././quota/util.c:423 #, c-format msgid "%s: fdopen on %s failed: %s\n" msgstr "%s: fdopen auf %s fehlgeschlagen: %s\n" #: .././repair/incore_ino.c:196 .././repair/incore_ino.c:205 #: .././repair/incore_ino.c:222 .././repair/incore_ino.c:231 msgid "could not allocate expanded nlink array\n" msgstr "erweiterte nlink-Matrix kann nicht alloziert werden.\n" #: .././repair/incore_ino.c:268 msgid "inode map malloc failed\n" msgstr "Inode map malloc fehlgeschlagen\n" #: .././repair/incore_ino.c:298 msgid "could not allocate nlink array\n" msgstr "nlink-Matrix kann nicht alloziert werden.\n" #: .././repair/incore_ino.c:390 msgid "add_aginode_uncertain - duplicate inode range\n" msgstr "add_aginode_uncertain - doppelter Inode-Bereich\n" #: .././repair/incore_ino.c:488 msgid "add_inode - duplicate inode range\n" msgstr "add_inode - doppelter Inode-Bereich\n" #: .././repair/incore_ino.c:579 #, c-format msgid "good inode list is --\n" msgstr "gute Inode-Liste ist --\n" #: .././repair/incore_ino.c:582 #, c-format msgid "uncertain inode list is --\n" msgstr "unsichere Inode-Liste ist --\n" #: .././repair/incore_ino.c:587 #, c-format msgid "agno %d -- no inodes\n" msgstr "agno %d -- keine Inodes\n" #: .././repair/incore_ino.c:591 #, c-format msgid "agno %d\n" msgstr "agno %d\n" #: .././repair/incore_ino.c:595 #, c-format msgid "\tptr = %lx, start = 0x%x, free = 0x%llx, confirmed = 0x%llx\n" msgstr "\tptr = %lx, Start = 0x%x, frei = 0x%llx, bestätigt = 0x%llx\n" #: .././repair/incore_ino.c:646 msgid "couldn't malloc parent list table\n" msgstr "malloc von Elternlistentabelle konnte nicht durchgeführt werden\n" #: .././repair/incore_ino.c:657 .././repair/incore_ino.c:703 msgid "couldn't memalign pentries table\n" msgstr "memalign von pentries-Tabelle konnte nicht durchgeführt werden\n" #: .././repair/incore_ino.c:761 .././repair/incore_ino.c:767 msgid "could not malloc inode extra data\n" msgstr "malloc von Inode-Extradaten konnte nicht durchgeführt werden\n" #: .././repair/incore_ino.c:815 msgid "couldn't malloc inode tree descriptor table\n" msgstr "" "malloc von Inode-Datei-Deskriptor-Tabelle konnte nicht durchgeführt werden\n" #: .././repair/incore_ino.c:819 msgid "couldn't malloc uncertain ino tree descriptor table\n" msgstr "malloc von unbestimmter ino-Baum-Deskriptor-Tabelle konnte nicht\n" "durchgeführt werden\n" #: .././repair/incore_ino.c:824 msgid "couldn't malloc inode tree descriptor\n" msgstr "malloc von Baum-Deskriptor konnte nicht durchgeführt werden\n" #: .././repair/incore_ino.c:828 msgid "couldn't malloc uncertain ino tree descriptor\n" msgstr "" "malloc von unbestimmtem ino-Baum-Deskriptor konnte nicht durchgeführt\n" "werden\n" #: .././repair/incore_ino.c:839 msgid "couldn't malloc uncertain inode cache area\n" msgstr "" "malloc von unbestimmtem Inode-Zwischenspeicherbereich konnte nicht\n" "durchgeführt werden\n" #: .././repair/phase1.c:28 msgid "Sorry, could not find valid secondary superblock\n" msgstr "" "Entschuldigung, gültiger zweiter Superblock kann nicht gefunden werden\n" #: .././repair/phase1.c:29 msgid "Exiting now.\n" msgstr "Wird beendet.\n" #: .././repair/phase1.c:40 #, c-format msgid "could not allocate ag header buffer (%d bytes)\n" msgstr "ag-Kopf-Puffer (%d Bytes) kann nicht alloziert werden\n" #: .././repair/phase1.c:58 msgid "Phase 1 - find and verify superblock...\n" msgstr "Phase 1 - Superblock finden und überprüfen...\n" #: .././repair/phase1.c:74 msgid "error reading primary superblock\n" msgstr "Fehler beim Lesen des primären Superblocks\n" #: .././repair/phase1.c:80 #, c-format msgid "bad primary superblock - %s !!!\n" msgstr "falscher primärer Superblock - %s !!!\n" #: .././repair/phase1.c:87 #, c-format msgid "couldn't verify primary superblock - %s !!!\n" msgstr "primärer Superblock kann nicht überprüft werden - %s !!!\n" #: .././repair/phase1.c:105 msgid "superblock has a features2 mismatch, correcting\n" msgstr "" "Superblock hat eine fehlende features2-Übereinstimmung, wird berichtigt\n" #: .././repair/phase1.c:121 #, c-format msgid "Enabling lazy-counters\n" msgstr "Schalte lazy-counters ein\n" #: .././repair/phase1.c:125 #, c-format msgid "Disabling lazy-counters\n" msgstr "lazy-counters werden ausgeschaltet\n" #: .././repair/phase1.c:128 #, c-format msgid "Lazy-counters are already %s\n" msgstr "Lazy-counters sind bereits %s\n" #: .././repair/phase1.c:129 msgid "enabled" msgstr "eingeschaltet" #: .././repair/phase1.c:129 msgid "disabled" msgstr "ausgeschaltet" #: .././repair/phase1.c:136 msgid "writing modified primary superblock\n" msgstr "Schreiben verändert primären Superblock\n" #: .././repair/phase1.c:139 msgid "would write modified primary superblock\n" msgstr "Schreiben könnte primären Superblock verändern\n" #: .././repair/phase4.c:125 .././repair/phase5.c:1439 .././repair/phase3.c:160 #: .././repair/phase6.c:3595 #, c-format msgid " - agno = %d\n" msgstr " - agno = %d\n" #: .././repair/phase4.c:205 msgid "Phase 4 - check for duplicate blocks...\n" msgstr "Phase 4 - auf doppelte Blöcke überprüfen...\n" #: .././repair/phase4.c:206 msgid " - setting up duplicate extent list...\n" msgstr " - Liste mit doppeltem Ausmaß wird eingerichtet...\n" #: .././repair/phase4.c:220 msgid "root inode would be lost\n" msgstr "Wurzel-Inode könnte verloren worden sein\n" #: .././repair/phase4.c:222 msgid "root inode lost\n" msgstr "Wurzel-Inode wurde verloren\n" #: .././repair/phase4.c:256 #, c-format msgid "unknown block state, ag %d, block %d\n" msgstr "unbekannter Block-Status, ag %d, Block %d\n" #: .././repair/phase4.c:314 #, c-format msgid "unknown rt extent state, extent %llu\n" msgstr "unbekannter rt-Ausmaß-Status, Ausmaß %llu\n" #: .././repair/phase4.c:375 msgid " - check for inodes claiming duplicate blocks...\n" msgstr " - es wird geprüft ob Inodes Blocks doppelt beanspruchen...\n" #: .././repair/avl64.c:1032 .././repair/avl.c:1011 #, c-format msgid "avl_insert: Warning! duplicate range [%llu,%llu]\n" msgstr "avl_insert: Warnung! Doppelter Bereich [%llu,%llu]\n" #: .././repair/avl64.c:1227 .././repair/avl.c:1206 #, c-format msgid "Command [fpdir] : " msgstr "Befehl [fpdir] : " #: .././repair/avl64.c:1236 .././repair/avl.c:1215 #, c-format msgid "end of range ? " msgstr "Ende des Bereichs? " #: .././repair/avl64.c:1247 .././repair/avl.c:1226 #, c-format msgid "Cannot find %d\n" msgstr "%d kann nicht gefunden werden\n" #: .././repair/avl64.c:1260 .././repair/avl.c:1239 #, c-format msgid "size of range ? " msgstr "Größe des Bereichs? " #: .././repair/avl64.c:1271 .././repair/avl.c:1250 #, c-format msgid "End of range ? " msgstr "Ende des Bereichs? " #: .././repair/avl64.c:1275 .././repair/avl.c:1254 #, c-format msgid "checklen 0/1 ? " msgstr "checklen 0/1? " #: .././repair/avl64.c:1282 .././repair/avl.c:1261 #, c-format msgid "Found something\n" msgstr "Etwas gefunden\n" #: .././repair/progress.c:16 msgid "inodes" msgstr "Inodes" #: .././repair/progress.c:20 msgid "directories" msgstr "Verzeichnisse" #: .././repair/progress.c:22 msgid "allocation groups" msgstr "Allokations-Gruppen" #: .././repair/progress.c:24 msgid "AGI unlinked buckets" msgstr "AGI gelöste Verweisbehälter" #: .././repair/progress.c:28 msgid "realtime extents" msgstr "Echtzeitbereiche" #: .././repair/progress.c:30 msgid "unlinked lists" msgstr "unverknüpfte Listen" #: .././repair/progress.c:37 #, c-format msgid " - %02d:%02d:%02d: %s - %llu of %llu %s done\n" msgstr " - %02d:%02d:%02d: %s - %llu von %llu %s erledigt\n" #: .././repair/progress.c:39 #, c-format msgid " - %02d:%02d:%02d: %s - %llu %s done\n" msgstr " - %02d:%02d:%02d: %s - %llu %s erledigt\n" #: .././repair/progress.c:51 msgid "scanning filesystem freespace" msgstr "freier Speicher des Dateisystems wird gescannt" #: .././repair/progress.c:53 msgid "scanning agi unlinked lists" msgstr "unverknüpfte agi-Listen werden gescannt" #: .././repair/progress.c:55 msgid "check uncertain AG inodes" msgstr "einige unklare AG-Inodes werden geprüft" #: .././repair/progress.c:57 msgid "process known inodes and inode discovery" msgstr "bekannte Inodes werden abgearbeitet und Inodes entdeckt" #: .././repair/progress.c:59 msgid "process newly discovered inodes" msgstr "neu entdeckte Inodes werden abgearbeitet" #: .././repair/progress.c:61 msgid "setting up duplicate extent list" msgstr "Liste mit doppelten Bereichen wird eingerichtet" #: .././repair/progress.c:63 msgid "initialize realtime bitmap" msgstr "Echtzeit-Bitmap wird initialisiert" #: .././repair/progress.c:65 msgid "reset realtime bitmaps" msgstr "Echtzeit-Bitmap wird zurückgesetzt" #: .././repair/progress.c:67 msgid "check for inodes claiming duplicate blocks" msgstr "es wird geprüft, ob Inodes doppelte Blöcke beanspruchen" #: .././repair/progress.c:69 msgid "rebuild AG headers and trees" msgstr "AG-Köpfe und Bäume werden neu erstellt" #: .././repair/progress.c:71 msgid "traversing filesystem" msgstr "Dateisystem wird durchquert" #: .././repair/progress.c:73 msgid "traversing all unattached subtrees" msgstr "alle unabhängigen Unterbäume werden durchquert" #: .././repair/progress.c:75 msgid "moving disconnected inodes to lost+found" msgstr "nicht verbundene Inodes werden nach lost+found verschoben" #: .././repair/progress.c:77 msgid "verify and correct link counts" msgstr "Verweisanzahl wird geprüft und berichtigt" #: .././repair/progress.c:79 msgid "verify link counts" msgstr "Verweisanzahl wird geprüft" #: .././repair/progress.c:118 msgid "cannot malloc pointer to done vector\n" msgstr "malloc von Zeiger auf erledigten Vektor nicht möglich\n" #: .././repair/progress.c:134 msgid "unable to create progress report thread\n" msgstr "außerstande einen Fortschritts-Bericht-Thread zu erzeugen\n" #: .././repair/progress.c:173 msgid "progress_rpt: cannot malloc progress msg buffer\n" msgstr "progress_rpt: malloc Fortschritts-msg-Puffer\n" #: .././repair/progress.c:187 msgid "progress_rpt: cannot create timer\n" msgstr "progress_rpt: Zeitnehmer kann nicht erzeugt werden\n" #: .././repair/progress.c:190 msgid "progress_rpt: cannot set timer\n" msgstr "progress_rpt: Zeitnehmer kann nicht gesetzt werden\n" #: .././repair/progress.c:214 msgid "progress_rpt: cannot lock progress mutex\n" msgstr "progress_rpt: mutex-Fortschritt kann nicht gesperrt werden\n" #: .././repair/progress.c:251 .././repair/progress.c:354 #, c-format msgid "%s" msgstr "%s" #: .././repair/progress.c:259 #, c-format msgid "" "\t- %02d:%02d:%02d: Phase %d: elapsed time %s - processed %d %s per minute\n" msgstr "" "\t- %02d:%02d:%02d: Phase %d: verstrichene Zeit %s - %d abgearbeitet %s\n" "pro Minute\n" #: .././repair/progress.c:264 #, c-format msgid "" "\t- %02d:%02d:%02d: Phase %d: %llu%% done - estimated remaining time %s\n" msgstr "" "\t- %02d:%02d:%02d: Phase %d: %llu%% erledigt - geschätzte verbleibende\n" "Zeit %s\n" #: .././repair/progress.c:272 msgid "progress_rpt: error unlock msg mutex\n" msgstr "progress_rpt: Fehler beim Entsperren von msg mutex\n" #: .././repair/progress.c:278 msgid "cannot delete timer\n" msgstr "Zeitnehmer kann nicht gelöscht werden\n" #: .././repair/progress.c:292 msgid "set_progress_msg: cannot lock progress mutex\n" msgstr "set_progress_msg: Mutex-Fortschritt kann nicht gesperrt werden\n" #: .././repair/progress.c:302 msgid "set_progress_msg: cannot unlock progress mutex\n" msgstr "set_progress_msg: Mutex-Fortschritt kann nicht entsperrt werden\n" #: .././repair/progress.c:322 msgid "print_final_rpt: cannot lock progress mutex\n" msgstr "print_final_rpt: Mutex-Fortschritt kann nicht gesperrt werden\n" #: .././repair/progress.c:358 msgid "print_final_rpt: cannot unlock progress mutex\n" msgstr "print_final_rpt: Mutex-Fortschritt kann nicht entsperrt werden\n" #: .././repair/progress.c:407 #, c-format msgid "%02d:%02d:%02d" msgstr "%02d:%02d:%02d" #: .././repair/progress.c:429 #, c-format msgid "%d week" msgstr "%d Woche" #: .././repair/progress.c:439 #, c-format msgid "%d day" msgstr "%d Tag" #: .././repair/progress.c:446 .././repair/progress.c:463 #: .././repair/progress.c:481 .././repair/progress.c:491 msgid ", " msgstr ", " #: .././repair/progress.c:455 #, c-format msgid "%d hour" msgstr "%d Stunde" #: .././repair/progress.c:473 #, c-format msgid "%d minute" msgstr "%d Minute" #: .././repair/progress.c:488 #, c-format msgid "%d second" msgstr "%d Sekunde" #: .././repair/progress.c:509 #, c-format msgid "" "\n" " XFS_REPAIR Summary %s\n" msgstr "" "\n" " XFS_REPAIR Zusammenfassung %s\n" #: .././repair/progress.c:511 msgid "Phase\t\tStart\t\tEnd\t\tDuration\n" msgstr "Phase\t\tStart\t\tEnde\t\tDauer\n" #: .././repair/progress.c:516 .././repair/progress.c:519 #, c-format msgid "Phase %d:\tSkipped\n" msgstr "Phase %d:\tÜbersprungen\n" #: .././repair/progress.c:523 #, c-format msgid "Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n" msgstr "Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n" #: .././repair/progress.c:529 #, c-format msgid "" "\n" "Total run time: %s\n" msgstr "" "\n" "Gesamte Laufzeit: %s\n" #: .././repair/sb.c:100 msgid "" "\n" "attempting to find secondary superblock...\n" msgstr "" "\n" "es wird versucht einen zweiten Superblock zu finden...\n" #: .././repair/sb.c:105 msgid "error finding secondary superblock -- failed to memalign buffer\n" msgstr "" "Fehler beim Finden eines zweiten Superblocks -- memalign des Puffers\n" "fehlgeschlagen\n" #: .././repair/sb.c:142 msgid "found candidate secondary superblock...\n" msgstr "Kandidat für zweiten Superblock gefunden...\n" #: .././repair/sb.c:154 msgid "verified secondary superblock...\n" msgstr "zweiter Superblock geprüft...\n" #: .././repair/sb.c:159 msgid "unable to verify superblock, continuing...\n" msgstr "außerstande Superblock zu prüfen, wird fortgesetzt...\n" #: .././repair/sb.c:457 msgid "failed to memalign superblock buffer\n" msgstr "memalign des Superblock-Puffers fehlgeschlagen\n" #: .././repair/sb.c:464 msgid "couldn't seek to offset 0 in filesystem\n" msgstr "Versatz 0 im Dateisystem kann nicht positioniert werden\n" #: .././repair/sb.c:472 msgid "primary superblock write failed!\n" msgstr "Schreiben der primären Superblock fehlgeschlagen!\n" #: .././repair/sb.c:490 #, c-format msgid "error reading superblock %u -- failed to memalign buffer\n" msgstr "" "Fehler beim Lesen des Superblocks %u - memalign des Puffers\n" "fehlgeschlagen\n" #: .././repair/sb.c:500 #, c-format msgid "error reading superblock %u -- seek to offset %lld failed\n" msgstr "" "Fehler beim Lesen des Superblocks %u - positionieren des Versatzes %lld\n" "fehlgeschlagen\n" #: .././repair/sb.c:508 #, c-format msgid "superblock read failed, offset %lld, size %d, ag %u, rval %d\n" msgstr "" "Lesen des Superblocks fehlgeschlagen, Versatz %lld, Größe %d, ag %u,\n" "rval %d\n" #: .././repair/sb.c:556 msgid "couldn't malloc geometry structure\n" msgstr "malloc konnte nicht für Geometriestruktur erfolgen\n" #: .././repair/sb.c:701 msgid "calloc failed in verify_set_primary_sb\n" msgstr "calloc fehlgeschlagen in verify_set_primary_sb\n" #: .././repair/sb.c:772 msgid "" "Only two AGs detected and they do not match - cannot validate filesystem " "geometry.\n" "Use the -o force_geometry option to proceed.\n" msgstr "" "Nur zwei AGs wurden entdeckt und diese passen nicht - die Geometrie des\n" "Dateisystems konnte nicht bestätigt werden.\n" #: .././repair/sb.c:788 msgid "" "Only one AG detected - cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n" msgstr "" "Nur ein AGs wurde entdeckt - die Geometrie des Dateisystems konnte nicht\n" "bestätigt werden.\n" "Benutzen Sie die force_geometry-Option -o um fortzufahren\n" #: .././repair/sb.c:803 msgid "Not enough matching superblocks - cannot proceed.\n" msgstr "" "Nicht genug passende Superblöcke - es kann nicht fortgefahren werden.\n" #: .././repair/sb.c:818 msgid "could not read superblock\n" msgstr "Superblock kann nicht gelesen werden\n" #: .././repair/phase5.c:235 msgid "could not set up btree block array\n" msgstr "btree-Block-Matrix kann nicht eingerichtet werden\n" #: .././repair/phase5.c:247 msgid "error - not enough free space in filesystem\n" msgstr "Fehler - nicht genug freier Platz im Dateisystem\n" #: .././repair/phase5.c:463 #, c-format msgid "can't rebuild fs trees -- not enough free space on ag %u\n" msgstr "" "fs-Bäume können nicht erneut gebildet werden -- nicht genug freier Platz\n" "auf ag %u\n" #: .././repair/phase5.c:487 #, c-format msgid "ag %u - not enough free space to build freespace btrees\n" msgstr "ag %u - nicht genug freier Platz im Freiplatz-btrees zu bilden\n" #: .././repair/phase5.c:522 #, c-format msgid "not enough free blocks left to describe all free blocks in AG %u\n" msgstr "" "nicht genügend freie Blöcke vorhandene um alle freien Blöcke in AG %u\n" "zu beschreiben\n" #: .././repair/phase5.c:1335 #, c-format msgid "lost %d blocks in ag %u\n" msgstr "%d Blöcke in ag %u verloren\n" #: .././repair/phase5.c:1338 #, c-format msgid "thought we were going to lose %d blocks in ag %u, actually lost %d\n" msgstr "" "man dachte, %d Blöcke würden in ag %u verloren gehen, aktuell verloren %d\n" #: .././repair/phase5.c:1385 .././repair/xfs_repair.c:810 msgid "couldn't get superblock\n" msgstr "Superblock kann nicht bekommen werden\n" #: .././repair/phase5.c:1462 #, c-format msgid "unable to rebuild AG %u. Not enough free space in on-disk AG.\n" msgstr "" "außerstande AG %u erneut zu bilden. Nicht genug freier Platz in on-disk AG.\n" #: .././repair/phase5.c:1502 #, c-format msgid "unable to rebuild AG %u. No free space.\n" msgstr "außerstande AG %u erneut zu bilden. Nicht genug Platz.\n" #: .././repair/phase5.c:1529 #, c-format msgid "lost %d blocks in agno %d, sorry.\n" msgstr "%d Blöcke in agno %d verloren, Entschuldigung.\n" #: .././repair/phase5.c:1598 msgid "Phase 5 - rebuild AG headers and trees...\n" msgstr "Phase 5 - AG-Köpfe und Bäume werden erneut gebildet...\n" #: .././repair/phase5.c:1628 msgid "cannot alloc sb_icount_ag buffers\n" msgstr "sb_icount_ag-Puffer können nicht alloziert werden\n" #: .././repair/phase5.c:1632 msgid "cannot alloc sb_ifree_ag buffers\n" msgstr "sb_ifree_ag-Puffer können nicht alloziert werden\n" #: .././repair/phase5.c:1636 msgid "cannot alloc sb_fdblocks_ag buffers\n" msgstr "sb_fdblocks_ag-Puffer können nicht alloziert werden\n" #: .././repair/phase5.c:1655 msgid " - generate realtime summary info and bitmap...\n" msgstr " - Echtzeit-Zusammenfassung und Bitmap wird erzeugt...\n" #: .././repair/phase5.c:1661 msgid " - reset superblock...\n" msgstr " - Superblock wird zurückgesetzt...\n" #: .././repair/versions.c:73 #, c-format msgid "bogus quota flags 0x%x set in superblock" msgstr "fingierte Quota-Markierungen 0x%x im Superblock gesetzt" #: .././repair/versions.c:86 msgid ", bogus flags will be cleared\n" msgstr ", fingierte Markierungen werden bereinigt\n" #: .././repair/versions.c:88 msgid ", bogus flags would be cleared\n" msgstr ", fingierte Markierungen könnten bereinigt werden\n" #: .././repair/versions.c:141 msgid "This filesystem has uninitialized extent flags.\n" msgstr "Dieses Dateisystem hat nicht initialisierte Ausmaß-Markierungen\n" #: .././repair/versions.c:149 msgid "This filesystem is marked shared.\n" msgstr "Dieses Dateisystem ist als gemeinsam nutzbar markiert.\n" #: .././repair/versions.c:155 msgid "" "This filesystem uses feature(s) not yet supported in this release.\n" "Please run a more recent version of xfs_repair.\n" msgstr "" "Dieses Dateisystem benutzt Merkmale, die von dieser Veröffentlichung\n" "noch nicht unterstützt werden.\n" "Bitte führen Sie eine aktuellere Version von xfs_repair aus.\n" #: .././repair/versions.c:161 #, c-format msgid "WARNING: unknown superblock version %d\n" msgstr "WARNUNG: unbekannte Superblock-Version %d\n" #: .././repair/versions.c:164 msgid "This filesystem contains features not understood by this program.\n" msgstr "" "Dieses Dateisystem enthält Merkmale, die von diesem Programm nicht\n" "verstanden werden.\n" #: .././repair/versions.c:172 msgid "" "WARNING: you have disallowed superblock-feature-bits-allowed\n" "\tbut this superblock has feature bits. The superblock\n" "\twill be downgraded. This may cause loss of filesystem meta-data\n" msgstr "" "WARNUNG: Sie haben superblock-feature-bits-allowed verboten, aber dieser\n" "\tSuperblock hat Funktions-Bits. Der Superblock wird herabgestuft. Dies\n" "\tkann den Verlust von Dateisystem-Metadaten zur Folge haben\n" #: .././repair/versions.c:177 msgid "" "WARNING: you have disallowed superblock-feature-bits-allowed\n" "\tbut this superblock has feature bits. The superblock\n" "\twould be downgraded. This might cause loss of filesystem\n" "\tmeta-data.\n" msgstr "" "WARNUNG: Sie haben superblock-feature-bits-allowed verboten, aber dieser\n" "\tSuperblock hat Funktions-Bits. Der Superblock wird herabgestuft. Dies\n" "\tkönnte den Verlust von Dateisystem-Metadaten zur Folge haben\n" #: .././repair/versions.c:191 msgid "" "WARNING: you have disallowed attributes but this filesystem\n" "\thas attributes. The filesystem will be downgraded and\n" "\tall attributes will be removed.\n" msgstr "" "WARNUNG: Sie haben Attribute verboten, aber dieses Dateisystem hat\n" "\tAttribute. Das Dateisystem wird herabgestuft und alle Attribute werden\n" "\tentfernt\n" #: .././repair/versions.c:196 msgid "" "WARNING: you have disallowed attributes but this filesystem\n" "\thas attributes. The filesystem would be downgraded and\n" "\tall attributes would be removed.\n" msgstr "" "WARNUNG: Sie haben Attribute verboten, aber dieses Dateisystem hat\n" "\tAttribute. Das Dateisystem könnte herabgestuft und alle Attribute\n" "\tentfernt werden\n" #: .././repair/versions.c:209 msgid "" "WARNING: you have disallowed attr2 attributes but this filesystem\n" "\thas attributes. The filesystem will be downgraded and\n" "\tall attr2 attributes will be removed.\n" msgstr "" "WARNUNG: Sie haben attr2-Attribute verboten, aber dieses Dateisystem hat\n" "\tAttribute. Das Dateisystem wird herabgestuft und alle attr2-Attribute\n" "\twerden entfernt\n" #: .././repair/versions.c:214 msgid "" "WARNING: you have disallowed attr2 attributes but this filesystem\n" "\thas attributes. The filesystem would be downgraded and\n" "\tall attr2 attributes would be removed.\n" msgstr "" "WARNUNG: Sie haben attr2-Attribute verboten, aber dieses Dateisystem hat\n" "\tAttribute. Das Dateisystem wird herabgestuft und alle attr2-Attribute\n" "\twerden entfernt\n" #: .././repair/versions.c:227 msgid "" "WARNING: you have disallowed version 2 inodes but this filesystem\n" "\thas version 2 inodes. The filesystem will be downgraded and\n" "\tall version 2 inodes will be converted to version 1 inodes.\n" "\tThis may cause some hard links to files to be destroyed\n" msgstr "" "WARNUNG: Sie haben Version-2-Inodes verboten, aber dieses Dateisystem hat\n" "\tVersion-2-Inodes. Das Dateisystem wird herabgestuft und alle\n" "\tVersion-2-Inodes werden in Version-1-Inodes umgewandelt. Dies kann zur\n" "\tFolge haben, dass einige Hardlinks auf Dateien zerstört werden.\n" #: .././repair/versions.c:233 msgid "" "WARNING: you have disallowed version 2 inodes but this filesystem\n" "\thas version 2 inodes. The filesystem would be downgraded and\n" "\tall version 2 inodes would be converted to version 1 inodes.\n" "\tThis might cause some hard links to files to be destroyed\n" msgstr "" "WARNUNG: Sie haben Version-2-Inodes verboten, aber dieses Dateisystem hat\n" "\tVersion-2-Inodes. Das Dateisystem könnte herabgestuft und alle\n" "\tVersion-2-Inodes in Version-1-Inodes umgewandelt erden. Dies könnte zur\n" "\tFolge haben, dass einige Hardlinks auf Dateien zerstört werden.\n" #: .././repair/versions.c:247 msgid "" "WARNING: you have disallowed quotas but this filesystem\n" "\thas quotas. The filesystem will be downgraded and\n" "\tall quota information will be removed.\n" msgstr "" "WARNUNG: Sie haben Quota verboten, aber dieses Dateisystem hat\n" "\tQuota. Das Dateisystem wird herabgestuft und jegliche Quota-\n" "\tInformation wird entfernt.\n" #: .././repair/versions.c:252 msgid "" "WARNING: you have disallowed quotas but this filesystem\n" "\thas quotas. The filesystem would be downgraded and\n" "\tall quota information would be removed.\n" msgstr "" "WARNUNG: Sie haben Quota verboten, aber dieses Dateisystem hat\n" "\tQuota. Das Dateisystem könnte herabgestuft und jegliche Quota-\n" "\tInformation entfernt werden.\n" #: .././repair/versions.c:276 msgid "" "WARNING: you have disallowed aligned inodes but this filesystem\n" "\thas aligned inodes. The filesystem will be downgraded.\n" "\tThis will permanently degrade the performance of this filesystem.\n" msgstr "" "WARNUNG: Sie haben angepasste Inodes verboten, aber dieses Dateisystem\n" "\that angepasste Inodes. Das Dateisystem wird herabgestuft.\n" "\tDies wird die Leistungsfähigkeit des Dateisystems dauerhaft mindern.\n" #: .././repair/versions.c:281 msgid "" "WARNING: you have disallowed aligned inodes but this filesystem\n" "\thas aligned inodes. The filesystem would be downgraded.\n" "\tThis would permanently degrade the performance of this filesystem.\n" msgstr "" "WARNUNG: Sie haben angepasste Inodes verboten, aber dieses Dateisystem\n" "\that angepasste Inodes. Das Dateisystem könnte herabgestuft werden.\n" "\tDies könnte die Leistungsfähigkeit des Dateisystems dauerhaft mindern\n" #: .././repair/threads.c:90 #, c-format msgid "cannot create worker threads, error = [%d] %s\n" msgstr "Arbeiter-Threads können nicht erzeugt werden, Fehler = [%d] %s\n" #: .././repair/threads.c:108 #, c-format msgid "cannot allocate worker item, error = [%d] %s\n" msgstr "Arbeiter-Gegenstand kann nicht alloziert werden, Fehler = [%d] %s\n" #: .././repair/bmap.c:43 #, c-format msgid "realloc failed in blkent_append (%u bytes)\n" msgstr "»realloc« in »blkent_append« fehlgeschlagen (%u Bytes)\n" #: .././repair/bmap.c:65 #, c-format msgid "malloc failed in blkent_new (%u bytes)\n" msgstr "»malloc« in »blkent_append« fehlgeschlagen (%u Bytes)\n" #: .././repair/bmap.c:91 #, c-format msgid "malloc failed in blkent_prepend (%u bytes)\n" msgstr "»malloc« in »blkent_prepend« fehlgeschlagen (%u Bytes)\n" #: .././repair/bmap.c:118 #, c-format msgid "malloc failed in blkmap_alloc (%u bytes)\n" msgstr "»malloc« in »blkent_alloc« fehlgeschlagen (%u Bytes)\n" #: .././repair/bmap.c:216 #, c-format msgid "blkmap_getn realloc failed (%u bytes)\n" msgstr "»blkmap_getn realloc« fehlgeschlagen (%u Bytes)\n" #: .././repair/bmap.c:252 #, c-format msgid "realloc failed in blkmap_grow (%u bytes)\n" msgstr "»realloc« in »blkent_grow« fehlgeschlagen (%u Bytes)\n" #: .././repair/phase2.c:65 #, c-format msgid "" "zero_log: cannot find log head/tail (xlog_find_tail=%d), zeroing it anyway\n" msgstr "" "zero_log: Kopf/Fuß des Protokolls kann nicht gefunden werden\n" "(xlog_find_tail=%d), wird trotzdem auf Null gesetzt\n" #: .././repair/phase2.c:70 #, c-format msgid "zero_log: head block %lld tail block %lld\n" msgstr "zero_log: Kopfblock %lld Fußblock %lld\n" #: .././repair/phase2.c:76 msgid "" "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "destroyed because the -L option was used.\n" msgstr "" "ALARM: Das Dateisystem hat wertvolle Metadaten-Änderungen in einem\n" "Protokoll, das zerstört wird, weil die -L-Option benutzt wird.\n" #: .././repair/phase2.c:80 msgid "" "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running xfs_repair. If you are unable to mount the filesystem, then use\n" "the -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n" msgstr "" "FEHLER: Das Dateisystem hat wertvolle Metadaten-Änderungen in einem\n" "Protokoll, das wiederholt werden sollte. Hängen Sie das Dateisystem ein,\n" "um das Protokoll zu wiederholen und hängen Sie es wieder aus um\n" "xfs_repair erneut auszuführen. Wenn Sie außer Stande sind, das\n" "Dateisystem einzuhängen, benutzen Sie die -L-Option um das Protokoll zu\n" "zerstören und versuchen Sie eine Reparatur.\n" "Beachten Sie, dass die Zerstörung des Protokolls Schaden verursachen\n" "kann -- bitte versuchen sie das Dateisystem einzuhängen ehe Sie dies tun.\n" #: .././repair/phase2.c:122 msgid "" "This filesystem has an external log. Specify log device with the -l " "option.\n" msgstr "" "Das Dateisystem hat ein externes Protokoll. Geben Sie das Protokoll-Gerät\n" "mit der Option -l an.\n" #: .././repair/phase2.c:125 #, c-format msgid "Phase 2 - using external log on %s\n" msgstr "Phase 2 - ein externes Protokoll auf %s benutzen\n" #: .././repair/phase2.c:127 msgid "Phase 2 - using internal log\n" msgstr "Phase 2 - ein internes Protokoll benutzen\n" #: .././repair/phase2.c:131 msgid " - zero log...\n" msgstr " - Null-Protokoll...\n" #: .././repair/phase2.c:135 msgid " - scan filesystem freespace and inode maps...\n" msgstr "" " - freier Speicher und Inode-Karten des Dateisystems werden\n" "gescannt...\n" #: .././repair/phase2.c:162 msgid "root inode chunk not found\n" msgstr "Wurzel-Inode-Stück nicht gefunden\n" #: .././repair/phase2.c:184 msgid " - found root inode chunk\n" msgstr " - Wurzel-Inode-Stück gefunden\n" #: .././repair/phase2.c:190 msgid "root inode marked free, " msgstr "Wurzel-Inode als frei gekennzeichnet, " #: .././repair/phase2.c:193 .././repair/phase2.c:202 .././repair/phase2.c:211 #: .././repair/dir2.c:1577 .././repair/dir2.c:1609 msgid "correcting\n" msgstr "wird berichtigt\n" #: .././repair/phase2.c:195 .././repair/phase2.c:204 .././repair/phase2.c:213 #: .././repair/dir2.c:1581 .././repair/dir2.c:1613 msgid "would correct\n" msgstr "könnte berichtigt werden\n" #: .././repair/phase2.c:199 msgid "realtime bitmap inode marked free, " msgstr "Echtzeit-Bitmap-Inode als frei gekennzeichnet, " #: .././repair/phase2.c:208 msgid "realtime summary inode marked free, " msgstr "Echtzeit-Zusammenfassungs-Inode als frei gekennzeichnet, " #: .././repair/phase7.c:43 #, c-format msgid "resetting inode %llu nlinks from %d to %d\n" msgstr "Inode %llu nlinks wird von %d auf %d zurückgesetzt\n" #: .././repair/phase7.c:49 #, c-format msgid "" "nlinks %d will overflow v1 ino, ino %llu will be converted to version 2\n" msgstr "" "nlinks %d wird überlaufen v1 ino, ino %llu wird zu Version 2 umgewandelt\n" #: .././repair/phase7.c:55 #, c-format msgid "would have reset inode %llu nlinks from %d to %d\n" msgstr "Inode %llu nlinks könnte von %d auf %d zurückgesetzt werden\n" #: .././repair/phase7.c:83 .././repair/phase6.c:3238 .././repair/phase6.c:3241 #, c-format msgid "couldn't map inode %llu, err = %d\n" msgstr "Inode %llu kann nicht kartiert werden, err = %d\n" #: .././repair/phase7.c:87 #, c-format msgid "couldn't map inode %llu, err = %d, can't compare link counts\n" msgstr "" "Inode %llu kann nicht kartiert werden, err = %d, Anzahl der Verweise kann\n" "nicht verglichen werden\n" #: .././repair/phase7.c:126 msgid "Phase 7 - verify and correct link counts...\n" msgstr "Phase 7 - Verweisanzahl wird geprüft und berichtigt...\n" #: .././repair/phase7.c:128 msgid "Phase 7 - verify link counts...\n" msgstr "Phase 7 - Verweisanzahl wird geprüft\n" #: .././repair/rt.c:47 msgid "couldn't allocate memory for incore realtime bitmap.\n" msgstr "Speicher für Incore-Echtzeit-Bitmap kann nicht alloziert werden.\n" #: .././repair/rt.c:51 msgid "couldn't allocate memory for incore realtime summary info.\n" msgstr "" "Speicher für Incore-Echtzeit-Zusammenfassungs-Info kann nicht alloziert\n" "werden.\n" #: .././repair/rt.c:203 #, c-format msgid "can't find block %d for rtbitmap inode\n" msgstr "Block %d für rtbitmap-Inode kann nicht gefunden werden\n" #: .././repair/rt.c:211 #, c-format msgid "can't read block %d for rtbitmap inode\n" msgstr "Block %d für rtbitmap-Inode kann nicht gelesen werden\n" #: .././repair/rt.c:265 #, c-format msgid "block %d for rtsummary inode is missing\n" msgstr "Block %d für rtsummary-Inode fehlt\n" #: .././repair/rt.c:273 #, c-format msgid "can't read block %d for rtsummary inode\n" msgstr "Block %d für rtsummary-Inode kann nicht gelesen werden\n" #: .././repair/scan.c:63 .././repair/scan.c:107 #, c-format msgid "can't read btree block %d/%d\n" msgstr "btree-Block %d/%d kann nicht gelesen werden\n" #: .././repair/scan.c:165 #, c-format msgid "bad magic # %#x in inode %llu (%s fork) bmbt block %llu\n" msgstr "falsche magische # %#x in Inode %llu (%s fork) bmbt Block %llu\n" #: .././repair/scan.c:171 #, c-format msgid "expected level %d got %d in inode %llu, (%s fork) bmbt block %llu\n" msgstr "" "erwartete Stufe %d hat %d in Inode %llu (%s Unterelement) bmbt Block %llu\n" #: .././repair/scan.c:191 #, c-format msgid "" "bad fwd (right) sibling pointer (saw %llu parent block says %llu)\n" "\tin inode %llu (%s fork) bmap btree block %llu\n" msgstr "" "falscher fwd (rechts) Geschwisterzeiger (%llu gesehen Elternblock\n" "\tsagt %llu) in Inode %llu (%s Unterelement) bmap btree Block %llu\n" #: .././repair/scan.c:201 #, c-format msgid "" "bad back (left) sibling pointer (saw %llu parent block says %llu)\n" "\tin inode %llu (%s fork) bmap btree block %llu\n" msgstr "" "falscher zurück (links) Geschwisterzeiger (%llu gesehen Elternblock\n" "\tsagt %llu) in Inode %llu (%s Unterelement) bmap btree Block %llu\n" #: .././repair/scan.c:215 #, c-format msgid "" "bad back (left) sibling pointer (saw %llu should be NULL (0))\n" "\tin inode %llu (%s fork) bmap btree block %llu\n" msgstr "" "falscher zurück (links) Geschwisterzeiger (%llu gesehen könnte NULL (0)\n" "\tsein) in Inode %llu (%s Unterelement) bmap btree Block %llu\n" #: .././repair/scan.c:250 .././repair/scan.c:258 #, c-format msgid "inode 0x%llx bmap block 0x%llx claimed, state is %d\n" msgstr "Inode 0x%llx bmap Block 0x%llx beansprucht, Status ist %d\n" #: .././repair/scan.c:274 #, c-format msgid "bad state %d, inode 0x%llx bmap block 0x%llx\n" msgstr "falscher Status %d, Inode 0x%llx bmap Block 0x%llx\n" #: .././repair/scan.c:300 .././repair/scan.c:350 #, c-format msgid "inode 0x%llx bad # of bmap records (%u, min - %u, max - %u)\n" msgstr "Inode 0x%llx falsche # von bmap-Datensätzen (%u, Min - %u, Max - %u)\n" #: .././repair/scan.c:330 #, c-format msgid "" "out-of-order bmap key (file offset) in inode %llu, %s fork, fsbno %llu\n" msgstr "" "bmap-Schlüssel außer Betrieb (Dateiversatz) in Inode %llu,\n" "%s Unterelement, fsbno %llu\n" #: .././repair/scan.c:366 .././repair/dinode.c:1228 #, c-format msgid "bad bmap btree ptr 0x%llx in ino %llu\n" msgstr "falscher bmap btree ptr 0x%llx in ino %llu\n" #: .././repair/scan.c:393 #, c-format msgid "" "correcting bt key (was %llu, now %llu) in inode %llu\n" "\t\t%s fork, btree block %llu\n" msgstr "" "bt-Schlüssel wird korrigiert (war %llu, nun %llu) in Inode %llu\n" "\t\t%s Unterelement, btree Block %llu\n" #: .././repair/scan.c:404 #, c-format msgid "" "bad btree key (is %llu, should be %llu) in inode %llu\n" "\t\t%s fork, btree block %llu\n" msgstr "" "falscher btree-Schlüssel (ist %llu, könnte %llu sein) in Inode %llu\n" "\t\t%s Unterelement, btree-Block %llu\n" #: .././repair/scan.c:421 #, c-format msgid "" "bad fwd (right) sibling pointer (saw %llu should be NULLFSBLOCK)\n" "\tin inode %llu (%s fork) bmap btree block %llu\n" msgstr "" "falscher fwd (rechts) Geschwisterzeiger (%llu gesehen könnte NULLFSBLOCK\n" "\tsein) in Inode %llu (%s Unterelement) »bmap btree«-Block %llu\n" #: .././repair/scan.c:460 #, c-format msgid "bad magic # %#x in btbno block %d/%d\n" msgstr "falsche magische # %#x in btbno-Block %d/%d\n" #: .././repair/scan.c:467 #, c-format msgid "expected level %d got %d in btbno block %d/%d\n" msgstr "erwartete Stufe %d hat %d in btbno-Block %d/%d\n" #: .././repair/scan.c:486 #, c-format msgid "" "bno freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "bno freespace btree Block beansprucht (Status %d), agno %d, bno %d,\n" "Suspekt %d\n" #: .././repair/scan.c:529 #, c-format msgid "block (%d,%d) multiply claimed by bno space tree, state - %d\n" msgstr "Block (%d,%d) mehrfach beansprucht vonbno space tree, Status - %d\n" #: .././repair/scan.c:604 #, c-format msgid "bad magic # %#x in btcnt block %d/%d\n" msgstr "falsche magische # %#x in btcnt-Block %d/%d\n" #: .././repair/scan.c:611 #, c-format msgid "expected level %d got %d in btcnt block %d/%d\n" msgstr "erwartete Stufe %d hat %d in btcnt-Block %d/%d\n" #: .././repair/scan.c:630 #, c-format msgid "" "bcnt freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "bcnt freespace btree Block beansprucht (Status %d), agno %d, bno %d,\n" "Suspekt %d\n" #: .././repair/scan.c:680 #, c-format msgid "block (%d,%d) already used, state %d\n" msgstr "Block (%d,%d) bereits benutzt, Status %d\n" #: .././repair/scan.c:768 #, c-format msgid "bad magic # %#x in inobt block %d/%d\n" msgstr "falsche magische # %#x in inobt-Block %d/%d\n" #: .././repair/scan.c:776 #, c-format msgid "expected level %d got %d in inobt block %d/%d\n" msgstr "erwartete Stufe %d hat %d in inobt-Block %d/%d\n" #: .././repair/scan.c:799 #, c-format msgid "inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "Inode-btree-Block beansprucht (Status %d), agno %d, bno %d, verdächtig %d\n" #: .././repair/scan.c:822 #, c-format msgid "dubious inode btree block header %d/%d\n" msgstr "fragwürdiger Inode-btree-Kopf %d/%d\n" #: .././repair/scan.c:859 #, c-format msgid "badly aligned inode rec (starting inode = %llu)\n" msgstr "schlecht ausgerichteter Inode-rec (Start-Inode = %llu)\n" #: .././repair/scan.c:875 #, c-format msgid "bad starting inode # (%llu (0x%x 0x%x)) in ino rec, skipping rec\n" msgstr "" "falsche Start-Inode # (%llu(0x%x 0x%x)) in ino rec, rec wird übersprungen\n" #: .././repair/scan.c:884 #, c-format msgid "bad ending inode # (%llu (0x%x 0x%x)) in ino rec, skipping rec\n" msgstr "" "falsch verschlüsselte Inode # (%llu (0x%x 0x%x)) in ino rec, rec wird\n" "übersprungen\n" #: .././repair/scan.c:913 #, c-format msgid "" "inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n" msgstr "" "Inode Chunk beansprucht benutzten Block, inobt Block - agno %d, bno %d,\n" "inopb %d\n" #: .././repair/scan.c:938 #, c-format msgid "inode rec for ino %llu (%d/%d) overlaps existing rec (start %d/%d)\n" msgstr "" "Inode-rec für ino %llu (%d/%d) überlappt existierenden rec (Start %d/%d)\n" #: .././repair/scan.c:990 #, c-format msgid "ir_freecount/free mismatch, inode chunk %d/%d, freecount %d nfree %d\n" msgstr "" "ir_freecount/frei keine Übereinstimmung, Inode-Chunk %d/%d,\n" "freecount %d nfree %d\n" #: .././repair/scan.c:1061 #, c-format msgid "can't read agfl block for ag %d\n" msgstr "agfl-Block für ag %d kann nicht gelesen werden\n" #: .././repair/scan.c:1074 #, c-format msgid "bad agbno %u in agfl, agno %d\n" msgstr "falsche agbno %u in agfl, agno %d\n" #: .././repair/scan.c:1083 #, c-format msgid "freeblk count %d != flcount %d in ag %d\n" msgstr "freeblk-Anzahl %d != flcount %d in ag %d\n" #: .././repair/scan.c:1110 #, c-format msgid "can't get root superblock for ag %d\n" msgstr "Wurzel-Superblock für ag %d kann nicht erlangt werden\n" #: .././repair/scan.c:1116 msgid "can't allocate memory for superblock\n" msgstr "Speicher für Superblock kann nicht alloziert werden\n" #: .././repair/scan.c:1126 #, c-format msgid "can't read agf block for ag %d\n" msgstr "agf-Block für ag %d kann nicht gelesen werden\n" #: .././repair/scan.c:1137 #, c-format msgid "can't read agi block for ag %d\n" msgstr "agi-Block für ag %d kann nicht gelesen werden\n" #: .././repair/scan.c:1161 #, c-format msgid "reset bad sb for ag %d\n" msgstr "falscher sb für ag %d wird zurückgesetzt\n" #: .././repair/scan.c:1164 #, c-format msgid "would reset bad sb for ag %d\n" msgstr "falscher sb für ag %d könnte zurückgesetzt werden\n" #: .././repair/scan.c:1169 #, c-format msgid "reset bad agf for ag %d\n" msgstr "falscher agf für ag %d wird zurückgesetzt\n" #: .././repair/scan.c:1172 #, c-format msgid "would reset bad agf for ag %d\n" msgstr "falscher agf für ag %d könnte zurückgesetzt werden\n" #: .././repair/scan.c:1177 #, c-format msgid "reset bad agi for ag %d\n" msgstr "falscher agi für ag %d wird zurückgesetzt\n" #: .././repair/scan.c:1180 #, c-format msgid "would reset bad agi for ag %d\n" msgstr "falscher agi für ag %d könnte zurückgesetzt werden\n" #: .././repair/scan.c:1190 #, c-format msgid "bad uncorrected agheader %d, skipping ag...\n" msgstr "falscher nicht berichtigter agheader %d, ag wird übersprungen...\n" #: .././repair/scan.c:1204 #, c-format msgid "bad agbno %u for btbno root, agno %d\n" msgstr "falscher agbno %u für btbno-Wurzel, agno %d\n" #: .././repair/scan.c:1214 #, c-format msgid "bad agbno %u for btbcnt root, agno %d\n" msgstr "falscher agbno %u für btbcnt-Wurzel, agno %d\n" #: .././repair/scan.c:1223 #, c-format msgid "bad agbno %u for inobt root, agno %d\n" msgstr "falscher agbno %u für inobt-Wurzel, agno %d\n" #: .././repair/dir.c:153 #, c-format msgid "invalid inode number %llu in directory %llu\n" msgstr "ungültige Inode-Nummer %llu in Verzeichnis %llu\n" #: .././repair/dir.c:158 #, c-format msgid "entry in shortform dir %llu references rt bitmap inode %llu\n" msgstr "Eintrag in Kurzform dir %llu bezieht sich auf Bitmap-Inode %llu\n" #: .././repair/dir.c:163 #, c-format msgid "entry in shortform dir %llu references rt summary inode %llu\n" msgstr "" "Eintrag in Kurzform dir %llu bezieht sich auf Zusammenfassungs-Inode %llu\n" #: .././repair/dir.c:168 #, c-format msgid "entry in shortform dir %llu references user quota inode %llu\n" msgstr "" "Eintrag in Kurzform dir %llu bezieht sich auf\n" "Benutzer-Quota-Inode %llu\n" #: .././repair/dir.c:173 #, c-format msgid "entry in shortform dir %llu references group quota inode %llu\n" msgstr "" "Eintrag in Kurzform dir %llu bezieht sich auf\n" "Gruppen-Quota-Inode %llu\n" #: .././repair/dir.c:193 #, c-format msgid "entry references free inode %llu in shortform directory %llu\n" msgstr "" "Eintrag bezieht sich auf freien Inode %llu in Kurzform-Verzeichnis %llu\n" #: .././repair/dir.c:212 #, c-format msgid "entry references non-existent inode %llu in shortform dir %llu\n" msgstr "" "Eintrag bezieht sich auf nicht existierenden Inode %llu in\n" "Kurzform-dir %llu\n" #: .././repair/dir.c:236 .././repair/dir2.c:990 #, c-format msgid "zero length entry in shortform dir %llu, resetting to %d\n" msgstr "" "Eintrag mit Länge Null in Kurzform-dir %llu, wird auf %d zurückgesetzt\n" #: .././repair/dir.c:241 .././repair/dir2.c:996 #, c-format msgid "zero length entry in shortform dir %llu, would set to %d\n" msgstr "" "Eintrag mit Länge Null in Kurzform-dir %llu, könnte auf %d zurückgesetzt\n" "werden\n" #: .././repair/dir.c:246 #, c-format msgid "zero length entry in shortform dir %llu, " msgstr "Eintrag mit Länge Null in Kurzform-dir %llu, " #: .././repair/dir.c:249 .././repair/dir.c:292 .././repair/dir2.c:1049 #, c-format msgid "junking %d entries\n" msgstr "%d Einträge werden verworfen\n" #: .././repair/dir.c:252 .././repair/dir.c:301 .././repair/dir2.c:1058 #, c-format msgid "would junk %d entries\n" msgstr "%d Einträge könnten verworfen werden\n" #: .././repair/dir.c:270 .././repair/dir2.c:1026 #, c-format msgid "size of last entry overflows space left in in shortform dir %llu, " msgstr "Größe des letzten Eintrag-Überlauf-Raums bleibt in Kurzform-dir %llu, " #: .././repair/dir.c:273 .././repair/dir2.c:1030 #, c-format msgid "resetting to %d\n" msgstr "es wird auf %d zurückgesetzt\n" #: .././repair/dir.c:278 .././repair/dir2.c:1035 #, c-format msgid "would reset to %d\n" msgstr "es könnte auf %d zurückgesetzt werden\n" #: .././repair/dir.c:283 .././repair/dir2.c:1039 #, c-format msgid "size of entry #%d overflows space left in in shortform dir %llu\n" msgstr "" "Größe des letzten Eintrag-#%d-Überlauf-Raums bleibt in Kurzform-dir %llu\n" #: .././repair/dir.c:288 .././repair/dir2.c:1045 #, c-format msgid "junking entry #%d\n" msgstr "Eintrag #%d wird verworfen\n" #: .././repair/dir.c:297 .././repair/dir2.c:1054 #, c-format msgid "would junk entry #%d\n" msgstr "Eintrag #%d könnte verworfen werden\n" #: .././repair/dir.c:320 .././repair/dir2.c:1076 #, c-format msgid "entry contains illegal character in shortform dir %llu\n" msgstr "Eintrag enthält unerlaubtes Zeichen in Kurzform-dir %llu\n" #: .././repair/dir.c:374 .././repair/dir2.c:1140 #, c-format msgid "junking entry \"%s\" in directory inode %llu\n" msgstr "Eintrag »%s« in Verzeichnis-Inode %llu wird verworfen\n" #: .././repair/dir.c:378 .././repair/dir2.c:1144 #, c-format msgid "would have junked entry \"%s\" in directory inode %llu\n" msgstr "Eintrag »%s« in Verzeichnis-Inode %llu könnte verworfen worden sein\n" #: .././repair/dir.c:404 .././repair/dir2.c:1171 #, c-format msgid "would have corrected entry count in directory %llu from %d to %d\n" msgstr "" "Eintragsanzahl könnte im Verzeichnis %llu von %d auf %d korrigiert\n" "worden sein\n" #: .././repair/dir.c:408 .././repair/dir2.c:1175 #, c-format msgid "corrected entry count in directory %llu, was %d, now %d\n" msgstr "berichtigte Eintragsanzahl im Verzeichnis %llu, war %d, nun %d\n" #: .././repair/dir.c:419 .././repair/dir2.c:1204 #, c-format msgid "would have corrected directory %llu size from %lld to %lld\n" msgstr "" "Größe des Verzeichnisses %llu könnte von %lld auf %lld berichtigt worden\n" "sein\n" #: .././repair/dir.c:424 .././repair/dir2.c:1210 #, c-format msgid "corrected directory %llu size, was %lld, now %lld\n" msgstr "Größe des Verzeichnisses %llu berichtigt, war %lld, nun %lld\n" #: .././repair/dir.c:446 .././repair/dir2.c:1252 #, c-format msgid "bogus .. inode number (%llu) in directory inode %llu, " msgstr "fingiert .. Inode-Nummer (%llu) in Verzeichnis-Inode %llu, " #: .././repair/dir.c:449 .././repair/dir.c:483 .././repair/dir2.c:1257 #: .././repair/dir2.c:1292 msgid "clearing inode number\n" msgstr "Inode-Nummer wird bereinigt\n" #: .././repair/dir.c:455 .././repair/dir.c:489 .././repair/dir2.c:1263 #: .././repair/dir2.c:1298 msgid "would clear inode number\n" msgstr "Inode-Nummer könnte bereinigt werden\n" #: .././repair/dir.c:463 .././repair/dir2.c:1270 #, c-format msgid "corrected root directory %llu .. entry, was %llu, now %llu\n" msgstr "Wurzel-Verzeichnis %llu berichtigt .. Eintrag war %llu, nun %llu\n" #: .././repair/dir.c:471 .././repair/dir2.c:1278 #, c-format msgid "would have corrected root directory %llu .. entry from %llu to %llu\n" msgstr "" "Wurzel-Verzeichnis %llu könnte berichtigt worden sein .. Eintrag von\n" "%llu zu %llu\n" #: .././repair/dir.c:480 #, c-format msgid "bad .. entry in dir ino %llu, points to self, " msgstr "falscher ..-Eintrag in dir ino %llu, zeigt auf sich selbst, " #: .././repair/dir.c:528 #, c-format msgid "bad range claimed [%d, %d) in da block\n" msgstr "falscher Bereich beansprucht [%d, %d) in da-Block\n" #: .././repair/dir.c:535 #, c-format msgid "byte range end [%d %d) in da block larger than blocksize %d\n" msgstr "Byte-Bereichsende [%d, %d) in da-Block größer als Blockgröße %d\n" #: .././repair/dir.c:542 #, c-format msgid "multiply claimed byte %d in da block\n" msgstr "mehrfach beanspruchtes Byte %d in da-Block\n" #: .././repair/dir.c:572 #, c-format msgid "hole (start %d, len %d) out of range, block %d, dir ino %llu\n" msgstr "" "Loch (Start %d, len %d) außerhalb des Bereiches, Block %d, dir ino %llu\n" #: .././repair/dir.c:583 #, c-format msgid "hole claims used byte %d, block %d, dir ino %llu\n" msgstr "Loch beansprucht benutztes Byte %d, Block %d, dir ino %llu\n" #: .././repair/dir.c:698 #, c-format msgid "- derived hole value %d, saw %d, block %d, dir ino %llu\n" msgstr "- abgeleiteter Lochwert %d, gesehen %d, Block %d, dir ino %llu\n" #: .././repair/dir.c:717 #, c-format msgid "" "- derived hole (base %d, size %d) in block %d, dir inode %llu not found\n" msgstr "" "- abgeleitetes Loch (Basis %d, Größe %d) in Block %d, dir Inode %llu\n" "nicht gefunden\n" #: .././repair/dir.c:793 .././repair/dir.c:971 .././repair/phase6.c:1198 #: .././repair/phase6.c:1566 #, c-format msgid "can't read block %u (fsbno %llu) for directory inode %llu\n" msgstr "" "Block %u(fsbno %llu) kann nicht gelesen werden für Verzeichnis-Inode %llu\n" #: .././repair/dir.c:797 #, c-format msgid "can't read block %u (fsbno %llu) for attrbute fork of inode %llu\n" msgstr "" "Block %u(fsbno %llu) kann nicht gelesen werden für Attributs-Unterelement\n" "des Inodes %llu\n" #: .././repair/dir.c:806 .././repair/dir.c:981 .././repair/phase6.c:1208 #, c-format msgid "bad dir/attr magic number in inode %llu, file bno = %u, fsbno = %llu\n" msgstr "falsche dir/attr magische Nummer in Inode %llu, Datei bno = %u,\n" "fsbno = %llu\n" #: .././repair/dir.c:814 .././repair/dir2.c:333 #, c-format msgid "bad record count in inode %llu, count = %d, max = %d\n" msgstr "falsche Datensatz-Anzahl in Inode %llu, Anzahl = %d max = %d\n" #: .././repair/dir.c:833 .././repair/dir2.c:356 #, c-format msgid "bad directory btree for directory inode %llu\n" msgstr "falscher Verzeichnis-btree für Verzeichnis-Inode %llu\n" #: .././repair/dir.c:837 #, c-format msgid "bad attribute fork btree for inode %llu\n" msgstr "falsches Attributs-Unterelement btree für Inode %llu\n" #: .././repair/dir.c:891 #, c-format msgid "release_da_cursor_int got unexpected non-null bp, dabno = %u\n" msgstr "release_da_cursor_int hat unerwartetes Nicht-Null bp, dabno = %u\n" #: .././repair/dir.c:952 .././repair/dir.c:997 #, c-format msgid "bmap of block #%u of inode %llu failed\n" msgstr "bmap des Blocks #%u des Inodes %llu fehlgeschlagen\n" #: .././repair/dir.c:1043 #, c-format msgid "directory/attribute block used/count inconsistency - %d/%hu\n" msgstr "Verzeichnis-/Attributsblock benutzt/Unstimmigkeit gezählt - %d/%hu\n" #: .././repair/dir.c:1053 .././repair/dir2.c:479 #, c-format msgid "" "directory/attribute block hashvalue inconsistency, expected > %u / saw %u\n" msgstr "" "Verzeichnis-/Attributsblock Hash-Wert-Unstimmigkeit, erwartet > %u /\n" "gesehen %u\n" #: .././repair/dir.c:1060 .././repair/dir2.c:486 #, c-format msgid "bad directory/attribute forward block pointer, expected 0, saw %u\n" msgstr "falscher Verzeichnis-/Attribut-Block-Zeiger, erwartet 0, gesehen %u\n" #: .././repair/dir.c:1066 #, c-format msgid "bad directory block in dir ino %llu\n" msgstr "falscher Verzeichnis-Block in dir ino %llu\n" #: .././repair/dir.c:1096 #, c-format msgid "" "correcting bad hashval in non-leaf dir/attr block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in non-leaf dir/attr-Block wird korrigiert\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir.c:1104 #, c-format msgid "" "would correct bad hashval in non-leaf dir/attr block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "würde hashval in non-leaf dir/attr-Block korrigieren\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir.c:1242 .././repair/dir2.c:650 #, c-format msgid "can't get map info for block %u of directory inode %llu\n" msgstr "" "Karten-Info für Block %u des Verzeichnis-Inodes %llu kann nicht bezogen\n" "werden\n" #: .././repair/dir.c:1251 #, c-format msgid "can't read block %u (%llu) for directory inode %llu\n" msgstr "Block %u (%llu) für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/dir.c:1264 #, c-format msgid "bad magic number %x in block %u (%llu) for directory inode %llu\n" msgstr "" "falsche magische Nummer %x in Block %u (%llu) füu Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1272 #, c-format msgid "bad back pointer in block %u (%llu) for directory inode %llu\n" msgstr "" "falscher Rückwarts-Zeiger in Block %u (%llu) für Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1278 #, c-format msgid "entry count %d too large in block %u (%llu) for directory inode %llu\n" msgstr "" "Eintragsanzahl %d zu groß in Block %u (%llu) für Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1285 #, c-format msgid "bad level %d in block %u (%llu) for directory inode %llu\n" msgstr "falsche Stufe %d in Block %u (%llu) für Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1343 #, c-format msgid "" "correcting bad hashval in interior dir/attr block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in innerem dir/attr-Block wird berichtigt\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir.c:1351 #, c-format msgid "" "would correct bad hashval in interior dir/attr block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in innerem dir/attr-Block könnte berichtigt werden\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir.c:1462 #, c-format msgid "" "directory block header conflicts with used space in directory inode %llu\n" msgstr "" "Kopf des Verzeichnisblocks hat einen Konflikt mit dem benutzten Raum im\n" "Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1491 #, c-format msgid "" "nameidx %d for entry #%d, bno %d, ino %llu > fs blocksize, deleting entry\n" msgstr "" "nameidx %d für Eintrag #%d, bno %d, ino %llu > fs Blockgröße, Eintrag\n" "wird gelöscht\n" #: .././repair/dir.c:1528 #, c-format msgid "" "nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, marking entry bad\n" msgstr "" "nameidx %d, Eintrag #%d, bno %d, ino %llu > fs Blockgröße, falscher\n" "Eintrag wird gekennzeichnet\n" #: .././repair/dir.c:1543 #, c-format msgid "" "nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, would delete entry\n" msgstr "" "nameidx %d für Eintrag #%d, bno %d, ino %llu > fs Blockgröße, Eintrag\n" "könnte gelöscht werden.\n" #: .././repair/dir.c:1580 #, c-format msgid "invalid ino number %llu in dir ino %llu, entry #%d, bno %d\n" msgstr "ungültige ino-Nummer %llu in dir ino %llu, Eintrag #%d, bno %d\n" #: .././repair/dir.c:1584 .././repair/dir.c:1600 .././repair/dir.c:1617 #: .././repair/dir.c:1633 .././repair/dir.c:1650 #, c-format msgid "\tclearing ino number in entry %d...\n" msgstr "\tino-Nummer in Eintrag %d wird bereinigt...\n" #: .././repair/dir.c:1591 .././repair/dir.c:1608 .././repair/dir.c:1624 #: .././repair/dir.c:1641 .././repair/dir.c:1658 #, c-format msgid "\twould clear ino number in entry %d...\n" msgstr "\tino-Nummer in Eintrag %d könnte bereinigt werden...\n" #: .././repair/dir.c:1596 #, c-format msgid "" "entry #%d, bno %d in directory %llu references realtime bitmap inode %llu\n" msgstr "" "Eintrag #%d, bno %d in Verzeichnis %llu bezieht sich auf\n" "Echtzeit-Bitmap-Inode %llu\n" #: .././repair/dir.c:1613 #, c-format msgid "" "entry #%d, bno %d in directory %llu references realtime summary inode %llu\n" msgstr "" "Eintrag #%d, bno %d in Verzeichnis %llu bezieht sich auf\n" "Echtzeit-Zusammenfassungs-Inode %llu\n" #: .././repair/dir.c:1629 #, c-format msgid "entry #%d, bno %d in directory %llu references user quota inode %llu\n" msgstr "" "Eintrag #%d, bno %d in Verzeichnis %llu bezieht sich auf\n" "Benutzer-Quota-Inode %llu\n" #: .././repair/dir.c:1646 #, c-format msgid "entry #%d, bno %d in directory %llu references group quota inode %llu\n" msgstr "" "Eintrag #%d, bno %d in Verzeichnis %llu bezieht sich auf\n" "Gruppen-Quota-Inode %llu\n" #: .././repair/dir.c:1683 #, c-format msgid "entry references free inode %llu in directory %llu, will clear entry\n" msgstr "" "Eintrag bezieht sich auf freien Inode %llu im Verzeichnis %llu, Eintrag\n" "soll bereinigt werden\n" #: .././repair/dir.c:1691 #, c-format msgid "entry references free inode %llu in directory %llu, would clear entry\n" msgstr "" "Eintrag bezieht sich auf freien Inode %llu im Verzeichnis %llu, Eintrag\n" "könnte bereinigt werden\n" #: .././repair/dir.c:1699 #, c-format msgid "bad ino number %llu in dir ino %llu, entry #%d, bno %d\n" msgstr "falsche ino-Nummer %llu in dir ino %llu, Eintrag #%d, bno %d\n" #: .././repair/dir.c:1702 msgid "clearing inode number...\n" msgstr "Inode-Nummer wird bereinigt...\n" #: .././repair/dir.c:1707 msgid "would clear inode number...\n" msgstr "Inode-Nummer könnte bereinigt werden...\n" #: .././repair/dir.c:1727 #, c-format msgid "entry #%d, dir inode %llu, has zero-len name, deleting entry\n" msgstr "" "Eintrag #%d, dir Inode %llu, hat zero-len Name, Eintrag wird gelöscht\n" #: .././repair/dir.c:1765 #, c-format msgid "entry #%d, dir inode %llu, has zero-len name, marking entry bad\n" msgstr "" "Eintrag #%d, dir Inode %llu, hat zero-len Name, Eintrag wird\n" "gekennzeichnet\n" #: .././repair/dir.c:1778 #, c-format msgid "" "bad size, entry #%d in dir inode %llu, block %u -- entry overflows block\n" msgstr "" "falsche Größe, Eintrag #%d in dir Inode %llu, Block %u -- Eintrag\n" "überflutet Block\n" #: .././repair/dir.c:1789 #, c-format msgid "" "dir entry slot %d in block %u conflicts with used space in dir inode %llu\n" msgstr "" "dir-Eintrag-Slot %d in Block %u hat einen Konflikt mit dem benutzten\n" "Raum im Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1828 #, c-format msgid "illegal name \"%s\" in directory inode %llu, entry will be cleared\n" msgstr "" "unerlaubter Name »%s« im Verzeichnis-Inode %llu, Eintrag soll bereinigt\n" "werden\n" #: .././repair/dir.c:1834 #, c-format msgid "illegal name \"%s\" in directory inode %llu, entry would be cleared\n" msgstr "" "unerlaubter Name »%s« im Verzeichnis-Inode %llu, Eintrag könnte bereinigt\n" "werden\n" #: .././repair/dir.c:1844 #, c-format msgid "\tmismatched hash value for entry \"%s\"\n" msgstr "\tnicht übereinstimmender Hash-Wert für Eintrag »%s«\n" #: .././repair/dir.c:1848 #, c-format msgid "\t\tin directory inode %llu. resetting hash value.\n" msgstr "\t\tin Verzeichnis-Inode %llu. Hash-Wert wird zurückgesetzt.\n" #: .././repair/dir.c:1854 #, c-format msgid "\t\tin directory inode %llu. would reset hash value.\n" msgstr "" "\t\tin Verzeichnis-Inode %llu. Hash-Wert könnte zurückgesetzt werden.\n" #: .././repair/dir.c:1884 #, c-format msgid "\tbad hash ordering for entry \"%s\"\n" msgstr "\t falsche Hash-Anforderung für Eintrag »%s«\n" #: .././repair/dir.c:1888 #, c-format msgid "\t\tin directory inode %llu. will clear entry\n" msgstr "\t\tin Verzeichnis-Inode %llu. Eintrag soll bereinigt werden\n" #: .././repair/dir.c:1895 #, c-format msgid "\t\tin directory inode %llu. would clear entry\n" msgstr "\t\tin Verzeichnis-Inode %llu. Eintrag könnte bereinigt werden\n" #: .././repair/dir.c:1911 #, c-format msgid "" "name \"%s\" (block %u, slot %d) conflicts with used space in dir inode %llu\n" msgstr "" "Name »%s« (Block %u, Slot %d) hat einen Konflikt mit benutztem Raum in\n" "dir-Inode %llu\n" #: .././repair/dir.c:1918 #, c-format msgid "will clear entry \"%s\" (#%d) in directory inode %llu\n" msgstr "Eintrag »%s« (#%d) soll gelöscht werden in Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1922 #, c-format msgid "would clear entry \"%s\" (#%d)in directory inode %llu\n" msgstr "Eintrag »%s« (#%d) könnte gelöscht werden in Verzeichnis-Inode %llu\n" #: .././repair/dir.c:1958 #, c-format msgid "bad .. entry in dir ino %llu, points to self" msgstr "falscher ..-Eintrag in dir ino %llu, zeigt auf sich selbst" #: .././repair/dir.c:1962 .././repair/dir.c:2059 msgid "will clear entry\n" msgstr "Eintrag soll gelöscht werden\n" #: .././repair/dir.c:1967 .././repair/dir.c:2063 .././repair/dir2.c:1641 msgid "would clear entry\n" msgstr "Eintrag könnte gelöscht werden\n" #: .././repair/dir.c:1977 #, c-format msgid "correcting .. entry in root inode %llu, was %llu\n" msgstr "wird berichtigt .. Eintrag in Wurzel-Inode %llu, war %llu\n" #: .././repair/dir.c:1984 #, c-format msgid "bad .. entry (%llu) in root inode %llu should be %llu\n" msgstr "falscher .. Eintrag (%llu) in Wurzel-Inode %llu könnte %llu sein\n" #: .././repair/dir.c:2001 #, c-format msgid "multiple .. entries in directory inode %llu, will clear second entry\n" msgstr "" "mehrfache .. Einträge in Verzeichnis-Inode %llu, zweiter Eintrag wird\n" "bereinigt werden\n" #: .././repair/dir.c:2007 #, c-format msgid "multiple .. entries in directory inode %llu, would clear second entry\n" msgstr "" "mehrfache .. Einträge in Verzeichnis-Inode %llu, zweiter Eintrag könnte\n" "bereinigt werden\n" #: .././repair/dir.c:2020 #, c-format msgid ". in directory inode %llu has wrong value (%llu), fixing entry...\n" msgstr "" ". in Verzeichnis-Inode %llu hat falschen Wert (%llu), stelle Eintrag\n" "wieder her ..\n" #: .././repair/dir.c:2027 #, c-format msgid ". in directory inode %llu has wrong value (%llu)\n" msgstr ". in Verzeichnis-Inode %llu hat falschen Wert (%llu)\n" #: .././repair/dir.c:2033 #, c-format msgid "multiple . entries in directory inode %llu\n" msgstr "mehrfache .. Einträge in Verzeichnis-Inode %llu\n" #: .././repair/dir.c:2040 #, c-format msgid "will clear one . entry in directory inode %llu\n" msgstr "ein . Eintrag in Verzeichnis-Inode %llu wird bereinigt\n" #: .././repair/dir.c:2046 #, c-format msgid "would clear one . entry in directory inode %llu\n" msgstr "ein . Eintrag in Verzeichnis-Inode %llu könnte bereinigt werden\n" #: .././repair/dir.c:2056 #, c-format msgid "entry \"%s\" in directory inode %llu points to self, " msgstr "Eintrag »%s« in Verzeichnis-Inode %llu zeigt auf sich selbst, " #: .././repair/dir.c:2081 #, c-format msgid "" "- resetting first used heap value from %d to %d in block %u of dir ino %llu\n" msgstr "" "- zuerst benutzter heap-Wert wird von %d auf %d in Block %u von \n" "dir ino %llu zurückgesetzt\n" #: .././repair/dir.c:2089 #, c-format msgid "" "- would reset first used value from %d to %d in block %u of dir ino %llu\n" msgstr "" "- zuerst benutzter heap-Wert könnte von %d auf %d in Block %u von \n" "dir ino %llu zurückgesetzt werden\n" #: .././repair/dir.c:2099 #, c-format msgid "- resetting namebytes cnt from %d to %d in block %u of dir inode %llu\n" msgstr "" "- Namensbytes cnt werden von %d auf %d in Block %u von dir ino %llu\n" "zurückgesetzt\n" #: .././repair/dir.c:2107 #, c-format msgid "" "- would reset namebytes cnt from %d to %d in block %u of dir inode %llu\n" msgstr "" "- Namensbytes cnt könnten von %d auf %d in Block %u von dir ino %llu\n" "zurückgesetzt werden\n" #: .././repair/dir.c:2142 #, c-format msgid "- found unexpected lost holes in block %u, dir inode %llu\n" msgstr "- unerwartet verlorene Löcher in Block %u, dir-Inode %llu gefunden\n" #: .././repair/dir.c:2150 #, c-format msgid "- hole info non-optimal in block %u, dir inode %llu\n" msgstr "- Loch-Info nicht optimal in Block %u, dir-Inode %llu\n" #: .././repair/dir.c:2157 #, c-format msgid "- hole info incorrect in block %u, dir inode %llu\n" msgstr "- Loch-Info falsch in Block %u, dir-Inode %llu\n" #: .././repair/dir.c:2168 #, c-format msgid "- existing hole info for block %d, dir inode %llu (base, size) - \n" msgstr "" "- existierende Loch-Info für Block %d, dir-Inode %llu (Basis, Größe) - \n" #: .././repair/dir.c:2176 #, c-format msgid "- holes flag = %d\n" msgstr "- Loch-Kennzeichner = %d\n" #: .././repair/dir.c:2182 #, c-format msgid "- compacting block %u in dir inode %llu\n" msgstr "- Block %u in dir-Inode %llu wird verdichtet\n" #: .././repair/dir.c:2223 #, c-format msgid "not enough space in block %u of dir inode %llu for all entries\n" msgstr "nicht genug Platz in Block %u von dir-Inode %llu für alle Einträge\n" #: .././repair/dir.c:2291 #, c-format msgid "- would compact block %u in dir inode %llu\n" msgstr "- Block %u in dir-Inode %llu könnte verdichtet werden\n" #: .././repair/dir.c:2353 .././repair/dir2.c:1823 #, c-format msgid "can't map block %u for directory inode %llu\n" msgstr "Block %u für Verzeichnis-Inode %llu kann nicht kartiert werden\n" #: .././repair/dir.c:2364 #, c-format msgid "" "can't read file block %u (fsbno %llu, daddr %lld) for directory inode %llu\n" msgstr "" "Block %u (fsbno %llu, daddr %lld) für Verzeichnis-Inode %llu kann nicht\n" "gelesen werden\n" #: .././repair/dir.c:2378 .././repair/dir.c:2639 #, c-format msgid "bad directory leaf magic # %#x for dir ino %llu\n" msgstr "falsches Verzeichnis-Blatt magische # %#x für dir ino %llu\n" #: .././repair/dir.c:2417 #, c-format msgid "" "bad sibling back pointer for directory block %u in directory inode %llu\n" msgstr "" "falscher Geschwister-Rückwärts-Zeiger für Verzeichnis-Block %u in\n" "Verzeichnis-Inode %llu\n" #: .././repair/dir.c:2449 .././repair/dir2.c:1900 #, c-format msgid "bad hash path in directory %llu\n" msgstr "falscher Hash-Pfad in Verzeichnis %llu\n" #: .././repair/dir.c:2559 #, c-format msgid "out of range internal directory block numbers (inode %llu)\n" msgstr "interne Verzeichnis-Blocknummern (Inode %llu) außerhalb des Bereichs\n" #: .././repair/dir.c:2565 #, c-format msgid "setting directory inode (%llu) size to %llu bytes, was %lld bytes\n" msgstr "" "Größe des Verzeichnis-Inodes (%llu) wird auf %llu Bytes gesetzt,\n" "war %lld Bytes\n" #: .././repair/dir.c:2619 #, c-format msgid "block 0 for directory inode %llu is missing\n" msgstr "Block 0 für Verzeichnis-Inode %llu fehlt\n" #: .././repair/dir.c:2626 #, c-format msgid "can't read block 0 for directory inode %llu\n" msgstr "Block 0 für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/dir.c:2662 #, c-format msgid "clearing forw/back pointers for directory inode %llu\n" msgstr "" "Vorwärts-/Rückwärtszeiger für Verzeichnis-Inode %llu werden bereinigt\n" #: .././repair/dir.c:2668 #, c-format msgid "would clear forw/back pointers for directory inode %llu\n" msgstr "" "Vorwärts-/Rückwärtszeiger für Verzeichnis-Inode %llu könnten bereinigt\n" "werden.\n" #: .././repair/dir.c:2733 .././repair/dir2.c:2105 #, c-format msgid "no . entry for directory %llu\n" msgstr "kein . Eintrag für Verzeichnis %llu\n" #: .././repair/dir.c:2742 .././repair/dir2.c:2115 #, c-format msgid "no .. entry for directory %llu\n" msgstr "kein .. Eintrag für Verzeichnis %llu\n" #: .././repair/dir.c:2744 .././repair/dir2.c:2117 #, c-format msgid "no .. entry for root directory %llu\n" msgstr "kein .. Eintrag für Wurzelverzeichnis %llu\n" #: .././repair/incore_ext.c:121 .././repair/incore_ext.c:679 msgid "couldn't allocate new extent descriptors.\n" msgstr "neue Umfang-Deskriptoren können nicht alloziert werden.\n" #: .././repair/incore_ext.c:254 msgid "duplicate bno extent range\n" msgstr "doppelter bno-Umfangs-Bereich\n" #: .././repair/incore_ext.c:391 msgid ": duplicate bno extent range\n" msgstr ": doppelter bno-Umfangs-Bereich\n" #: .././repair/incore_ext.c:555 .././repair/incore_ext.c:606 #: .././repair/incore_ext.c:797 .././repair/incore_ext.c:852 msgid "duplicate extent range\n" msgstr "doppelter Umfangs-Bereich\n" #: .././repair/incore_ext.c:910 msgid "couldn't malloc dup extent tree descriptor table\n" msgstr "" "malloc dup extent konnte nicht für Baum-Deskriptor-Tabelle ausgeführt\n" "werden\n" #: .././repair/incore_ext.c:915 msgid "couldn't malloc free by-bno extent tree descriptor table\n" msgstr "" "malloc free by-bno extent konnte nicht für Baum-Deskriptor-Tabelle\n" "ausgeführt werden\n" #: .././repair/incore_ext.c:920 msgid "couldn't malloc free by-bcnt extent tree descriptor table\n" msgstr "" "malloc free by-bcnt extent konnte nicht für Baum-Deskriptor-Tabelle\n" "ausgeführt werden\n" #: .././repair/incore_ext.c:926 msgid "couldn't malloc dup extent tree descriptor\n" msgstr "malloc dup extent konnte nicht für Baum-Deskriptor ausgeführt werden\n" #: .././repair/incore_ext.c:930 msgid "couldn't malloc bno extent tree descriptor\n" msgstr "malloc bno extent konnte nicht für Baum-Deskriptor ausgeführt werden\n" #: .././repair/incore_ext.c:934 msgid "couldn't malloc bcnt extent tree descriptor\n" msgstr "" "malloc bcnt extent konnte nicht für Baum-Deskriptor ausgeführt werden\n" #: .././repair/incore_ext.c:944 msgid "couldn't malloc dup rt extent tree descriptor\n" msgstr "" "malloc dup rt extent konnte nicht für Baum-Deskriptor ausgeführt werden\n" #: .././repair/dir2.c:56 #, c-format msgid "malloc failed (%u bytes) dir2_add_badlist:ino %llu\n" msgstr "malloc fehlgeschlagen (%u Bytes) dir2_add_badlist:ino %llu\n" #: .././repair/dir2.c:97 .././repair/dir2.c:208 .././repair/dir2.c:244 msgid "couldn't malloc dir2 buffer list\n" msgstr "malloc dir2 Pufferliste konnte nicht ausgeführt werden\n" #: .././repair/dir2.c:124 msgid "couldn't malloc dir2 buffer header\n" msgstr "malloc dir2 Pufferkopfzeilen konnte nicht ausgeführt werden\n" #: .././repair/dir2.c:141 msgid "couldn't malloc dir2 buffer data\n" msgstr "malloc dir2 Pufferdaten konnte nicht ausgeführt werden\n" #: .././repair/dir2.c:305 .././repair/dir2.c:661 .././repair/dir2.c:1705 #: .././repair/phase6.c:2272 #, c-format msgid "can't read block %u for directory inode %llu\n" msgstr "Block %u für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/dir2.c:315 #, c-format msgid "found non-root LEAFN node in inode %llu bno = %u\n" msgstr "Nicht-Wurzel-LEAFN-Knoten gefunden in Inode %llu bno = %u\n" #: .././repair/dir2.c:324 #, c-format msgid "bad dir magic number 0x%x in inode %llu bno = %u\n" msgstr "falsche magische Nummer 0x%x in Inode %llu bno = %u\n" #: .././repair/dir2.c:345 #, c-format msgid "bad header depth for directory inode %llu\n" msgstr "falsche Kopfzeilentiefe für Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:407 #, c-format msgid "release_dir2_cursor_int got unexpected non-null bp, dabno = %u\n" msgstr "release_dir2_cursor_int hat unerwartetes Nicht-Null-bp, dabno = %u\n" #: .././repair/dir2.c:470 #, c-format msgid "directory block used/count inconsistency - %d / %hu\n" msgstr "Verzeichnis-Block benutzt/Anzahl unvollständig - %d / %hu\n" #: .././repair/dir2.c:492 #, c-format msgid "bad directory block in inode %llu\n" msgstr "falscher Verzeichnisblock in Inode %llu\n" #: .././repair/dir2.c:512 #, c-format msgid "" "correcting bad hashval in non-leaf dir block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in non-leaf dir-Block wird koorigiert\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir2.c:519 #, c-format msgid "" "would correct bad hashval in non-leaf dir block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in non-leaf dir-Block würde koorigiert\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir2.c:674 #, c-format msgid "bad magic number %x in block %u for directory inode %llu\n" msgstr "falsche Magische Nummer %x in Block %u für Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:682 #, c-format msgid "bad back pointer in block %u for directory inode %llu\n" msgstr "falscher Rückwärts-Zeiger in Block %u für Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:688 #, c-format msgid "entry count %d too large in block %u for directory inode %llu\n" msgstr "Eintragsanzahl %d in Block %u für Verzeichnis-Inode %llu zu groß\n" #: .././repair/dir2.c:695 #, c-format msgid "bad level %d in block %u for directory inode %llu\n" msgstr "falsche Stufe %d in Block %u für Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:738 #, c-format msgid "" "correcting bad hashval in interior dir block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in interior dir-Block wird koorigiert\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir2.c:745 #, c-format msgid "" "would correct bad hashval in interior dir block\n" "\tin (level %d) in inode %llu.\n" msgstr "" "falscher hashval in interior dir-Block würde koorigiert\n" "\tin (Stufe %d) in Inode %llu.\n" #: .././repair/dir2.c:779 msgid "couldn't malloc dir2 shortform copy\n" msgstr "malloc dir2 Kurzformkopie kann nicht durchgeführt werden\n" #: .././repair/dir2.c:917 msgid "current" msgstr "aktuell" #: .././repair/dir2.c:920 .././repair/dir2.c:1443 msgid "invalid" msgstr "ungültig" #: .././repair/dir2.c:923 .././repair/dir2.c:1445 msgid "realtime bitmap" msgstr "Echtzeit-Bitmap" #: .././repair/dir2.c:926 .././repair/dir2.c:1447 msgid "realtime summary" msgstr "Echtzeit-Zusammenfassung" #: .././repair/dir2.c:929 .././repair/dir2.c:1449 msgid "user quota" msgstr "Benutzer-Quota" #: .././repair/dir2.c:932 .././repair/dir2.c:1451 msgid "group quota" msgstr "Gruppen-Quota" #: .././repair/dir2.c:966 .././repair/dir2.c:1460 msgid "non-existent" msgstr "nicht existent" #: .././repair/dir2.c:970 #, c-format msgid "entry \"%*.*s\" in shortform directory %llu references %s inode %llu\n" msgstr "" "Eintrag »%*.*s« in Kurzform-Verzeichnis %llu verweist auf %s Inode %llu\n" #: .././repair/dir2.c:1002 #, c-format msgid "zero length entry in shortform dir %llu" msgstr "Eintrag der Länge Null in Kurzform dir %llu" #: .././repair/dir2.c:1006 #, c-format msgid ", junking %d entries\n" msgstr ", %d Einträge werden verworfen\n" #: .././repair/dir2.c:1009 #, c-format msgid ", would junk %d entries\n" msgstr ", %d Einträge könnten verworfen werden\n" #: .././repair/dir2.c:1083 #, c-format msgid "entry contains offset out of order in shortform dir %llu\n" msgstr "Eintrag enthält Versatz außer Betrieb in Kurzform-dir %llu\n" #: .././repair/dir2.c:1186 #, c-format msgid "would have corrected i8 count in directory %llu from %d to %d\n" msgstr "" "i8-Anzahl in Verzeichnis %llu könnte von %d auf %d berichtigt worden sein\n" #: .././repair/dir2.c:1190 #, c-format msgid "corrected i8 count in directory %llu, was %d, now %d\n" msgstr "i8-Anzahl in Verzeichnis %llu wurde berichtigt, war %d, nun %d\n" #: .././repair/dir2.c:1224 #, c-format msgid "directory %llu offsets too high\n" msgstr "Verzeichnis %llu Versätze zu groß\n" #: .././repair/dir2.c:1229 #, c-format msgid "would have corrected entry offsets in directory %llu\n" msgstr "Eintrags-Versätze in Verzeichnis %llu könnten berichtigt worden sein\n" #: .././repair/dir2.c:1233 #, c-format msgid "corrected entry offsets in directory %llu\n" msgstr "Eintrags-Versätze in Verzeichnis %llu wurden berichtigt\n" #: .././repair/dir2.c:1288 #, c-format msgid "bad .. entry in directory inode %llu, points to self, " msgstr "falscher .. Eintrag in Verzeichnis-Inode %llu, zeigt auf sich selbst, " #: .././repair/dir2.c:1401 #, c-format msgid "corrupt block %u in directory inode %llu\n" msgstr "kaputter Block %u in Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:1404 msgid "\twill junk block\n" msgstr "\tBlock wird weggeworfen\n" #: .././repair/dir2.c:1406 msgid "\twould junk block\n" msgstr "\tBlock könnte weggeworfen werden\n" #: .././repair/dir2.c:1488 #, c-format msgid "" "entry \"%*.*s\" at block %u offset %d in directory inode %llu references %s " "inode %llu\n" msgstr "" "Eintrag »%*.*s« in Block %u Versatz %d in Verzeichnis-Inode %llu bezieht\n" "sich auf %s Inode %llu\n" #: .././repair/dir2.c:1499 #, c-format msgid "entry at block %u offset %d in directory inode %llu has 0 namelength\n" msgstr "" "Eintrag in Block %u Versatz %d in Verzeichnis-Inode %llu hat\n" "Namenslänge 0\n" #: .././repair/dir2.c:1511 #, c-format msgid "\tclearing inode number in entry at offset %d...\n" msgstr "\t Inode-Nummer im Eintrag bei Versatz %d wird bereinigt...\n" #: .././repair/dir2.c:1518 #, c-format msgid "\twould clear inode number in entry at offset %d...\n" msgstr "\t Inode-Nummer im Eintrag bei Versatz %d könnte bereinigt werden...\n" #: .././repair/dir2.c:1531 #, c-format msgid "" "entry at block %u offset %d in directory inode %llu has illegal name \"%*.*s" "\": " msgstr "" "Eintrag in Block %u Versatz %d in Verzeichnis-Inode %llu hat unerlaubten\n" "Namen »%*.*s«: " #: .././repair/dir2.c:1561 #, c-format msgid "bad .. entry in directory inode %llu, points to self: " msgstr "falscher .. Eintrag in Verzeichnis-Inode %llu zeigt auf sich selbst: " #: .././repair/dir2.c:1572 #, c-format msgid "bad .. entry in root directory inode %llu, was %llu: " msgstr "falscher .. Eintrag in Wurzelverzeichnis-Inode %llu, war %llu: " #: .././repair/dir2.c:1592 #, c-format msgid "multiple .. entries in directory inode %llu: " msgstr "mehrere .. Einträge in Verzeichnis-Inode %llu: " #: .././repair/dir2.c:1605 #, c-format msgid "bad . entry in directory inode %llu, was %llu: " msgstr "falscher . Eintrag in Verzeichnis-Inode %llu, war %llu: " #: .././repair/dir2.c:1617 #, c-format msgid "multiple . entries in directory inode %llu: " msgstr "mehrere . Einträge in Verzeichnis-Inode %llu: " #: .././repair/dir2.c:1627 #, c-format msgid "entry \"%*.*s\" in directory inode %llu points to self: " msgstr "Eintrag »%*.*s« in Verzeichnis-Inode %llu zeigt auf sich selbst: " #: .././repair/dir2.c:1639 msgid "clearing entry\n" msgstr "Eintrag wird bereinigt\n" #: .././repair/dir2.c:1653 #, c-format msgid "bad bestfree table in block %u in directory inode %llu: " msgstr "falsche bestfree-Tabelle in Block %u in Verzeichnis-Inode %llu: " #: .././repair/dir2.c:1656 msgid "repairing table\n" msgstr "Tabelle wird repariert\n" #: .././repair/dir2.c:1660 msgid "would repair table\n" msgstr "Tabelle könnte repariert werden\n" #: .././repair/dir2.c:1697 #, c-format msgid "block %u for directory inode %llu is missing\n" msgstr "Block %u für Verzeichnis-Inode %llu fehlt\n" #: .././repair/dir2.c:1714 #, c-format msgid "bad directory block magic # %#x in block %u for directory inode %llu\n" msgstr "" "falscher Verzeichnisblock magische # %#x in Block %u für\n" "Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:1758 #, c-format msgid "bad entry count in block %u of directory inode %llu\n" msgstr "falsche Eintragsanzahl in Block %u des Verzeichnis-Inodes %llu\n" #: .././repair/dir2.c:1766 #, c-format msgid "bad hash ordering in block %u of directory inode %llu\n" msgstr "falsche Hash-Reihenfolge in Block %u von Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:1775 #, c-format msgid "bad stale count in block %u of directory inode %llu\n" msgstr "falsche Stale-Anzahl in Block %u von Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:1833 #, c-format msgid "can't read file block %u for directory inode %llu\n" msgstr "Dateiblock %u für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/dir2.c:1844 #, c-format msgid "bad directory leaf magic # %#x for directory inode %llu block %u\n" msgstr "" "falsches Verzeichnisblatt magische # %#x für Verzeichnis-Inode %llu Block %u\n" #: .././repair/dir2.c:1874 #, c-format msgid "bad sibling back pointer for block %u in directory inode %llu\n" msgstr "" "falscher Geschwister-Rückwärts-Zeiger für Block %u in\n" "Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:2004 #, c-format msgid "block %llu for directory inode %llu is missing\n" msgstr "Block %llu für Verzeichnis-Inode %llu fehlt\n" #: .././repair/dir2.c:2013 #, c-format msgid "can't read block %llu for directory inode %llu\n" msgstr "Block %llu für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/dir2.c:2020 #, c-format msgid "" "bad directory block magic # %#x in block %llu for directory inode %llu\n" msgstr "" "falsches Verzeichnisblatt magische # %#x in Block %llu für\n" "Verzeichnis-Inode %llu\n" #: .././repair/dir2.c:2098 #, c-format msgid "bad size/format for directory %llu\n" msgstr "falsche Größe/Format für Verzeichnis %llu\n" #: .././repair/init.c:42 msgid "ts_alloc: cannot allocate thread specific storage\n" msgstr "ts_alloc: Thread-spezifischer Speicher kann nicht zugewiesen werden\n" #: .././repair/init.c:94 #, c-format msgid "getrlimit(RLIMIT_FSIZE) failed!\n" msgstr "getrlimit(RLIMIT_FSIZE) fehlgeschlagen!\n" #: .././repair/init.c:102 #, c-format msgid "setrlimit failed - current: %lld, max: %lld\n" msgstr "setrlimit fehlgeschlagen - aktuell: %lld, max: %lld\n" #: .././repair/init.c:149 msgid "couldn't initialize XFS library\n" msgstr "XFS-Bibliothek kann nicht initialisiert werden\n" #: .././repair/incore.c:38 msgid "couldn't allocate block map pointers\n" msgstr "Blockkarten-Zeiger können nicht alloziert werden\n" #: .././repair/incore.c:41 msgid "couldn't allocate block map locks\n" msgstr "Blockkarten-Sperren können nicht alloziert werden\n" #: .././repair/incore.c:49 #, c-format msgid "couldn't allocate block map, size = %d\n" msgstr "Blockkarten kann nicht alloziert werden, Größe = %d\n" #: .././repair/incore.c:67 #, c-format msgid "couldn't allocate realtime block map, size = %llu\n" msgstr "Echtzeit-Blockkarten können nicht alloziert werden, Größe = %llu\n" #: .././repair/dinode.c:70 msgid "Unknown inode format.\n" msgstr "Unbekanntes Inodeformat.\n" #: .././repair/dinode.c:87 #, c-format msgid "clearing inode %llu attributes\n" msgstr "Attribute des Inodes %llu werden bereinigt\n" #: .././repair/dinode.c:90 #, c-format msgid "would have cleared inode %llu attributes\n" msgstr "Attribute des Inodes %llu könnten bereinigt worden sein\n" #: .././repair/dinode.c:493 #, c-format msgid "inode %llu - bad rt extent start block number %llu, offset %llu\n" msgstr "" "Inode %llu - falsche »rt«-Erweiterungs-Startblock-Nummer %llu,\n" "Versatz %llu\n" #: .././repair/dinode.c:499 #, c-format msgid "inode %llu - bad rt extent last block number %llu, offset %llu\n" msgstr "" "Inode %llu - falsche »rt«-Erweiterungs-Endblock-Nummer %llu,Versatz %llu\n" #: .././repair/dinode.c:505 #, c-format msgid "" "inode %llu - bad rt extent overflows - start %llu, end %llu, offset %llu\n" msgstr "" "Inode %llu - falsche »rt«-Erweiterungs-Überläufe - Start %llu,\n" "Ende %llu, Versatz %llu\n" #: .././repair/dinode.c:519 #, c-format msgid "malformed rt inode extent [%llu %llu] (fs rtext size = %u)\n" msgstr "" "missgebildete »rt«-Inode-Erweiterung [%llu %llu] (fs rtext Größe = %u)\n" #: .././repair/dinode.c:537 #, c-format msgid "" "data fork in rt ino %llu claims dup rt extent, off - %llu, start - %llu, " "count %llu\n" msgstr "" "Daten-Unterelement in rt ino %llu beansprucht »dup rt«-Erweiterung,aus - %" "llu, Start - %llu, Anzahl %llu\n" #: .././repair/dinode.c:557 #, c-format msgid "bad state in rt block map %llu\n" msgstr "falscher Status in »rt«-Block-Karte %llu\n" #: .././repair/dinode.c:563 #, c-format msgid "data fork in rt inode %llu found metadata block %llu in rt bmap\n" msgstr "" "Daten-Unterelement in rt ino %llu fand Metadaten-Block %llu in rt bmap\n" #: .././repair/dinode.c:573 #, c-format msgid "data fork in rt inode %llu claims used rt block %llu\n" msgstr "" "Daten-Unterelement in »rt«-Inode %llu beansprucht benutzten\n" "»rt«-Block %llu\n" #: .././repair/dinode.c:580 #, c-format msgid "illegal state %d in rt block map %llu\n" msgstr "unerlaubter Status %d in »rt«-Block-Karte %llu\n" #: .././repair/dinode.c:636 msgid "real-time" msgstr "Echtzeit" #: .././repair/dinode.c:638 msgid "regular" msgstr "regelmäßig" #: .././repair/dinode.c:647 #, c-format msgid "" "bmap rec out of order, inode %llu entry %d [o s c] [%llu %llu %llu], %d [%" "llu %llu %llu]\n" msgstr "" "bmap rec außer Betrieb, Inode %llu Eintrag %d [o s c] [%llu %llu %llu], %d [%" "llu %llu %llu]\n" #: .././repair/dinode.c:661 #, c-format msgid "zero length extent (off = %llu, fsbno = %llu) in ino %llu\n" msgstr "Länge-Null-Erweiterung (off = %llu, fsbno = %llu) in ino %llu\n" #: .././repair/dinode.c:690 #, c-format msgid "inode %llu - bad extent starting block number %llu, offset %llu\n" msgstr "Inode %llu - falsche erweiterte Startblock-Nummer %llu, Versatz %llu\n" #: .././repair/dinode.c:697 #, c-format msgid "inode %llu - bad extent last block number %llu, offset %llu\n" msgstr "Inode %llu - falsche erweiterte Endblock-Nummer %llu, Versatz %llu\n" #: .././repair/dinode.c:704 #, c-format msgid "inode %llu - bad extent overflows - start %llu, end %llu, offset %llu\n" msgstr "" "Inode %llu - falsche Erweiterungs-Überläufe - Start %llu, Ende %llu,\n" "Versatz %llu\n" #: .././repair/dinode.c:712 #, c-format msgid "" "inode %llu - extent offset too large - start %llu, count %llu, offset %llu\n" msgstr "" "Inode %llu - falsche Erweiterungs-Versatz zu groß - Start %llu,\n" "Anzahl %llu, Versatz %llu\n" #: .././repair/dinode.c:745 #, c-format msgid "" "%s fork in ino %llu claims dup extent, off - %llu, start - %llu, cnt %llu\n" msgstr "" "%s Unterelement in ino %llu beansprucht »dup«-Erweiterung, aus - %llu,\n" "Start - %llu, cnt %llu\n" #: .././repair/dinode.c:778 #, c-format msgid "%s fork in ino %llu claims free block %llu\n" msgstr "%s Unterelement in ino %llu beansprucht freien Block %llu\n" #: .././repair/dinode.c:787 #, c-format msgid "bad state in block map %llu\n" msgstr "falscher Status in Block-Karte %llu\n" #: .././repair/dinode.c:792 #, c-format msgid "%s fork in inode %llu claims metadata block %llu\n" msgstr "%s Unterelement in Inode %llu beansprucht Metadatenblock %llu\n" #: .././repair/dinode.c:800 #, c-format msgid "%s fork in %s inode %llu claims used block %llu\n" msgstr "%s Unterelement in %s Inode %llu beansprucht benutzten Block %llu\n" #: .././repair/dinode.c:806 #, c-format msgid "illegal state %d in block map %llu\n" msgstr "unerlaubter Status %d im Block-Karte %llu\n" #: .././repair/dinode.c:884 #, c-format msgid "cannot read inode (%u/%u), disk block %lld\n" msgstr "Inode (%u/%u) kann nicht gelesen werden, Plattenblock %lld\n" #: .././repair/dinode.c:995 .././repair/dinode.c:1052 #, c-format msgid "cannot read bmap block %llu\n" msgstr "»bmap«-Block %llu kann nicht gelesen werden\n" #: .././repair/dinode.c:1015 #, c-format msgid "# of bmap records in inode %llu exceeds max (%u, max - %u)\n" msgstr "" "# der »bmap«-Aufzeichnungen in Inode %llu überschreiten Maximum (%u,\n" "max - %u)\n" #: .././repair/dinode.c:1023 #, c-format msgid "" "- # of bmap records in inode %llu less than minimum (%u, min - %u), " "proceeding ...\n" msgstr "" "- # der »bmap«-Aufzeichnungen in Inode %llu weniger als das Minimum\n" "(%u, min - %u), fortsetzen ...\n" #: .././repair/dinode.c:1064 #, c-format msgid "# of bmap records in inode %llu greater than maximum (%u, max - %u)\n" msgstr "" "# der »bmap«-Aufzeichnungen in Inode %llu größer als das Maximum (%u, \n" "max - %u)\n" #: .././repair/dinode.c:1071 #, c-format msgid "" "- # of bmap records in inode %llu less than minimum (%u, min - %u), " "continuing...\n" msgstr "" "- # der »bmap«-Aufzeichnungen in Inode %llu weniger als das Minimum\n" "(%u, min - %u), fortfahren ...\n" #: .././repair/dinode.c:1088 #, c-format msgid "could not map block %llu\n" msgstr "Block %llu kann nicht kartiert werden\n" #: .././repair/dinode.c:1122 #, c-format msgid "get_bmapi() called for local inode %llu\n" msgstr "get_bmapi() für lokalen Inode %llu aufgerufen\n" #: .././repair/dinode.c:1130 #, c-format msgid "bad inode format for inode %llu\n" msgstr "falsches Inode-Format für Inode %llu\n" #: .././repair/dinode.c:1194 #, c-format msgid "bad level %d in inode %llu bmap btree root block\n" msgstr "falsche Stufe %d im Inode-%llu-»bmap btree«-Wurzelblock\n" #: .././repair/dinode.c:1199 #, c-format msgid "bad numrecs 0 in inode %llu bmap btree root block\n" msgstr "falsche numrecs 0 im Inode-%llu-»bmap btree«-Wurzelblock\n" #: .././repair/dinode.c:1208 #, c-format msgid "" "indicated size of %s btree root (%d bytes) greater than space in inode %llu %" "s fork\n" msgstr "" "angegebene Größe der »%s-btree«-Wurzel (%d Bytes) größer als Platz in Inode %" "llu %s Unterelement\n" #: .././repair/dinode.c:1247 #, c-format msgid "" "correcting key in bmbt root (was %llu, now %llu) in inode %llu %s fork\n" msgstr "" "Schlüssel in »bmbt«-Wurzel wird korrigiert (war %llu, nun %llu) in Inode\n" "%llu %s Unterelement\n" #: .././repair/dinode.c:1258 #, c-format msgid "" "bad key in bmbt root (is %llu, would reset to %llu) in inode %llu %s fork\n" msgstr "" "falscher Schlüssel in »bmbt«-Wurzel (ist %llu, könnte zu %llu\n" "zurückgesetzt werden) in Inode %llu %s Unterelement\n" #: .././repair/dinode.c:1274 #, c-format msgid "out of order bmbt root key %llu in inode %llu %s fork\n" msgstr "" "»bmbt«-Wurzel-Schlüssel %llu außer Betrieb in Inode %llu\n" "%s Unterelement\n" #: .././repair/dinode.c:1302 #, c-format msgid "bad fwd (right) sibling pointer (saw %llu should be NULLFSBLOCK)\n" msgstr "" "falscher fwd (rechts) Geschwisterzeiger (%llu gesehen könnte NULLFSBLOCK\n" "sein)\n" #: .././repair/dinode.c:1305 #, c-format msgid "\tin inode %u (%s fork) bmap btree block %llu\n" msgstr "\tin Inode %u (%s-Unterelement) bmap btree Block %llu\n" #: .././repair/dinode.c:1373 #, c-format msgid "local inode %llu data fork is too large (size = %lld, max = %d)\n" msgstr "" "lokales Inode-%llu-Daten-Unterelement ist zu groß (Größe = %lld, max = %d)\n" #: .././repair/dinode.c:1381 #, c-format msgid "local inode %llu attr fork too large (size %d, max = %d)\n" msgstr "" "lokales Inode-%llu-attr-Unterelement ist zu groß (Größe = %d, max = %d)\n" #: .././repair/dinode.c:1388 #, c-format msgid "local inode %llu attr too small (size = %d, min size = %d)\n" msgstr "" "lokales Inode-%llu-attr-Unterelement ist zu klein (Größe = %d, min = %d)\n" #: .././repair/dinode.c:1411 #, c-format msgid "mismatch between format (%d) and size (%lld) in symlink ino %llu\n" msgstr "" "Ungleichheit zwischen Format (%d) und Größe (%lld) in symbolischer\n" "Verknüpfung ino %llu\n" #: .././repair/dinode.c:1417 #, c-format msgid "mismatch between format (%d) and size (%lld) in symlink inode %llu\n" msgstr "" "Ungleichheit zwischen Format (%d) und Größe (%lld) in symbolischer\n" "Verknüpfung Inode %llu\n" #: .././repair/dinode.c:1432 #, c-format msgid "bad number of extents (%d) in symlink %llu data fork\n" msgstr "" "falsche Anzahl von Ausweitungen (%d) in symbolischem Verweis %llu\n" "des Datenunterelements\n" #: .././repair/dinode.c:1445 #, c-format msgid "bad extent #%d offset (%llu) in symlink %llu data fork\n" msgstr "" "falscher Umfang #%d Versatz (%llu) in symbolischem Verweis %llu\n" "des Datenunterelements\n" #: .././repair/dinode.c:1451 #, c-format msgid "bad extent #%d count (%llu) in symlink %llu data fork\n" msgstr "" "falsche Umfang #%d Anzahl (%llu) in symbolischem Verweis %llu des\n" "Datenunterelements\n" #: .././repair/dinode.c:1507 #, c-format msgid "symlink in inode %llu too long (%lld chars)\n" msgstr "symbolischer Verweis in Inode %llu zu lang (%lld Zeichen)\n" #: .././repair/dinode.c:1540 #, c-format msgid "cannot read inode %llu, file block %d, disk block %llu\n" msgstr "" "Inode %llu kann nicht gelesen werden, Dateiblock %d, Plattenblock %llu\n" #: .././repair/dinode.c:1562 #, c-format msgid "found illegal null character in symlink inode %llu\n" msgstr "" "unerlaubtes Null-Zeichen gefunden in symbolischem Verweis zu Inode %llu\n" #: .././repair/dinode.c:1576 .././repair/dinode.c:1586 #, c-format msgid "component of symlink in inode %llu too long\n" msgstr "Bestandteil des symbolischen Verweises in Inode %llu zu lang\n" #: .././repair/dinode.c:1611 #, c-format msgid "inode %llu has bad inode type (IFMNT)\n" msgstr "Inode %llu hat falschen Inode-Typ (IFMNT)\n" #: .././repair/dinode.c:1621 #, c-format msgid "size of character device inode %llu != 0 (%lld bytes)\n" msgstr "" "Größe des Inodes %llu des zeichenorientierten Gerätes !=0 (%lld Bytes)\n" #: .././repair/dinode.c:1626 #, c-format msgid "size of block device inode %llu != 0 (%lld bytes)\n" msgstr "Größe des Inodes %llu des blockorientierten Gerätes !=0 (%lld Bytes)\n" #: .././repair/dinode.c:1631 #, c-format msgid "size of socket inode %llu != 0 (%lld bytes)\n" msgstr "Größe des Socket-Inodes %llu !=0 (%lld Bytes)\n" #: .././repair/dinode.c:1636 #, c-format msgid "size of fifo inode %llu != 0 (%lld bytes)\n" msgstr "Größe des fifo-Inodes %llu !=0 (%lld Bytes)\n" #: .././repair/dinode.c:1641 #, c-format msgid "Internal error - process_misc_ino_types, illegal type %d\n" msgstr "Interner Fehler - process_misc_ino_types, unerlaubter Typ %d\n" #: .././repair/dinode.c:1668 #, c-format msgid "size of character device inode %llu != 0 (%llu blocks)\n" msgstr "" "Größe des Inodes %llu des zeichenorientierten Gerätes !=0 (%llu Bytes)\n" #: .././repair/dinode.c:1673 #, c-format msgid "size of block device inode %llu != 0 (%llu blocks)\n" msgstr "Größe des Inodes %llu des blockorientierten Gerätes !=0 (%llu Bytes)\n" #: .././repair/dinode.c:1678 #, c-format msgid "size of socket inode %llu != 0 (%llu blocks)\n" msgstr "Größe des Socket-Inodes %llu !=0 (%llu Bytes)\n" #: .././repair/dinode.c:1683 #, c-format msgid "size of fifo inode %llu != 0 (%llu blocks)\n" msgstr "Größe des fifo-Inodes %llu !=0 (%llu Bytes)\n" #: .././repair/dinode.c:1761 #, c-format msgid "root inode %llu has bad type 0x%x\n" msgstr "Wurzel-Inode %llu hat falschen Typ 0x%x\n" #: .././repair/dinode.c:1765 msgid "resetting to directory\n" msgstr "Verzeichnis wird zurückgesetzt\n" #: .././repair/dinode.c:1769 msgid "would reset to directory\n" msgstr "Verzeichnis könnte zurückgesetzt werden\n" #: .././repair/dinode.c:1775 #, c-format msgid "user quota inode %llu has bad type 0x%x\n" msgstr "Benutzer-Quota-Inode %llu hat falschen Typ 0x%x\n" #: .././repair/dinode.c:1784 #, c-format msgid "group quota inode %llu has bad type 0x%x\n" msgstr "Gruppen-Quota-Inode %llu hat falschen Typ 0x%x\n" #: .././repair/dinode.c:1793 #, c-format msgid "realtime summary inode %llu has bad type 0x%x, " msgstr "Echtzeit-Summen-Inode %llu hat falschen Typ 0x%x, " #: .././repair/dinode.c:1796 .././repair/dinode.c:1815 msgid "resetting to regular file\n" msgstr "es wird auf normale Datei zurückgesetzt\n" #: .././repair/dinode.c:1800 .././repair/dinode.c:1819 msgid "would reset to regular file\n" msgstr "es könnte auf normale Datei zurückgesetzt werden\n" #: .././repair/dinode.c:1804 #, c-format msgid "bad # of extents (%u) for realtime summary inode %llu\n" msgstr "falsche # des Umfangs (%u) für Echtzeit-Summen-Inode %llu\n" #: .././repair/dinode.c:1812 #, c-format msgid "realtime bitmap inode %llu has bad type 0x%x, " msgstr "Echtzeit-Bitmap-Inode %llu hat falschen Typ 0x%x, " #: .././repair/dinode.c:1823 #, c-format msgid "bad # of extents (%u) for realtime bitmap inode %llu\n" msgstr "falsche # von Extents (%u) für Echtzeit-Bitmap-Inode %llu\n" #: .././repair/dinode.c:1858 #, c-format msgid "mismatch between format (%d) and size (%lld) in directory ino %llu\n" msgstr "" "Unterschied zwischen Format (%d) und Größe (%lld) im Verzeichnis ino %llu\n" #: .././repair/dinode.c:1864 #, c-format msgid "directory inode %llu has bad size %lld\n" msgstr "Verzeichnis-Inode %llu hat falsche Größe %lld\n" #: .././repair/dinode.c:1872 #, c-format msgid "bad data fork in symlink %llu\n" msgstr "falsches Daten-Unterelement in symbolischem Verweis %llu\n" #: .././repair/dinode.c:1892 #, c-format msgid "found inode %llu claiming to be a real-time file\n" msgstr "gefundener Inode %llu beansprucht, eine Echtzeit-Datei zu sein\n" #: .././repair/dinode.c:1901 #, c-format msgid "realtime bitmap inode %llu has bad size %lld (should be %lld)\n" msgstr "Echtzeit-Bitmap-Inode %llu hat falsche Größe %lld (sollte %lld sein)\n" #: .././repair/dinode.c:1911 #, c-format msgid "realtime summary inode %llu has bad size %lld (should be %d)\n" msgstr "Echtzeit-Summen-Inode %llu hat falsche Größe %lld (könnte %d sein)\n" #: .././repair/dinode.c:1939 #, c-format msgid "bad attr fork offset %d in dev inode %llu, should be %d\n" msgstr "" "falscher attr-Unterelement-Versatz %d in dev-Inode %llu, könnte %d sein\n" #: .././repair/dinode.c:1949 #, c-format msgid "bad attr fork offset %d in inode %llu, max=%d\n" msgstr "falscher attr-Unterelement-Versatz %d in Inode %llu, maximal=%d\n" #: .././repair/dinode.c:1956 #, c-format msgid "unexpected inode format %d\n" msgstr "unerwartetes Inode-Format %d\n" #: .././repair/dinode.c:1976 #, c-format msgid "correcting nblocks for inode %llu, was %llu - counted %llu\n" msgstr "nblocks für Inode %llu werden korrigiert, war %llu - gezählt %llu\n" #: .././repair/dinode.c:1982 #, c-format msgid "bad nblocks %llu for inode %llu, would reset to %llu\n" msgstr "" "falsche nblocks %llu für Inode %llu, könnte auf %llu zurückgesetzt werden\n" #: .././repair/dinode.c:1989 #, c-format msgid "too many data fork extents (%llu) in inode %llu\n" msgstr "zu großes Daten-Unterelement-Ausmaß (%llu) in Inode %llu\n" #: .././repair/dinode.c:1995 #, c-format msgid "correcting nextents for inode %llu, was %d - counted %llu\n" msgstr "nextents für Inode %llu werden korrigiert, waren %d - gezählt %llu\n" #: .././repair/dinode.c:2001 #, c-format msgid "bad nextents %d for inode %llu, would reset to %llu\n" msgstr "" "falsche nextents %d für Inode %llu, könnten auf %llu zurückgesetzt\n" "werden\n" #: .././repair/dinode.c:2008 #, c-format msgid "too many attr fork extents (%llu) in inode %llu\n" msgstr "zu großes Daten-Unterelement-Ausmaß (%llu) in Inode %llu\n" #: .././repair/dinode.c:2014 #, c-format msgid "correcting anextents for inode %llu, was %d - counted %llu\n" msgstr "anextents für Inode %llu werden korrigiert, waren %d - gezählt %llu\n" #: .././repair/dinode.c:2020 #, c-format msgid "bad anextents %d for inode %llu, would reset to %llu\n" msgstr "" "falsche anextents %d für Inode %llu, könnten auf %llu zurückgesetzt\n" "werden\n" #: .././repair/dinode.c:2075 .././repair/dinode.c:2113 #, c-format msgid "unknown format %d, ino %llu (mode = %d)\n" msgstr "unbekanntes Format %d, ino %llu (Modus = %d)\n" #: .././repair/dinode.c:2080 #, c-format msgid "bad data fork in inode %llu\n" msgstr "falsches Daten-Unterelement in Inode %llu\n" #: .././repair/dinode.c:2152 #, c-format msgid "bad attribute format %d in inode %llu, " msgstr "falsches Attribut-Format %d in Inode %llu, " #: .././repair/dinode.c:2155 msgid "resetting value\n" msgstr "Wert wird zurückgesetzt\n" #: .././repair/dinode.c:2159 msgid "would reset value\n" msgstr "Wert könnte zurückgesetzt werden\n" #: .././repair/dinode.c:2189 .././repair/attr_repair.c:977 #, c-format msgid "illegal attribute format %d, ino %llu\n" msgstr "unerlaubtes Attributs-Format %d, ino %llu\n" #: .././repair/dinode.c:2204 #, c-format msgid "bad attribute fork in inode %llu" msgstr "falsches Attribut-Unterelement in Inode %llu" #: .././repair/dinode.c:2208 msgid ", clearing attr fork\n" msgstr ", bereinige attr-Unterelement\n" #: .././repair/dinode.c:2217 msgid ", would clear attr fork\n" msgstr ", könnte attr-Unterelement bereinigen\n" #: .././repair/dinode.c:2245 #, c-format msgid "illegal attribute fmt %d, ino %llu\n" msgstr "unerlaubtes Attribut fmt %d, ino %llu\n" #: .././repair/dinode.c:2264 #, c-format msgid "problem with attribute contents in inode %llu\n" msgstr "Problem mit Attributs-Inhalt in Inode %llu\n" #: .././repair/dinode.c:2272 msgid "would clear attr fork\n" msgstr "könnte attr-Unterelement bereinigen\n" #: .././repair/dinode.c:2314 #, c-format msgid "version 2 inode %llu claims > %u links, " msgstr "Version 2 Inode %llu beansprucht > %u Verweise, " #: .././repair/dinode.c:2317 msgid "updating superblock version number\n" msgstr "Superblock-Versionsnummer wird aktualisiert\n" #: .././repair/dinode.c:2320 msgid "would update superblock version number\n" msgstr "Superblock-Versionsnummer könnte aktualisiert werden\n" #: .././repair/dinode.c:2328 #, c-format msgid "WARNING: version 2 inode %llu claims > %u links, " msgstr "WARNUNG: Version 2 Inode %llu beansprucht > %u Verweise, " #: .././repair/dinode.c:2332 #, c-format msgid "" "converting back to version 1,\n" "this may destroy %d links\n" msgstr "" "es wird zu Version 1 zurück umgewandelt,\n" "das kann %d Verweise zerstören\n" #: .././repair/dinode.c:2342 #, c-format msgid "" "would convert back to version 1,\n" "\tthis might destroy %d links\n" msgstr "" "es könnte zu Version 1 zurück umgewandelt werden,\n" "\tdas könnte %d Verweise zerstören\n" #: .././repair/dinode.c:2357 #, c-format msgid "found version 2 inode %llu, " msgstr "Version-2-Inode %llu gefunden, " #: .././repair/dinode.c:2359 msgid "converting back to version 1\n" msgstr "wird zu Version 1 zurück verwandelt\n" #: .././repair/dinode.c:2365 msgid "would convert back to version 1\n" msgstr "es könnte zu Version 1 zurück umgewandelt werden\n" #: .././repair/dinode.c:2378 #, c-format msgid "clearing obsolete nlink field in version 2 inode %llu, was %d, now 0\n" msgstr "" "überflüssiges nlink-Feld in Version-2-Inode %llu wurde bereinigt, war %d,\n" "nun 0\n" #: .././repair/dinode.c:2384 #, c-format msgid "" "would clear obsolete nlink field in version 2 inode %llu, currently %d\n" msgstr "" "überflüssiges nlink-Feld in Version-2-Inode %llu könnte bereinigt werden,\n" "aktuell %d\n" #: .././repair/dinode.c:2457 #, c-format msgid "bad magic number 0x%x on inode %llu%c" msgstr "falsche magische Nummer 0x%x auf Inode %llu%c" #: .././repair/dinode.c:2462 msgid " resetting magic number\n" msgstr " magische Nummer wird zurückgesetzt\n" #: .././repair/dinode.c:2466 msgid " would reset magic number\n" msgstr " magische Nummer würde zurückgesetzt\n" #: .././repair/dinode.c:2474 #, c-format msgid "bad version number 0x%x on inode %llu%c" msgstr "falsche Versionsnummer 0x%x auf Inode %llu%c" #: .././repair/dinode.c:2479 msgid " resetting version number\n" msgstr " Versionsnummer wird zurückgesetzt\n" #: .././repair/dinode.c:2485 msgid " would reset version number\n" msgstr " Versionsnummer könnte zurückgesetzt werden\n" #: .././repair/dinode.c:2494 #, c-format msgid "bad (negative) size %lld on inode %llu\n" msgstr "falsche (negative) Größe %lld auf Inode %llu\n" #: .././repair/dinode.c:2525 #, c-format msgid "imap claims a free inode %llu is in use, " msgstr "imap beansprucht einen freien Inode, %llu ist in Benutzung" #: .././repair/dinode.c:2527 msgid "correcting imap and clearing inode\n" msgstr "imap wird korrigiert und Inode bereinigt\n" #: .././repair/dinode.c:2531 msgid "would correct imap and clear inode\n" msgstr "imap könnte korrigiert und Inode bereinigt werden\n" #: .././repair/dinode.c:2547 #, c-format msgid "bad inode format in inode %llu\n" msgstr "falsches Inode-Format in Inode %llu\n" #: .././repair/dinode.c:2600 #, c-format msgid "bad inode type %#o inode %llu\n" msgstr "falscher Inode-Typ %#o Inode %llu\n" #: .././repair/dinode.c:2623 #, c-format msgid "bad non-zero extent size %u for non-realtime/extsize inode %llu, " msgstr "falsches Nicht-Null-Ausmaß %u für Nicht-Echtzeit/extsize Inode %llu, " #: .././repair/dinode.c:2627 msgid "resetting to zero\n" msgstr "wird auf Null zurückgesetzt\n" #: .././repair/dinode.c:2631 msgid "would reset to zero\n" msgstr "könnte auf Null zurückgesetzt werden\n" #: .././repair/dinode.c:2686 #, c-format msgid "problem with directory contents in inode %llu\n" msgstr "Problem mit Verzeichnis-Inhalt in Inode %llu\n" #: .././repair/dinode.c:2693 #, c-format msgid "problem with symbolic link in inode %llu\n" msgstr "Problem mit symbolischem Verweis in Inode %llu\n" #: .././repair/dinode.c:2790 #, c-format msgid "processing inode %d/%d\n" msgstr "Inode %d/%d wird verarbeitet\n" #: .././repair/agheader.c:35 #, c-format msgid "bad magic # 0x%x for agf %d\n" msgstr "flasche magische # 0x%x für agf %d\n" #: .././repair/agheader.c:44 #, c-format msgid "bad version # %d for agf %d\n" msgstr "falsche Version # %d für agf %d\n" #: .././repair/agheader.c:53 #, c-format msgid "bad sequence # %d for agf %d\n" msgstr "falsche Sequenz # %d für agf %d\n" #: .././repair/agheader.c:63 #, c-format msgid "bad length %d for agf %d, should be %d\n" msgstr "falsche Länge %d für agf %d, könnte %d sein\n" #: .././repair/agheader.c:76 #, c-format msgid "bad length %d for agf %d, should be %llu\n" msgstr "falsche Länge %d für agf %d, könnte %llu sein\n" #: .././repair/agheader.c:90 #, c-format msgid "flfirst %d in agf %d too large (max = %d)\n" msgstr "flfirst %d in agf %d zu groß (Maximum = %d)\n" #: .././repair/agheader.c:97 #, c-format msgid "fllast %d in agf %d too large (max = %d)\n" msgstr "fllast %d in agf %d zu groß (Maximum = %d)\n" #: .././repair/agheader.c:118 #, c-format msgid "bad magic # 0x%x for agi %d\n" msgstr "falsche magische # 0x%x für agi %d\n" #: .././repair/agheader.c:127 #, c-format msgid "bad version # %d for agi %d\n" msgstr "falsche Version # %d für agi %d\n" #: .././repair/agheader.c:136 #, c-format msgid "bad sequence # %d for agi %d\n" msgstr "falsche Sequenz # %d für agi %d\n" #: .././repair/agheader.c:146 #, c-format msgid "bad length # %d for agi %d, should be %d\n" msgstr "falsche Länge %d für agi %d, könnte %d sein\n" #: .././repair/agheader.c:159 #, c-format msgid "bad length # %d for agi %d, should be %llu\n" msgstr "falsche Länge %d für agi %d, könnte %llu sein\n" #: .././repair/agheader.c:270 #, c-format msgid "zeroing unused portion of %s superblock (AG #%u)\n" msgstr "ungenutzten Anteil des »%s«-Superblocks nullen (AG #%u)\n" #: .././repair/agheader.c:271 .././repair/agheader.c:277 msgid "primary" msgstr "primär" #: .././repair/agheader.c:271 .././repair/agheader.c:277 msgid "secondary" msgstr "sekundär" #: .././repair/agheader.c:276 #, c-format msgid "would zero unused portion of %s superblock (AG #%u)\n" msgstr "" "ungenutzter Anteil des »%s«-Superblocks sollte genullt werden (AG #%u)\n" #: .././repair/agheader.c:295 #, c-format msgid "bad flags field in superblock %d\n" msgstr "falsches Kennzeichnungsfeld im Superblock %d\n" #: .././repair/agheader.c:312 #, c-format msgid "non-null user quota inode field in superblock %d\n" msgstr "Benutzer-Quota-Inode-Feld im Superblock %d nicht Null\n" #: .././repair/agheader.c:325 #, c-format msgid "non-null group quota inode field in superblock %d\n" msgstr "Gruppen-Quota-Inode-Feld im Superblock %d nicht Null\n" #: .././repair/agheader.c:337 #, c-format msgid "non-null quota flags in superblock %d\n" msgstr "Quota-Markierungen im Superblock %d nicht Null\n" #: .././repair/agheader.c:355 #, c-format msgid "bad shared version number in superblock %d\n" msgstr "falsche geteilte Versionsnummer im Superblock %d\n" #: .././repair/agheader.c:367 #, c-format msgid "bad inode alignment field in superblock %d\n" msgstr "falsches Inode-Ausrichtungs-Feld im Superblock %d\n" #: .././repair/agheader.c:380 #, c-format msgid "bad stripe unit/width fields in superblock %d\n" msgstr "falsche Stripe-Einheit/Breite Felder in Superblock %d\n" #: .././repair/agheader.c:398 #, c-format msgid "bad log/data device sector size fields in superblock %d\n" msgstr "falsche Protokoll/Daten-Gerät-Sektorenfeldgröße im Superblock %d\n" #: .././repair/agheader.c:429 #, c-format msgid "bad on-disk superblock %d - %s\n" msgstr "falscher on-disk-Superblock %d - %s\n" #: .././repair/agheader.c:436 #, c-format msgid "primary/secondary superblock %d conflict - %s\n" msgstr "primäre/sekundärer Superblock-%d-Konflikt - %s\n" #: .././repair/dino_chunks.c:59 #, c-format msgid "cannot read agbno (%u/%u), disk block %lld\n" msgstr "agbno (%u/%u) kann nicht gelesen werden, Plattenblock %lld\n" #: .././repair/dino_chunks.c:157 #, c-format msgid "uncertain inode block %d/%d already known\n" msgstr "unsicherer Inode-Block %d/%d bereits bekannt\n" #: .././repair/dino_chunks.c:173 .././repair/dino_chunks.c:443 #: .././repair/dino_chunks.c:505 #, c-format msgid "inode block %d/%d multiply claimed, (state %d)\n" msgstr "Inode-Block %d/%d mehrfach beansprucht, (Status %d)\n" #: .././repair/dino_chunks.c:180 .././repair/dino_chunks.c:510 #, c-format msgid "inode block %d/%d bad state, (state %d)\n" msgstr "Inode-Block %d/%d Status schlecht, (Status %d)\n" #: .././repair/dino_chunks.c:450 #, c-format msgid "uncertain inode block overlap, agbno = %d, ino = %llu\n" msgstr "unsichere Inode-Block-Überschneidung, agbno = %d, ino = %llu\n" #: .././repair/dino_chunks.c:492 #, c-format msgid "uncertain inode block %llu already known\n" msgstr "unsicherer Inode-Block %llu bereits bekannt\n" #: .././repair/dino_chunks.c:628 #, c-format msgid "failed to allocate %d bytes of memory\n" msgstr "%d Bytes Speicher zu allozieren fehlgeschlagen\n" #: .././repair/dino_chunks.c:640 #, c-format msgid "cannot read inode %llu, disk block %lld, cnt %d\n" msgstr "Inode %llu kann nicht gelesen werden, Plattenblock %lld, cnt %d\n" #: .././repair/dino_chunks.c:757 .././repair/dino_chunks.c:938 #: .././repair/phase3.c:74 #, c-format msgid "bad state in block map %d\n" msgstr "falscher Status in Block-Kartierung %d\n" #: .././repair/dino_chunks.c:761 .././repair/dino_chunks.c:943 #, c-format msgid "inode block %llu multiply claimed, state was %d\n" msgstr "Inode-Block %llu mehrfach beansprucht, Status war %d\n" #: .././repair/dino_chunks.c:796 #, c-format msgid "imap claims in-use inode %llu is free, " msgstr "von imap in Benutzung beanspruchter Inode %llu ist frei, " #: .././repair/dino_chunks.c:803 msgid "correcting imap\n" msgstr "imap wird korrigiert\n" #: .././repair/dino_chunks.c:805 msgid "would correct imap\n" msgstr "imap könnte korrigiert werden\n" #: .././repair/dino_chunks.c:851 #, c-format msgid "cleared root inode %llu\n" msgstr "bereinigter Wurzel-Inode %llu\n" #: .././repair/dino_chunks.c:855 #, c-format msgid "would clear root inode %llu\n" msgstr "könnte Wurzel-Inode %llu bereinigen\n" #: .././repair/dino_chunks.c:864 #, c-format msgid "cleared realtime bitmap inode %llu\n" msgstr "geleerter Echtzeit-Bitmap-Inode %llu\n" #: .././repair/dino_chunks.c:869 #, c-format msgid "would clear realtime bitmap inode %llu\n" msgstr "würde Echtzeit-Bitmap-Inode %llu leeren\n" #: .././repair/dino_chunks.c:879 #, c-format msgid "cleared realtime summary inode %llu\n" msgstr "bereinigter Echtzeit-Zusammenfassungs-Inode %llu\n" #: .././repair/dino_chunks.c:884 #, c-format msgid "would clear realtime summary inode %llu\n" msgstr "könnte Echtzeit-Zusammenfassungs-Inode %llu bereinigen\n" #: .././repair/dino_chunks.c:890 #, c-format msgid "cleared inode %llu\n" msgstr "bereinigter Inode %llu\n" #: .././repair/dino_chunks.c:893 #, c-format msgid "would have cleared inode %llu\n" msgstr "Inode %llu könnte bereinigt worden sein\n" #: .././repair/dino_chunks.c:1099 .././repair/dino_chunks.c:1134 #: .././repair/dino_chunks.c:1248 msgid "found inodes not in the inode allocation tree\n" msgstr "Inodes wurden nicht im Inode-Allokierungs-Baum gefunden\n" #: .././repair/phase3.c:117 #, c-format msgid "cannot read agi block %lld for ag %u\n" msgstr "agi-Block %lld für ag %u kann nicht gelesen werden\n" #: .././repair/phase3.c:139 #, c-format msgid "error following ag %d unlinked list\n" msgstr "Fehler folgt ag %d unverknüpfter Liste\n" #: .././repair/phase3.c:211 msgid "Phase 3 - for each AG...\n" msgstr "Phase 3 - für jedes AG...\n" #: .././repair/phase3.c:213 msgid " - scan and clear agi unlinked lists...\n" msgstr " - agi unverknüpfte Listen werden gescannt und bereinigt...\n" #: .././repair/phase3.c:215 msgid " - scan (but don't clear) agi unlinked lists...\n" msgstr "" " - agi unverknüpfte Listen werden gescannt (aber nicht bereinigt...\n" #: .././repair/phase3.c:235 msgid " - process known inodes and perform inode discovery...\n" msgstr "" " - bekannte Inodes werden behandelt und Inode-Entdeckung wird\n" "durchgeführt...\n" #: .././repair/phase3.c:246 msgid " - process newly discovered inodes...\n" msgstr " - neu entdeckte Inodes werden behandelt...\n" #: .././repair/phase6.c:63 #, c-format msgid "malloc failed add_dotdot_update (%u bytes)\n" msgstr "malloc fehlgeschlagen add_dotdot_update (%u Bytes)\n" #: .././repair/phase6.c:174 #, c-format msgid "malloc failed in dir_hash_add (%u bytes)\n" msgstr "malloc fehlgeschlagen in dir_hash_add (%u Bytes)\n" #: .././repair/phase6.c:228 msgid "ok" msgstr "ok" #: .././repair/phase6.c:229 msgid "duplicate leaf" msgstr "doppeltes Blatt" #: .././repair/phase6.c:230 msgid "hash value mismatch" msgstr "Hash-Wert stimmt nicht überein" #: .././repair/phase6.c:231 msgid "no data entry" msgstr "kein Dateneintrag" #: .././repair/phase6.c:232 msgid "no leaf entry" msgstr "kein Blatteintrag" #: .././repair/phase6.c:233 msgid "bad stale count" msgstr "falsche Stale-Anzahl" #: .././repair/phase6.c:241 #, c-format msgid "bad hash table for directory inode %llu (%s): " msgstr "falsche Hash-Tabelle für Verzeichnis-Inode %llu (%s): " #: .././repair/phase6.c:244 msgid "rebuilding\n" msgstr "erneut bilden\n" #: .././repair/phase6.c:246 msgid "would rebuild\n" msgstr "könnte erneut bilden\n" #: .././repair/phase6.c:282 msgid "calloc failed in dir_hash_init\n" msgstr "calloc fehlgeschlagen in dir_hash_init\n" #: .././repair/phase6.c:412 msgid "ran out of disk space!\n" msgstr "lief außerhalb des Plattenplatzes!\n" #: .././repair/phase6.c:414 #, c-format msgid "xfs_trans_reserve returned %d\n" msgstr "xfs_trans_reserve zurückgegeben %d\n" #: .././repair/phase6.c:443 .././repair/phase6.c:536 #, c-format msgid "couldn't iget realtime bitmap inode -- error - %d\n" msgstr "" "iget für Echtezeit-Bitmap-Inode konnte nicht ausgeführt werden --\n" "Fehler - %d\n" #: .././repair/phase6.c:493 #, c-format msgid "couldn't allocate realtime bitmap, error = %d\n" msgstr "Echtzeit-Bitmap kann nicht alloziert werden, Fehler = %d\n" #: .././repair/phase6.c:506 #, c-format msgid "allocation of the realtime bitmap failed, error = %d\n" msgstr "Allokation des Echtzeit-Bitmaps fehlgeschlagen, Fehler = %d\n" #: .././repair/phase6.c:549 #, c-format msgid "couldn't map realtime bitmap block %llu, error = %d\n" msgstr "Echtzeit-Bitmap-Block %llu kann nicht kartiert werden, Fehler = %d\n" #: .././repair/phase6.c:562 #, c-format msgid "can't access block %llu (fsbno %llu) of realtime bitmap inode %llu\n" msgstr "" "auf Block %llu (fsbno %llu) des Echtzeit-Bitmap-Inodes %llu kann nicht\n" "zugegriffen werden.\n" #: .././repair/phase6.c:605 .././repair/phase6.c:676 #, c-format msgid "couldn't iget realtime summary inode -- error - %d\n" msgstr "" "iget für Echtezeit-Zusammenfassungs-Inode konnte nicht ausgeführt werden\n" "-- Fehler - %d\n" #: .././repair/phase6.c:618 #, c-format msgid "couldn't map realtime summary inode block %llu, error = %d\n" msgstr "" "Echtzeit-Zusammenfassungs-Inode-Block %llu kann nicht kartiert werden,\n" "Fehler = %d\n" #: .././repair/phase6.c:631 #, c-format msgid "can't access block %llu (fsbno %llu) of realtime summary inode %llu\n" msgstr "" "auf Block %llu (fsbno %llu) des Echtzeit-Zusammenfassungs-Inodes %llu\n" "kann nicht zugegriffen werden.\n" #: .././repair/phase6.c:732 #, c-format msgid "couldn't allocate realtime summary inode, error = %d\n" msgstr "" "Echtzeit-Zusammenfassungs-Inode kann nicht alloziert werden, Fehler = %d\n" #: .././repair/phase6.c:745 #, c-format msgid "allocation of the realtime summary ino failed, error = %d\n" msgstr "" "Allokation des Echtzeit-Zusammenfassungs-ino fehlgeschlagen, Fehler = %d\n" #: .././repair/phase6.c:775 #, c-format msgid "could not iget root inode -- error - %d\n" msgstr "iget für Wurzel-Inode konnte nicht ausgeführt werden -- Fehler - %d\n" #: .././repair/phase6.c:843 #, c-format msgid "%d - couldn't iget root inode to obtain %s\n" msgstr "" "%d - iget für Wurzel-Inode konnte nicht ausgeführt werden, um %s zu\n" "erhalten\n" #: .././repair/phase6.c:874 #, c-format msgid "%s inode allocation failed %d\n" msgstr "%s Inode-Allokation fehlgeschlagen %d\n" #: .././repair/phase6.c:892 #, c-format msgid "can't make %s, createname error %d\n" msgstr "%s kann nicht gemacht werden, createname-Fehler %d\n" #: .././repair/phase6.c:910 #, c-format msgid "%s directory creation failed -- bmapf error %d\n" msgstr "%s Verzeichnis erzeugen fehlgeschlagen -- bmapf Fehler %d\n" #: .././repair/phase6.c:953 #, c-format msgid "%d - couldn't iget orphanage inode\n" msgstr "%d - iget für verwaisten Inode konnte nicht ausgeführt werden\n" #: .././repair/phase6.c:966 #, c-format msgid "%d - couldn't iget disconnected inode\n" msgstr "%d - iget für getrennten Inode konnte nicht ausgeführt werden\n" #: .././repair/phase6.c:986 .././repair/phase6.c:1030 #: .././repair/phase6.c:1087 .././repair/phase6.c:1730 #, c-format msgid "space reservation failed (%d), filesystem may be out of space\n" msgstr "" "Platzreservierung fehlgeschlagen (%d), auf dem Dateisystem könnte kein\n" "Platz sein\n" #: .././repair/phase6.c:997 .././repair/phase6.c:1042 #: .././repair/phase6.c:1098 #, c-format msgid "name create failed in %s (%d), filesystem may be out of space\n" msgstr "" "Erzeugen des Namens fehlgeschlagen in %s (%d), auf dem Dateisystem\n" "könnte kein Platz sein\n" #: .././repair/phase6.c:1010 #, c-format msgid "creation of .. entry failed (%d), filesystem may be out of space\n" msgstr "" "Erzeugung von ..-Eintrag fehlgeschlagen (%d), auf dem Dateisystem könnte\n" "kein Platz sein\n" #: .././repair/phase6.c:1019 #, c-format msgid "bmap finish failed (err - %d), filesystem may be out of space\n" msgstr "" "Beenden von bmap fehlgeschlagen (err - %d), auf dem Dateisystem könnte\n" "kein Platz sein\n" #: .././repair/phase6.c:1061 #, c-format msgid "name replace op failed (%d), filesystem may be out of space\n" msgstr "" "op-Namen ersetzen fehlgeschlagen (%d), auf dem Dateisystem könnte kein\n" "Platz sein\n" #: .././repair/phase6.c:1068 .././repair/phase6.c:1108 #: .././repair/phase6.c:1753 #, c-format msgid "bmap finish failed (%d), filesystem may be out of space\n" msgstr "" "Beenden von bmap fehlgeschlagen (%d), auf dem Dateisystem könnte kein\n" "Platz sein\n" #: .././repair/phase6.c:1149 .././repair/phase6.c:1548 msgid "dir" msgstr "dir" #: .././repair/phase6.c:1158 .././repair/phase6.c:1162 #, c-format msgid "can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n" msgstr "" "Block %d in %s Inode %llu kann nicht kartiert werden, xfs_bmapi gibt %d\n" "zurück, nmap = %d\n" #: .././repair/phase6.c:1170 .././repair/phase6.c:1173 #: .././repair/phase6.c:1626 .././repair/phase6.c:1630 #, c-format msgid "block %d in %s ino %llu doesn't exist\n" msgstr "Block %d in %s ino %llu existiert nicht\n" #: .././repair/phase6.c:1228 .././repair/phase6.c:1232 #, c-format msgid "can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n" msgstr "" "Block %d in %s ino %llu kann nicht kartiert werden, xfs_bmapi gibt %d\n" "zurück, nmap = %d\n" #: .././repair/phase6.c:1240 .././repair/phase6.c:1244 #, c-format msgid "block %d in %s inode %llu doesn't exist\n" msgstr "Block %d in %s Inode %llu existiert nicht\n" #: .././repair/phase6.c:1267 msgid ", marking entry to be junked\n" msgstr ", Eintrag wird zum verwerfen gekennzeichnet\n" #: .././repair/phase6.c:1271 msgid ", would junk entry\n" msgstr ", Eintrag könnte verworfen werden\n" #: .././repair/phase6.c:1387 #, c-format msgid "entry \"%s\" in dir inode %llu points to non-existent inode %llu" msgstr "" "Eintrag »%s« in dir-Inode %llu zeigt auf nicht existierenden Inode %llu" #: .././repair/phase6.c:1405 #, c-format msgid "entry \"%s\" in dir inode %llu points to free inode %llu" msgstr "Eintrag »%s« in dir-Inode %llu zeigt auf freien Inode %llu" #: .././repair/phase6.c:1421 .././repair/phase6.c:2086 #: .././repair/phase6.c:2711 .././repair/phase6.c:3038 #, c-format msgid "%s (ino %llu) in root (%llu) is not a directory" msgstr "%s (ino %llu) in Wurzel (%llu) ist kein Verzeichnis" #: .././repair/phase6.c:1443 .././repair/phase6.c:2107 #: .././repair/phase6.c:2728 .././repair/phase6.c:3055 #, c-format msgid "entry \"%s\" (ino %llu) in dir %llu is a duplicate name" msgstr "Eintrag »%s« (ino %llu) in dir %llu ist ein doppelter Name" #: .././repair/phase6.c:1474 #, c-format msgid "" "entry \"%s\" in dir %llu points to an already connected dir inode %llu,\n" msgstr "" "Eintrag »%s« in dir %llu zeigt auf einen bereits verbundenen\n" "dir-Inode %llu,\n" #: .././repair/phase6.c:1483 .././repair/phase6.c:2208 #: .././repair/phase6.c:2761 .././repair/phase6.c:3086 #, c-format msgid "" "entry \"%s\" in dir ino %llu doesn't have a .. entry, will set it in ino %" "llu.\n" msgstr "" "Eintrag »%s« in dir %llu hat keinen ..-Eintrag, wird in ino %llu gesetzt.\n" #: .././repair/phase6.c:1491 #, c-format msgid "" "entry \"%s\" in dir ino %llu not consistent with .. value (%llu) in ino %" "llu,\n" msgstr "" "Eintrag »%s« in dir ino %llu nicht vollständig mit ..-Wert (%llu) in ino %" "llu,\n" #: .././repair/phase6.c:1506 .././repair/phase6.c:2232 #, c-format msgid "\twill clear entry \"%s\"\n" msgstr "\tEintrag »%s« wird bereinigt\n" #: .././repair/phase6.c:1509 .././repair/phase6.c:2235 #, c-format msgid "\twould clear entry \"%s\"\n" msgstr "\tEintrag »%s« könnte bereinigt werden\n" #: .././repair/phase6.c:1553 #, c-format msgid "cannot map block 0 of directory inode %llu\n" msgstr "Block 0 des Verzeichnis-Inodes %llu kann nicht kartiert werden\n" #: .././repair/phase6.c:1576 #, c-format msgid "bad magic # (0x%x) for dir ino %llu leaf block (bno %u fsbno %llu)\n" msgstr "" "falsche magische # (0x%x) für ino %llu Blatt-Block (bno %u fsbno %llu)\n" #: .././repair/phase6.c:1613 .././repair/phase6.c:1617 #, c-format msgid "can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n" msgstr "" "Blatt-Block %d in dir %llu kann nicht kartiert werden, xfs_bmapi gibt %d\n" "zurück, nmap = %d\n" #: .././repair/phase6.c:1669 #, c-format msgid "rebuilding directory inode %llu\n" msgstr "Verzeichnis-Inode %llu wird erneut erzeugt\n" #: .././repair/phase6.c:1694 #, c-format msgid "xfs_bmap_last_offset failed -- error - %d\n" msgstr "xfs_bmap_last_offset fehlgeschlagen -- Fehler - %d\n" #: .././repair/phase6.c:1701 #, c-format msgid "xfs_bunmapi failed -- error - %d\n" msgstr "xfs_bunmapi fehlgeschlagen -- Fehler - %d\n" #: .././repair/phase6.c:1743 #, c-format msgid "name create failed in ino %llu (%d), filesystem may be out of space\n" msgstr "" "Erzeugen des Namens fehlgeschlagen in ino %llu (%d), auf dem Dateisystem\n" "könnte kein Platz sein\n" #: .././repair/phase6.c:1808 #, c-format msgid "shrink_inode failed inode %llu block %u\n" msgstr "shrink_inode fehlgeschlagen Inode %llu Block %u\n" #: .././repair/phase6.c:1889 #, c-format msgid "realloc failed in longform_dir2_entry_check_data (%u bytes)\n" msgstr "realloc fehlgeschlagen in longform_dir2_entry_check_data (%u Bytes)\n" #: .././repair/phase6.c:1946 #, c-format msgid "empty data block %u in directory inode %llu: " msgstr "leerer Datenblock %u in Verzeichnis-Inode %llu: " #: .././repair/phase6.c:1949 #, c-format msgid "corrupt block %u in directory inode %llu: " msgstr "beschädigter Block %u in Verzeichnis-Inode %llu: " #: .././repair/phase6.c:1953 msgid "junking block\n" msgstr "Block wird weggeworfen\n" #: .././repair/phase6.c:1956 msgid "would junk block\n" msgstr "Block könnte weggeworfen werden\n" #: .././repair/phase6.c:1979 #, c-format msgid "bad directory block magic # %#x for directory inode %llu block %d: " msgstr "" "falscher Verzeichnisblock magische # %#x für Verzeichnis-Inode %llu Block %d: " #: .././repair/phase6.c:1983 #, c-format msgid "fixing magic # to %#x\n" msgstr "magische # wird auf %#x fixiert\n" #: .././repair/phase6.c:1987 #, c-format msgid "would fix magic # to %#x\n" msgstr "magische # würde auf %#x fixiert\n" #: .././repair/phase6.c:2007 #, c-format msgid "directory inode %llu block %u has consecutive free entries: " msgstr "" "Verzeichnis-Inode %llu Block %u hat aufeinander folgende freie Einträge: " #: .././repair/phase6.c:2011 msgid "joining together\n" msgstr "wird zusammengeführt\n" #: .././repair/phase6.c:2020 msgid "would join together\n" msgstr "könnte zusammengeführt werden\n" #: .././repair/phase6.c:2051 #, c-format msgid "entry \"%s\" in directory inode %llu points to non-existent inode %llu" msgstr "" "Eintrag »%s« in Verzeichnis-Inode %llu zeigt auf nicht existierenden\n" "Inode %llu" #: .././repair/phase6.c:2068 #, c-format msgid "entry \"%s\" in directory inode %llu points to free inode %llu" msgstr "Eintrag »%s« in Verzeichnis-Inode %llu zeigt auf freien Inode %llu" #: .././repair/phase6.c:2138 #, c-format msgid "entry \"%s\" (ino %llu) in dir %llu is not in the the first block" msgstr "Eintrag »%s« (ino %llu) in dir %llu ist nicht im ersten Block" #: .././repair/phase6.c:2164 #, c-format msgid "entry \"%s\" in dir %llu is not the first entry" msgstr "Eintrag »%s« in dir %llu ist nicht der erste Eintrag" #: .././repair/phase6.c:2200 #, c-format msgid "" "entry \"%s\" in dir %llu points to an already connected directory inode %" "llu\n" msgstr "" "Eintrag »%s« in dir %llu zeigt auf einen bereits verbundenen Verzeichnis-" "Inode %llu\n" #: .././repair/phase6.c:2219 #, c-format msgid "" "entry \"%s\" in dir inode %llu inconsistent with .. value (%llu) in ino %" "llu\n" msgstr "" "Eintrag »%s« in dir %llu stimmt nicht mit ..-Wert (%llu) in ino %llu überein\n" #: .././repair/phase6.c:2289 .././repair/phase6.c:2367 #, c-format msgid "leaf block %u for directory inode %llu bad header\n" msgstr "Blattblock %u für Verzeichnis-Inode %llu hat falsche Kopfzeilen\n" #: .././repair/phase6.c:2307 #, c-format msgid "leaf block %u for directory inode %llu bad tail\n" msgstr "Blatt-Block %u für Verzeichnis-Inode %llu hat falsches Ende\n" #: .././repair/phase6.c:2346 #, c-format msgid "can't read leaf block %u for directory inode %llu\n" msgstr "Blatt-Block %u für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/phase6.c:2357 #, c-format msgid "unknown magic number %#x for block %u in directory inode %llu\n" msgstr "" "unbekannte Magische Nummer %#x für Block %u in Verzeichnis-Inode %llu\n" #: .././repair/phase6.c:2392 #, c-format msgid "can't read freespace block %u for directory inode %llu\n" msgstr "" "Block %u mit freiem Platz für Verzeichnis-Inode %llu konnte nicht gelesen\n" "werden\n" #: .././repair/phase6.c:2404 #, c-format msgid "free block %u for directory inode %llu bad header\n" msgstr "freier Block %u für Verzeichnis-Inode %llu hat falschen Kopf\n" #: .././repair/phase6.c:2417 #, c-format msgid "free block %u entry %i for directory ino %llu bad\n" msgstr "freier Block %u Eintrag %i für Verzeichnis-ino %llu falsch\n" #: .././repair/phase6.c:2426 #, c-format msgid "free block %u for directory inode %llu bad nused\n" msgstr "freier Block %u für Verzeichnis-Inode %llu falsch nused\n" #: .././repair/phase6.c:2437 #, c-format msgid "missing freetab entry %u for directory inode %llu\n" msgstr "fehlender freetab-Eintrag %u für Verzeichnis-Inode %llu\n" #: .././repair/phase6.c:2478 #, c-format msgid "malloc failed in longform_dir2_entry_check (%u bytes)\n" msgstr "malloc fehlgeschlagen in longform_dir2_entry_check (%u Bytes)\n" #: .././repair/phase6.c:2508 #, c-format msgid "realloc failed in longform_dir2_entry_check (%u bytes)\n" msgstr "realloc fehlgeschlagen in longform_dir2_entry_check (%u Bytes)\n" #: .././repair/phase6.c:2514 #, c-format msgid "can't read data block %u for directory inode %llu\n" msgstr "Datenblock %u für Verzeichnis-Inode %llu kann nicht gelesen werden\n" #: .././repair/phase6.c:2619 #, c-format msgid "shortform dir inode %llu has null data entries \n" msgstr "Kurzform dir-Inode %llu hat Null-Daten-Einträge \n" #: .././repair/phase6.c:2686 #, c-format msgid "entry \"%s\" in shortform dir %llu references non-existent ino %llu" msgstr "" "Eintrag »%s« in Kurzform dir-Inode %llu bezieht sich auf nicht\n" "existierenden ino %llu" #: .././repair/phase6.c:2699 #, c-format msgid "entry \"%s\" in shortform dir inode %llu points to free inode %llu" msgstr "" "Eintrag »%s« in Kurzform dir-Inode %llu bezieht sich auf einen freien\n" "Inode %llu" #: .././repair/phase6.c:2752 #, c-format msgid "entry \"%s\" in dir %llu references already connected dir ino %llu,\n" msgstr "" "Eintrag »%s« in dir %llu bezieht sich auf einen bereits verbundenen\n" "dir ino %llu\n" #: .././repair/phase6.c:2769 #, c-format msgid "" "entry \"%s\" in dir %llu not consistent with .. value (%llu) in dir ino %llu" msgstr "" "Eintrag »%s« in dir %llu nicht übereinstimmend mit ..-Wert (%llu) in\n" "dir ino %llu" #: .././repair/phase6.c:2811 .././repair/phase6.c:3139 msgid "junking entry\n" msgstr "Eintrag wird verworfen\n" #: .././repair/phase6.c:2815 .././repair/phase6.c:3143 msgid "would junk entry\n" msgstr "Eintrag könnte verworfen werden\n" #: .././repair/phase6.c:2854 .././repair/phase6.c:3198 #, c-format msgid "setting size to %lld bytes to reflect junked entries\n" msgstr "" "Größe wird auf %lld Bytes gesetzt um verworfene Einträge\n" "widerzuspiegeln\n" #: .././repair/phase6.c:2905 #, c-format msgid "would set .. in sf dir inode %llu to %llu\n" msgstr ".. könnte in sf dir-Inode %llu auf %llu gesetzt werden\n" #: .././repair/phase6.c:2908 #, c-format msgid "setting .. in sf dir inode %llu to %llu\n" msgstr ".. wird in sf dir-Inode %llu auf %llu gesetzt\n" #: .././repair/phase6.c:3011 #, c-format msgid "" "entry \"%s\" in shortform directory %llu references non-existent inode %llu" msgstr "" "Eintrag »%s« in Kurzform-Verzeichnis %llu bezieht sich auf nicht\n" "existierenden Inode %llu" #: .././repair/phase6.c:3025 #, c-format msgid "" "entry \"%s\" in shortform directory inode %llu points to free inode %llu" msgstr "" "Eintrag »%s« in Kurzform-Verzeichnis-Inode %llu zeigt auf freien\n" "Inode %llu" #: .././repair/phase6.c:3076 #, c-format msgid "" "entry \"%s\" in directory inode %llu references already connected inode %" "llu,\n" msgstr "" "Eintrag »%s« in Verzeichnis-Inode %llu bezieht sich auf bereits verbundenen " "Inode %llu,\n" #: .././repair/phase6.c:3096 #, c-format msgid "" "entry \"%s\" in directory inode %llu not consistent with .. value (%llu) in " "inode %llu,\n" msgstr "" "Eintrag »%s« in Verzeichnis-Inode %llu nicht übereinstimmen mit ..-Wert (%" "llu) in Inode %llu,\n" #: .././repair/phase6.c:3167 #, c-format msgid "would fix i8count in inode %llu\n" msgstr "i8count in Inode %llu könnte repariert werden\n" #: .././repair/phase6.c:3179 #, c-format msgid "fixing i8count in inode %llu\n" msgstr "i8count in Inode %llu wird repariert\n" #: .././repair/phase6.c:3354 msgid "missing root directory .. entry, cannot fix in V1 dir filesystem\n" msgstr "" "fehlender Wurzelverzeichnis-..-Eintrag, kann nicht in V1 dir-Dateisystem\n" "behoben werden\n" #: .././repair/phase6.c:3360 #, c-format msgid "" "%d bad entries found in dir inode %llu, cannot fix in V1 dir filesystem\n" msgstr "" "%d falsche Einträge in dir-Inode %llu gefunden, kann nicht in V1\n" "dir-Dateisystem behoben werden\n" #: .././repair/phase6.c:3367 #, c-format msgid "missing \".\" entry in dir ino %llu, cannot in fix V1 dir filesystem\n" msgstr "" "fehlender ».«-Eintrag in dir ino %llu, kann nicht in V1 dir-Dateisystem\n" "behoben werden\n" #: .././repair/phase6.c:3386 msgid "recreating root directory .. entry\n" msgstr "..-Eintrag des Wurzel-Verzeichnisses wird neu erzeugt\n" #: .././repair/phase6.c:3405 #, c-format msgid "can't make \"..\" entry in root inode %llu, createname error %d\n" msgstr "" "»..«-Eintrag im Wurzel-Inode %llu kann nicht erstellt werden, createname-" "Fehler %d\n" #: .././repair/phase6.c:3417 msgid "would recreate root directory .. entry\n" msgstr "..-Eintrag des Wurzel-Verzeichnisses könnte neu erzeugt werden\n" #: .././repair/phase6.c:3440 #, c-format msgid "would create missing \".\" entry in dir ino %llu\n" msgstr "fehlender ».«-Eintrag in dir ino %llu könnte erzeugt werden\n" #: .././repair/phase6.c:3446 #, c-format msgid "creating missing \".\" entry in dir ino %llu\n" msgstr "fehlender ».«-Eintrag in dir ino %llu wird erzeugt\n" #: .././repair/phase6.c:3470 #, c-format msgid "can't make \".\" entry in dir ino %llu, createname error %d\n" msgstr "" "».«-Eintrag in dir ino %llu kann nicht erzeugt werden createname-Fehler %d\n" #: .././repair/phase6.c:3560 #, c-format msgid "disconnected dir inode %llu, " msgstr "nicht verbundener dir-Inode %llu, " #: .././repair/phase6.c:3562 #, c-format msgid "disconnected inode %llu, " msgstr "nicht verbundener Inode %llu, " #: .././repair/phase6.c:3564 msgid "cannot fix in V1 dir filesystem\n" msgstr "kann nicht in V1 dir-Dateisystem behoben werden\n" #: .././repair/phase6.c:3568 #, c-format msgid "moving to %s\n" msgstr "gehe zu %s\n" #: .././repair/phase6.c:3571 #, c-format msgid "would move to %s\n" msgstr "könnte zu %s gehen\n" #: .././repair/phase6.c:3662 msgid "Phase 6 - check inode connectivity...\n" msgstr "Phase 6 - Inode-Verbindbarkeit wird geprüft...\n" #: .././repair/phase6.c:3681 msgid "" "need to reinitialize root directory, but not supported on V1 dir filesystem\n" msgstr "" "Neuinitialisierung des Wurzelverzeichnisses nötig, aber nicht auf\n" "V1 dir-Dateisystem unterstützt\n" #: .././repair/phase6.c:3684 msgid "reinitializing root directory\n" msgstr "Wurzel-Verzeichnis wird neu initialisiert\n" #: .././repair/phase6.c:3689 msgid "would reinitialize root directory\n" msgstr "Wurzel-Verzeichnis könnte neu initialisiert werden\n" #: .././repair/phase6.c:3695 msgid "reinitializing realtime bitmap inode\n" msgstr "Echtzeit-Bitmap-Inode wird neu initialisiert\n" #: .././repair/phase6.c:3699 msgid "would reinitialize realtime bitmap inode\n" msgstr "Echtzeit-Bitmap-Inode könnte neu initialisiert werden\n" #: .././repair/phase6.c:3705 msgid "reinitializing realtime summary inode\n" msgstr "Echtzeit-Zusammenfassung wird neu initialisiert\n" #: .././repair/phase6.c:3709 msgid "would reinitialize realtime summary inode\n" msgstr "Echtzeit-Zusammenfassung könnte neu initialisiert werden\n" #: .././repair/phase6.c:3715 msgid " - resetting contents of realtime bitmap and summary inodes\n" msgstr "" " - Inhalte der Echtzeit-Bitmaps und Zusammenfassungs-Inodes werden " "zurückgesetzt\n" #: .././repair/phase6.c:3718 .././repair/phase6.c:3723 msgid "Warning: realtime bitmap may be inconsistent\n" msgstr "Warnung: Echtzeit-Bitmap kann unvollständig sein\n" #: .././repair/phase6.c:3729 msgid " - traversing filesystem ...\n" msgstr " - Dateisystem wird durchquert ...\n" #: .././repair/phase6.c:3752 msgid " - traversal finished ...\n" msgstr " - durchqueren beendet ...\n" #: .././repair/phase6.c:3753 #, c-format msgid " - moving disconnected inodes to %s ...\n" msgstr " - nicht verbundene Inodes werden nach %s verschoben ...\n" #: .././repair/xfs_repair.c:89 #, c-format msgid "" "Usage: %s [options] device\n" "\n" "Options:\n" " -f The device is a file\n" " -L Force log zeroing. Do this as a last resort.\n" " -l logdev Specifies the device where the external log resides.\n" " -m maxmem Maximum amount of memory to be used in megabytes.\n" " -n No modify mode, just checks the filesystem for damage.\n" " -P Disables prefetching.\n" " -r rtdev Specifies the device where the realtime section resides.\n" " -v Verbose output.\n" " -c subopts Change filesystem parameters - use xfs_admin.\n" " -o subopts Override default behaviour, refer to man page.\n" " -t interval Reporting interval in minutes.\n" " -d Repair dangerously.\n" " -V Reports version and exits.\n" msgstr "" "Aufruf: %s [Optionen] Gerät\n" "\n" "Optionen:\n" " -f Das Gerät ist eine Datei\n" " -L Protokoll auf Null setzen erzwingen. Tun Sie dies als\n" " letzten Ausweg.\n" " -l logdev Gibt das Gerät an, auf dem das externe Protokoll liegt.\n" " -m maxmem Maximaler Wert von Speicher zum benutzen in Megabyte.\n" " -n Unveränderlicher Modus, prüft das Dateisystem nur auf\n" " Schäden.\n" " -P Vorher holen abgeschaltet.\n" " -r rtdev Gibt das Gerät an, auf dem der Echtzeitbereich liegt.\n" " -v Ausführliche Ausgabe.\n" " -c subopts Dateisystem-Parameter ändern - xfs_admin benutzen.\n" " -o subopts Standardverhalten überschreiben, bezogen auf Handbuchseite.\n" " -t interval Berichtsintervall in Minuten.\n" " -d Gefährliche Reparatur.\n" " -V Version anzeigen und beenden.\n" #: .././repair/xfs_repair.c:115 msgid "no error" msgstr "kein Fehler" #: .././repair/xfs_repair.c:116 msgid "bad magic number" msgstr "falsche Magische Nummer" #: .././repair/xfs_repair.c:117 msgid "bad blocksize field" msgstr "falsches Blockgrößen-Feld" #: .././repair/xfs_repair.c:118 msgid "bad blocksize log field" msgstr "falsches Blockgrößen-Protokoll-Feld" #: .././repair/xfs_repair.c:119 msgid "bad or unsupported version" msgstr "falsche oder nicht unterstützte Version" #: .././repair/xfs_repair.c:121 msgid "filesystem mkfs-in-progress bit set" msgstr "mkfs-in-progress-Bit des Dateisystems gesetzt" #: .././repair/xfs_repair.c:123 msgid "inconsistent filesystem geometry information" msgstr "unvollständige Information über die Geometrie des Dateisystems" #: .././repair/xfs_repair.c:125 msgid "bad inode size or inconsistent with number of inodes/block" msgstr "falsche Inode-Größe oder unvollständig mit Anzahl der Inodes/Block" #: .././repair/xfs_repair.c:126 msgid "bad sector size" msgstr "falsche Bereichsgröße" #: .././repair/xfs_repair.c:128 msgid "AGF geometry info conflicts with filesystem geometry" msgstr "AGF-Geometrie-Info hat einen Konflikt mit der Dateisystem-Geometrie" #: .././repair/xfs_repair.c:130 msgid "AGI geometry info conflicts with filesystem geometry" msgstr "AGI-Geometrie-Info hat einen Konflikt mit der Dateisystem-Geometrie" #: .././repair/xfs_repair.c:132 msgid "AG superblock geometry info conflicts with filesystem geometry" msgstr "" "AG-Superblock-Geometrie-Info hat einen Konflikt mit der\n" "Dateisystem-Geometrie" #: .././repair/xfs_repair.c:133 msgid "attempted to perform I/O beyond EOF" msgstr "versucht ein I/O jenseits von EOF auszuführen" #: .././repair/xfs_repair.c:135 msgid "inconsistent filesystem geometry in realtime filesystem component" msgstr "" "unvollständige Dateisystem-Geometrie in Echtzeit-Dateisystem-Komponente" #: .././repair/xfs_repair.c:137 msgid "maximum indicated percentage of inodes > 100%" msgstr "maximal angezeigte Prozentzahl der Inodes > 100%" #: .././repair/xfs_repair.c:139 msgid "inconsistent inode alignment value" msgstr "uneinheitlicher Inode-Ausrichtungswert" #: .././repair/xfs_repair.c:141 msgid "not enough secondary superblocks with matching geometry" msgstr "nicht genug sekundäre Superblöcke mit passender Geometrie" #: .././repair/xfs_repair.c:143 msgid "bad stripe unit in superblock" msgstr "falsche Stripe-Einheit in Superblock" #: .././repair/xfs_repair.c:145 msgid "bad stripe width in superblock" msgstr "falsche Stripe-Breite in Superblock" #: .././repair/xfs_repair.c:147 msgid "bad shared version number in superblock" msgstr "falsche verteilte Versionsnummer im Superblock" #: .././repair/xfs_repair.c:152 #, c-format msgid "bad error code - %d\n" msgstr "falscher Fehler-Code - %d\n" #: .././repair/xfs_repair.c:160 #, c-format msgid "-%c %s option cannot have a value\n" msgstr "-%c %s-Option kann keinen Wert haben\n" #: .././repair/xfs_repair.c:256 msgid "-o bhash option cannot be used with -m option\n" msgstr "-o bhash-Option kann nicht mit der -m-Option benutzt werden\n" #: .././repair/xfs_repair.c:305 msgid "-m option cannot be used with -o bhash option\n" msgstr "-m-Option kann nicht mit der -o bhash-Option benutzt werden\n" #: .././repair/xfs_repair.c:347 #, c-format msgid "" "\n" "fatal error -- " msgstr "" "\n" "schwerwiegender Fehler -- " #: .././repair/xfs_repair.c:455 #, c-format msgid "sb root inode value %llu %sinconsistent with calculated value %lu\n" msgstr "sb-Wurzel-Inode-Wert %llu %suneinheitlich mit berechnetem Wert %lu\n" #: .././repair/xfs_repair.c:462 #, c-format msgid "resetting superblock root inode pointer to %lu\n" msgstr "Superblock-Wurzel-Inode-Zeiger wird auf %lu zurückgesetzt\n" #: .././repair/xfs_repair.c:466 #, c-format msgid "would reset superblock root inode pointer to %lu\n" msgstr "Superblock-Wurzel-Inode-Zeiger könnte auf %lu zurückgesetzt werden\n" #: .././repair/xfs_repair.c:478 #, c-format msgid "" "sb realtime bitmap inode %llu %sinconsistent with calculated value %lu\n" msgstr "" "sb-Echtzeit-Bitmap-Inode %llu %suneinheitlich mit berechnetem Wert %lu\n" #: .././repair/xfs_repair.c:485 #, c-format msgid "resetting superblock realtime bitmap ino pointer to %lu\n" msgstr "Superblock-Echtzeit-Bitmap-ino-Zeiger wird auf %lu zurückgesetzt\n" #: .././repair/xfs_repair.c:489 #, c-format msgid "would reset superblock realtime bitmap ino pointer to %lu\n" msgstr "" "Superblock-Echtzeit-Bitmap-ino-Zeiger könnte auf %lu zurückgesetzt werden\n" #: .././repair/xfs_repair.c:501 #, c-format msgid "" "sb realtime summary inode %llu %sinconsistent with calculated value %lu\n" msgstr "" "sb-Echtzeit-Zusammenfassungs-Inode %llu %suneinheitlich mit berechnetem\n" "Wert %lu\n" #: .././repair/xfs_repair.c:508 #, c-format msgid "resetting superblock realtime summary ino pointer to %lu\n" msgstr "" "Superblock-Echtzeit-Zusammenfassungs-ino-Zeiger wird auf %lu zurückgesetzt\n" #: .././repair/xfs_repair.c:512 #, c-format msgid "would reset superblock realtime summary ino pointer to %lu\n" msgstr "" "Superblock-Echtzeit-Zusammenfassungs-ino-Zeiger könnte auf %lu\n" "zurückgesetzt werden\n" #: .././repair/xfs_repair.c:560 msgid "" "Primary superblock would have been modified.\n" "Cannot proceed further in no_modify mode.\n" "Exiting now.\n" msgstr "" "Primärer Superblock könnte verändert worden sein.\n" "Es kann nicht im no_modify.Modus fortgefahren werden.\n" "Es wird nun beendet.\n" #: .././repair/xfs_repair.c:576 #, c-format msgid "%s: cannot repair this filesystem. Sorry.\n" msgstr "%s: Dieses Dateisystem kann nicht repariert werden. Entschuldigung.\n" #: .././repair/xfs_repair.c:601 #, c-format msgid " - reporting progress in intervals of %s\n" msgstr " - Berichts-Prozess in Abständen von %s\n" #: .././repair/xfs_repair.c:647 #, c-format msgid "" " - max_mem = %lu, icount = %llu, imem = %llu, dblock = %llu, dmem = %" "llu\n" msgstr "" " - max_mem = %lu, icount = %llu, imem = %llu, dblock = %llu, dmem = %" "llu\n" #: .././repair/xfs_repair.c:660 #, c-format msgid "" "Required memory for repair is greater that the maximum specified with the -m " "option. Please increase it to at least %lu.\n" msgstr "" "Benötigter Speicher für die Reparatur ist größer als das mit der\n" "-m-Option angegebene Maximum. Bitte erhöhen Sie es auf mindestens %lu.\n" #: .././repair/xfs_repair.c:678 #, c-format msgid " - block cache size set to %d entries\n" msgstr " - Block-Zwischenspeichergröße ist auf %d Einträge gesetzt\n" #: .././repair/xfs_repair.c:702 msgid "Found unsupported filesystem features. Exiting now.\n" msgstr "" "Es wurden nicht unterstützte Dateisystemmerkmale gefunden. Es wird nun\n" "beendet.\n" #: .././repair/xfs_repair.c:720 #, c-format msgid "No modify flag set, skipping phase 5\n" msgstr "Kein Veränderungskennzeichen gesetzt, Phase 5 wird übersprungen\n" #: .././repair/xfs_repair.c:734 msgid "Inode allocation btrees are too corrupted, skipping phases 6 and 7\n" msgstr "" "Inode-Allokations-btrees sind zu beschädigt, Phasen 6 und 7 werden\n" "übersprungen\n" #: .././repair/xfs_repair.c:740 msgid "Warning: no quota inodes were found. Quotas disabled.\n" msgstr "" "Warnung: Keine Quota-Inodes wurden gefunden. Quota ausgeschaltet\n" #: .././repair/xfs_repair.c:743 msgid "Warning: no quota inodes were found. Quotas would be disabled.\n" msgstr "" "Warnung: Keine Quota-Inodes wurden gefunden. Quota könnte ausgeschaltet\n" "sein\n" #: .././repair/xfs_repair.c:748 msgid "Warning: quota inodes were cleared. Quotas disabled.\n" msgstr "" "Warnung: Quota-Inodes wurden bereinigt. Quota ausgeschaltet\n" #: .././repair/xfs_repair.c:751 msgid "Warning: quota inodes would be cleared. Quotas would be disabled.\n" msgstr "" "Warnung: Quota-Inodes könnten bereinigt werden. Quota könnte\n" "ausgeschaltet sein\n" #: .././repair/xfs_repair.c:757 msgid "" "Warning: user quota information was cleared.\n" "User quotas can not be enforced until limit information is recreated.\n" msgstr "" "Warnung: Benutzer-Quota-Information wurde bereinigt.\n" "Benutzer-Quota können nicht erzwungen werden bis die\n" "Beschränkungsinformation neu erzeugt wurde.\n" #: .././repair/xfs_repair.c:761 msgid "" "Warning: user quota information would be cleared.\n" "User quotas could not be enforced until limit information was recreated.\n" msgstr "" "Warnung: Benutzer-Quota-Information könnte bereinigt werden.\n" "Benutzer-Quota kann nicht erzwungen werden bis die\n" "Beschränkungsinformation neu erzeugt wurde.\n" #: .././repair/xfs_repair.c:769 msgid "" "Warning: group quota information was cleared.\n" "Group quotas can not be enforced until limit information is recreated.\n" msgstr "" "Warnung: Gruppen-Quota-Information wurde bereinigt.\n" "Gruppen-Quota kann nicht erzwungen werden bis die\n" "Beschränkungsinformation neu erzeugt wurde.\n" #: .././repair/xfs_repair.c:773 msgid "" "Warning: group quota information would be cleared.\n" "Group quotas could not be enforced until limit information was recreated.\n" msgstr "" "Warnung: Gruppen-Quota-Information könnte bereinigt werden.\n" "Gruppen-Quota kann nicht erzwungen werden bis die\n" "Beschränkungsinformation neu erzeugt wurde.\n" #: .././repair/xfs_repair.c:781 msgid "" "Warning: project quota information was cleared.\n" "Project quotas can not be enforced until limit information is recreated.\n" msgstr "" "Warnung: Projekt-Quota-Information wurde bereinigt.\n" "Projekt-Quota kann nicht erzwungen werden bis die\n" "Beschränkungsinformation neu erzeugt wurde.\n" #: .././repair/xfs_repair.c:785 msgid "" "Warning: project quota information would be cleared.\n" "Project quotas could not be enforced until limit information was recreated.\n" msgstr "" "Warnung: Projekt-Quota-Information könnte bereinigt werden.\n" "Projekt-Quota kann nicht erzwungen werden bis die\n" "Beschränkungsinformation neu erzeugt wurde.\n" #: .././repair/xfs_repair.c:796 msgid "No modify flag set, skipping filesystem flush and exiting.\n" msgstr "" "Kein Änderungskennzeichen gesetzt, Leeren des Dateisystems wird\n" "übersprungen und es wird beendet\n" #: .././repair/xfs_repair.c:815 msgid "Note - quota info will be regenerated on next quota mount.\n" msgstr "" "Anmerkung - Quota-Information wird beim nächsten Einhängen des Quotas neu\n" "erzeugt\n" #: .././repair/xfs_repair.c:823 #, c-format msgid "" "Note - stripe unit (%d) and width (%d) fields have been reset.\n" "Please set with mount -o sunit=,swidth=\n" msgstr "" "Beachten Sie - Stripe-Einheit (%d) und -Beite (%d) Felder wurden\n" "zurückgesetzt. Bitte setzen Sie mit mount -o sunit=,swidth=\n" #: .././repair/xfs_repair.c:846 msgid "done\n" msgstr "erledigt\n" #: .././repair/attr_repair.c:106 msgid "" "entry contains illegal value in attribute named SGI_ACL_FILE or " "SGI_ACL_DEFAULT\n" msgstr "" "Eintrag enthält unerlaubten Wert im Attribut mit Namen SGI_ACL_FILE\n" "oder SGI_ACL_DEFAULT\n" #: .././repair/attr_repair.c:128 msgid "entry contains illegal value in attribute named SGI_MAC_LABEL\n" msgstr "Eintrag enthält unerlaubten Wert im Attribut mit Namen SGI_MAC_LABEL\n" #: .././repair/attr_repair.c:134 msgid "entry contains illegal value in attribute named SGI_CAP_FILE\n" msgstr "Eintrag enthält unerlaubten Wert im Attribut mit Namen SGI_CAP_FILE\n" #: .././repair/attr_repair.c:173 #, c-format msgid "there are no attributes in the fork for inode %llu\n" msgstr "es sind keine Attribute im Unterelement für Inode %llu\n" #: .././repair/attr_repair.c:181 #, c-format msgid "would junk the attribute fork since count is 0 for inode %llu\n" msgstr "Attributs-Fork würde weggeworfen seit Anzahl für Inode %llu 0 ist\n" #: .././repair/attr_repair.c:201 msgid "zero length name entry in attribute fork," msgstr "Namenseintrag mit Länge Null in Attribut-Abspaltung," #: .././repair/attr_repair.c:204 .././repair/attr_repair.c:224 #, c-format msgid " truncating attributes for inode %llu to %d\n" msgstr "Attribute für Inode %llu auf %d kürzen\n" #: .././repair/attr_repair.c:209 .././repair/attr_repair.c:230 #, c-format msgid " would truncate attributes for inode %llu to %d\n" msgstr "Attribute für Inode %llu könnten auf %d gekürzt werden\n" #: .././repair/attr_repair.c:221 msgid "name or value attribute lengths are too large,\n" msgstr "Name oder Länge des Attributswerts sind zu lang,\n" #: .././repair/attr_repair.c:243 msgid "entry contains illegal character in shortform attribute name\n" msgstr "" "Eintrag enthält unerlaubtes Zeichen in der Kurzform des Attributsnamens\n" #: .././repair/attr_repair.c:249 msgid "entry has INCOMPLETE flag on in shortform attribute\n" msgstr "Eintrag hat INCOMPLETE-Markierung in der Attributs-Kurzform\n" #: .././repair/attr_repair.c:266 #, c-format msgid "removing attribute entry %d for inode %llu\n" msgstr "Attributseintrag %d für Inode %llu wird entfernt\n" #: .././repair/attr_repair.c:278 #, c-format msgid "would remove attribute entry %d for inode %llu\n" msgstr "Attributs-Eintrag %d für Inode %llu könnte entfernt werden\n" #: .././repair/attr_repair.c:292 #, c-format msgid "" "would have corrected attribute entry count in inode %llu from %d to %d\n" msgstr "" "Anzahl der Attributs-Einträge könnte in Inode %llu von %d auf %d\n" "korrigiert worden sein\n" #: .././repair/attr_repair.c:296 #, c-format msgid "corrected attribute entry count in inode %llu, was %d, now %d\n" msgstr "" "Korrigierte Anzahl der Attributs-Einträge in Inode %llu war %d,\n" "ist nun %d\n" #: .././repair/attr_repair.c:307 #, c-format msgid "would have corrected attribute totsize in inode %llu from %d to %d\n" msgstr "" "Anzahl der Attributs-Gesamtgröße könnte in Inode %llu von %d auf %d\n" "korrigiert worden sein\n" #: .././repair/attr_repair.c:312 #, c-format msgid "corrected attribute entry totsize in inode %llu, was %d, now %d\n" msgstr "" "Korrigierte Gesamtgröße der Attributs-Einträge in Inode %llu war %d,\n" "ist nun %d\n" #: .././repair/attr_repair.c:342 #, c-format msgid "remote block for attributes of inode %llu is missing\n" msgstr "entfernt liegender Block für Attribute des Inodes %llu fehlt\n" #: .././repair/attr_repair.c:350 #, c-format msgid "can't read remote block for attributes of inode %llu\n" msgstr "" "entfernt liegender Block für Attribute des Inodes %llu kann nicht\n" "gelesen werden\n" #: .././repair/attr_repair.c:394 #, c-format msgid "" "attribute entry %d in attr block %u, inode %llu has bad name (namelen = %d)\n" msgstr "" "Attributs-Eintrag #%d in »attr«-Block %u, Inode %llu hat ungültigen\n" "Namen (namelen = %d)\n" #: .././repair/attr_repair.c:411 #, c-format msgid "bad hashvalue for attribute entry %d in attr block %u, inode %llu\n" msgstr "" "falscher Hash-Wert für Attributs-Eintrag %d in »attr«-Block %u,\n" "Inode %llu\n" #: .././repair/attr_repair.c:420 #, c-format msgid "" "bad security value for attribute entry %d in attr block %u, inode %llu\n" msgstr "" "falscher Sicherheitswert für Attributs-Eintrag %d in »attr«-Block %u in\n" "Inode %llu\n" #: .././repair/attr_repair.c:453 #, c-format msgid "inconsistent remote attribute entry %d in attr block %u, ino %llu\n" msgstr "" "Unvollständiger entfernt liegender Attributs-Eintrag %d in\n" "»attr«-Block %u, ino %llu\n" #: .././repair/attr_repair.c:463 #, c-format msgid "cannot malloc enough for remotevalue attribute for inode %llu\n" msgstr "malloc nicht ausreichend für remotevalue-Attribut für Inode %llu\n" #: .././repair/attr_repair.c:465 msgid "SKIPPING this remote attribute\n" msgstr "ÜBERSPRINGE dieses entfernt liegende Attribut\n" #: .././repair/attr_repair.c:470 #, c-format msgid "remote attribute get failed for entry %d, inode %llu\n" msgstr "" "das Abholen des entfernt liegenden Attributs scheiterte für Eintrag %d,\n" "Inode %llu\n" #: .././repair/attr_repair.c:476 #, c-format msgid "remote attribute value check failed for entry %d, inode %llu\n" msgstr "" "das Prüfen des entfernt liegenden Attributs-Wertes scheiterte für\n" "Eintrag %d, Inode %llu\n" #: .././repair/attr_repair.c:513 #, c-format msgid "bad attribute count %d in attr block %u, inode %llu\n" msgstr "falsche Attributs-Anzahl %d in »attr«-Block %u, Inode %llu\n" #: .././repair/attr_repair.c:528 #, c-format msgid "bad attribute nameidx %d in attr block %u, inode %llu\n" msgstr "falsches Attribut nameidx %d in »attr«-Block %u, Inode %llu\n" #: .././repair/attr_repair.c:537 #, c-format msgid "attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n" msgstr "" "Attributs-Eintrag #%d in »attr«-Block %u, Inode %llu ist UNVOLLSTÄNDIG\n" #: .././repair/attr_repair.c:548 #, c-format msgid "" "attribute entry %d in attr block %u, inode %llu claims already used space\n" msgstr "" "Attributs-Eintrag #%d in »attr«-Block %u, Inode %llu erhebt Anspruch auf\n" "benutzten Speicher\n" #: .././repair/attr_repair.c:571 #, c-format msgid "attribute entry %d in attr block %u, inode %llu claims used space\n" msgstr "" "Attributs-Eintrag %d in »attr«-Block %u, Inode %llu erhebt Anspruch auf\n" "benutzten Speicher\n" #: .././repair/attr_repair.c:596 #, c-format msgid "" "- resetting first used heap value from %d to %d in block %u of attribute " "fork of inode %llu\n" msgstr "" "- zuerst benutzter Heap-Wert wird von %d auf %d zurückgesetzt in Block %u\n" "des Attributs-Forks von Inode %llu\n" #: .././repair/attr_repair.c:604 #, c-format msgid "" "- would reset first used value from %d to %d in block %u of attribute fork " "of inode %llu\n" msgstr "" "- zuerst genutzter Wert könnte von %d auf %d zurückgesetzt werden im\n" "Block %u des Attribut-Unterelements von Inode %llu\n" #: .././repair/attr_repair.c:614 #, c-format msgid "" "- resetting usedbytes cnt from %d to %d in block %u of attribute fork of " "inode %llu\n" msgstr "" "- usedbytes cnt wird von %d auf %d zurückgesetzt in Block %u des\n" "Attributs-Forks von Inode %llu\n" #: .././repair/attr_repair.c:622 #, c-format msgid "" "- would reset usedbytes cnt from %d to %d in block %u of attribute fork of %" "llu\n" msgstr "" "- usedbytes cnt würde von %d auf %d zurückgesetzt in Block %u des\n" "Attributs-Forks von Inode %llu\n" #: .././repair/attr_repair.c:671 #, c-format msgid "can't map block %u for attribute fork for inode %llu\n" msgstr "" "Block %u kann nicht für Erstellung eines Unterelements des Inodes %llu\n" "kartiert werden\n" #: .././repair/attr_repair.c:679 #, c-format msgid "" "can't read file block %u (fsbno %llu) for attribute fork of inode %llu\n" msgstr "" "Datei-Block %u (fsbno %llu) für Erstellung des Subattributs des Inodes\n" "%llu kann nicht gelesen werden\n" #: .././repair/attr_repair.c:689 #, c-format msgid "bad attribute leaf magic %#x for inode %llu\n" msgstr "falsches Attributsblatt magische %#x für Inode %llu\n" #: .././repair/attr_repair.c:720 #, c-format msgid "" "bad sibling back pointer for block %u in attribute fork for inode %llu\n" msgstr "" "falscher Geschwister-Rückwärtszeiger für Block %u in Attributs-Fork für\n" "Inode %llu\n" #: .././repair/attr_repair.c:747 #, c-format msgid "bad hash path in attribute fork for inode %llu\n" msgstr "schlechter Hash-Pfad in Subattribut für Inode %llu\n" #: .././repair/attr_repair.c:846 #, c-format msgid "block 0 of inode %llu attribute fork is missing\n" msgstr "Block 0 des Subattributs von Inode %llu fehlt\n" #: .././repair/attr_repair.c:852 #, c-format msgid "agno of attribute fork of inode %llu out of regular partition\n" msgstr "" "agno des Subattributs des Inodes %llu außerhalb der regulären Partition\n" #: .././repair/attr_repair.c:860 #, c-format msgid "can't read block 0 of inode %llu attribute fork\n" msgstr "Block 0 des Subattributs von Inode %llu kann nicht gelesen werden\n" #: .././repair/attr_repair.c:874 #, c-format msgid "clearing forw/back pointers in block 0 for attributes in inode %llu\n" msgstr "" "Vorwärts-/Rückwärtszeiger im Block 0 für Attribute des Inodes %llu wird\n" "bereinigt\n" #: .././repair/attr_repair.c:880 #, c-format msgid "" "would clear forw/back pointers in block 0 for attributes in inode %llu\n" msgstr "" "Vorwärts-/Rückwärtszeiger im Block 0 für Attribute des Inodes %llu\n" "könnte bereinigt werden\n" #: .././repair/attr_repair.c:910 #, c-format msgid "bad attribute leaf magic # %#x for dir ino %llu\n" msgstr "falsches Attributsblatt magische # %#x für dir ino %llu\n" #: .././repair/attr_repair.c:1000 msgid "cannot malloc enough for ACL attribute\n" msgstr "nicht genug malloc für ACL-Attribut möglich\n" #: .././repair/attr_repair.c:1001 msgid "SKIPPING this ACL\n" msgstr "ÜBERSPRINGE dieses ACL\n" #: .././repair/prefetch.c:473 msgid "prefetch corruption\n" msgstr "Voraufrufbeschädigung\n" #: .././repair/prefetch.c:628 .././repair/prefetch.c:724 #, c-format msgid "failed to create prefetch thread: %s\n" msgstr "Erzeugung des Voraufruf-Threads fehlgeschlagen: %s\n" #: .././repair/prefetch.c:762 msgid "failed to initialize prefetch mutex\n" msgstr "initialisieren des Voraufruf-Mutex fehlgeschlagen\n" #: .././repair/prefetch.c:764 .././repair/prefetch.c:766 msgid "failed to initialize prefetch cond var\n" msgstr "initialisieren der Voraufruf-cond var fehlgeschlagen\n" #: .././rtcp/xfs_rtcp.c:30 #, c-format msgid "%s [-e extsize] [-p] source target\n" msgstr "%s [-e extsize] [-p] Quelle Ziel\n" #: .././rtcp/xfs_rtcp.c:71 #, c-format msgid "%s: must specify files to copy\n" msgstr "%s: Dateien zum Kopieren müssen angegeben werden\n" #: .././rtcp/xfs_rtcp.c:86 #, c-format msgid "%s: stat of %s failed\n" msgstr "%s: stat von %s fehlgeschlagen\n" #: .././rtcp/xfs_rtcp.c:93 #, c-format msgid "%s: final argument is not directory\n" msgstr "%s: letztes Argument ist kein Verzeichnis\n" #: .././rtcp/xfs_rtcp.c:140 #, c-format msgid "%s: failed stat on %s: %s\n" msgstr "%s: stat auf %s fehlgeschlagen: %s\n" #: .././rtcp/xfs_rtcp.c:161 #, c-format msgid "%s: %s filesystem has no realtime partition\n" msgstr "%s: %s-Dateisystem hat keine Echtzeit-Partition\n" #: .././rtcp/xfs_rtcp.c:182 .././rtcp/xfs_rtcp.c:210 #, c-format msgid "%s: open of %s failed: %s\n" msgstr "%s: Öffnen auf %s fehlgeschlagen: %s\n" #: .././rtcp/xfs_rtcp.c:199 #, c-format msgid "%s: set attributes on %s failed: %s\n" msgstr "%s: Setzen von Attributen auf %s fehlgeschlagen: %s\n" #: .././rtcp/xfs_rtcp.c:217 #, c-format msgid "%s: get attributes of %s failed: %s\n" msgstr "%s: Erhalten von Attributen auf %s fehlgeschlagen: %s\n" #: .././rtcp/xfs_rtcp.c:227 .././rtcp/xfs_rtcp.c:262 #, c-format msgid "%s: %s is not a realtime file.\n" msgstr "%s: %s ist keine Echtzeit-Datei.\n" #: .././rtcp/xfs_rtcp.c:236 #, c-format msgid "%s: %s file extent size is %d, instead of %d.\n" msgstr "%s: %s Dateiumfanggröße ist %d anstelle von %d.\n" #: .././rtcp/xfs_rtcp.c:248 .././rtcp/xfs_rtcp.c:271 #, c-format msgid "%s: open of %s source failed: %s\n" msgstr "%s: Öffnen von %s-Quelle fehlgeschlagen:%s\n" #: .././rtcp/xfs_rtcp.c:285 #, c-format msgid "%s: couldn't get direct I/O information: %s\n" msgstr "%s: direkte I/O-Information kann nicht erlangt werden: %s\n" #: .././rtcp/xfs_rtcp.c:295 #, c-format msgid "%s: extent size %d not a multiple of %d.\n" msgstr "%s: Umfanggröße %d ist kein Vielfaches von %d.\n" #: .././rtcp/xfs_rtcp.c:309 #, c-format msgid "The size of %s is not a multiple of %d.\n" msgstr "Die Größe von %s ist kein Vielfaches von %d.\n" #: .././rtcp/xfs_rtcp.c:312 #, c-format msgid "%s will be padded to %lld bytes.\n" msgstr "%s wird auf %lld Bytes aufgefüllt.\n" #: .././rtcp/xfs_rtcp.c:318 #, c-format msgid "" "Use the -p option to pad %s to a size which is a multiple of %d bytes.\n" msgstr "" "Benutzen Sie die -p-Option um %s auf eine Größe aufzufüllen, die ein\n" "Vielfaches von %d Bytes ist.\n" #: .././rtcp/xfs_rtcp.c:360 #, c-format msgid "%s: write error: %s\n" msgstr "%s: Schreibfehler: %s\n" #: .././rtcp/xfs_rtcp.c:388 #, c-format msgid "%s: could not open %s: %s\n" msgstr "%s: %s kann nicht geöffnet werden: %s\n" xfsprogs-5.3.0/po/pl.po0000644000175000017500000176217313570057155014666 0ustar nathansnathans# Polish translation for xfsprogs. # This file is distributed under the same license as the xfsprogs package. # Jakub Bogusz , 2006-2018. # msgid "" msgstr "" "Project-Id-Version: xfsprogs 4.15.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-02-26 20:58+0100\n" "PO-Revision-Date: 2018-02-26 20:59+0100\n" "Last-Translator: Jakub Bogusz \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: .././copy/xfs_copy.c:115 #, c-format msgid "Check logfile \"%s\" for more details\n" msgstr "WiÄ™cej szczegółów w pliku logu \"%s\"\n" #: .././copy/xfs_copy.c:121 #, c-format msgid "%s: could not write to logfile \"%s\".\n" msgstr "%s: nie udaÅ‚o siÄ™ zapisać pliku logu \"%s\".\n" #: .././copy/xfs_copy.c:124 #, c-format msgid "Aborting XFS copy -- logfile error -- reason: %s\n" msgstr "Przerwano XFS copy - błąd pliku logu - przyczyna: %s\n" #: .././copy/xfs_copy.c:139 .././copy/xfs_copy.c:292 .././copy/xfs_copy.c:617 #: .././copy/xfs_copy.c:624 msgid "Aborting XFS copy - reason" msgstr "Przerwano XFS copy - przyczyna" #: .././copy/xfs_copy.c:159 msgid "THE FOLLOWING COPIES FAILED TO COMPLETE\n" msgstr "NASTĘPUJÄ„CYCH KOPII NIE UDAÅO SIĘ UKOŃCZYĆ\n" #: .././copy/xfs_copy.c:163 msgid "write error" msgstr "błąd zapisu" #: .././copy/xfs_copy.c:165 msgid "lseek error" msgstr "błąd lseek" #: .././copy/xfs_copy.c:166 #, c-format msgid " at offset %lld\n" msgstr " pod offsetem %lld\n" #: .././copy/xfs_copy.c:170 #, c-format msgid "All copies completed.\n" msgstr "Wszystkie kopie ukoÅ„czone.\n" #: .././copy/xfs_copy.c:173 #, c-format msgid "See \"%s\" for more details.\n" msgstr "WiÄ™cej szczegółów w \"%s\".\n" #: .././copy/xfs_copy.c:261 #, c-format msgid "%s: write error on target %d \"%s\" at offset %lld\n" msgstr "%s: błąd zapisu przy celu %d \"%s\" pod offsetem %lld\n" #: .././copy/xfs_copy.c:266 #, c-format msgid "%s: lseek error on target %d \"%s\" at offset %lld\n" msgstr "%s: błąd lseek przy celu %d \"%s\" pod offsetem %lld\n" #: .././copy/xfs_copy.c:272 #, c-format msgid "Aborting target %d - reason" msgstr "Przerywano zapis celu %d - przyczyna" #: .././copy/xfs_copy.c:276 msgid "Aborting XFS copy - no more targets.\n" msgstr "Przerwano XFS copy - nie ma wiÄ™cej celów.\n" #: .././copy/xfs_copy.c:287 #, c-format msgid "%s: thread %d died unexpectedly, target \"%s\" incomplete\n" msgstr "%s: wÄ…tek %d zmarÅ‚ nieoczekiwanie, cel \"%s\" niekompletny\n" #: .././copy/xfs_copy.c:289 #, c-format msgid "%s: offset was probably %lld\n" msgstr "%s: offset prawdopodobnie %lld\n" #: .././copy/xfs_copy.c:300 #, c-format msgid "%s: Unknown child died (should never happen!)\n" msgstr "%s: Nieznany potomek zmarÅ‚ (nie powinno siÄ™ zdarzyć!)\n" #: .././copy/xfs_copy.c:310 #, c-format msgid "Usage: %s [-bdV] [-L logfile] source target [target ...]\n" msgstr "SkÅ‚adnia: %s [-bdV] [-L plik_logu] źródÅ‚o cel [cel ...]\n" #: .././copy/xfs_copy.c:393 #, c-format msgid "%s: lseek failure at offset %lld\n" msgstr "%s: niepowodzenie lseek pod offsetem %lld\n" #: .././copy/xfs_copy.c:408 #, c-format msgid "assert error: buf->length = %d, buf->size = %d\n" msgstr "błąd zapewnienia: buf->length = %d, buf->size = %d\n" #: .././copy/xfs_copy.c:414 #, c-format msgid "%s: read failure at offset %lld\n" msgstr "%s: błąd odczytu pod offsetem %lld\n" #: .././copy/xfs_copy.c:444 msgid "ag header buffer invalid!\n" msgstr "błędny bufor nagłówka ag!\n" #: .././copy/xfs_copy.c:597 .././db/init.c:97 .././estimate/xfs_estimate.c:144 #: .././fsr/xfs_fsr.c:295 .././growfs/xfs_growfs.c:191 .././io/init.c:212 #: .././logprint/logprint.c:206 .././mkfs/xfs_mkfs.c:3883 .././quota/init.c:182 #: .././repair/xfs_repair.c:324 .././rtcp/xfs_rtcp.c:55 #: .././scrub/xfs_scrub.c:604 .././spaceman/init.c:89 #, c-format msgid "%s version %s\n" msgstr "%s wersja %s\n" #: .././copy/xfs_copy.c:615 #, c-format msgid "%s: couldn't open log file \"%s\"\n" msgstr "%s: nie udaÅ‚o siÄ™ otworzyć pliku logu \"%s\"\n" #: .././copy/xfs_copy.c:622 #, c-format msgid "%s: couldn't set up logfile stream\n" msgstr "%s: nie udaÅ‚o siÄ™ ustanowić strumienia pliku logu\n" #: .././copy/xfs_copy.c:634 msgid "Couldn't allocate target array\n" msgstr "Nie udaÅ‚o siÄ™ przydzielić tablicy celów\n" #: .././copy/xfs_copy.c:653 #, c-format msgid "%s: couldn't open source \"%s\"\n" msgstr "%s: nie udaÅ‚o siÄ™ otworzyć źródÅ‚a \"%s\"\n" #: .././copy/xfs_copy.c:659 #, c-format msgid "%s: couldn't stat source \"%s\"\n" msgstr "%s: nie udaÅ‚o siÄ™ wykonać stat na źródle \"%s\"\n" #: .././copy/xfs_copy.c:669 #, c-format msgid "%s: Cannot set direct I/O flag on \"%s\".\n" msgstr "%s: Nie można ustawić flagi bezpoÅ›redniego we/wy na \"%s\".\n" #: .././copy/xfs_copy.c:674 #, c-format msgid "%s: xfsctl on file \"%s\" failed.\n" msgstr "%s: xfsctl na pliku \"%s\" nie powiodÅ‚o siÄ™.\n" #: .././copy/xfs_copy.c:697 #, c-format msgid "%s: Warning -- a filesystem is mounted on the source device.\n" msgstr "%s: Uwaga - system plików jest zamontowany na urzÄ…dzeniu źródÅ‚owym.\n" #: .././copy/xfs_copy.c:700 msgid "\t\tGenerated copies may be corrupt unless the source is\n" msgstr "\t\tWygenerowane kopie mogÄ… być uszkodzone o ile źródÅ‚o nie jest\n" #: .././copy/xfs_copy.c:702 msgid "\t\tunmounted or mounted read-only. Copy proceeding...\n" msgstr "" "\t\todmontowane lub zamontowane tylko do odczytu. Kopiowanie w trakcie...\n" #: .././copy/xfs_copy.c:719 #, c-format msgid "" "%s: couldn't initialize XFS library\n" "%s: Aborting.\n" msgstr "" "%s: nie udaÅ‚o siÄ™ zainicjować biblioteki XFS\n" "%s: Przerwano.\n" #: .././copy/xfs_copy.c:743 #, c-format msgid "" "%s: %s filesystem failed to initialize\n" "%s: Aborting.\n" msgstr "" "%s: Nie powiodÅ‚a siÄ™ inicjalizacja systemu plików %s\n" "%s: Przerwano.\n" #: .././copy/xfs_copy.c:747 #, c-format msgid "" "%s %s filesystem failed to initialize\n" "%s: Aborting.\n" msgstr "" "%s: Nie powiodÅ‚a siÄ™ inicjalizacja systemu plików %s\n" "%s: Przerwano.\n" #: .././copy/xfs_copy.c:751 #, c-format msgid "" "%s: %s has an external log.\n" "%s: Aborting.\n" msgstr "" "%s: %s ma zewnÄ™trzny log.\n" "%s: Przerwano.\n" #: .././copy/xfs_copy.c:755 #, c-format msgid "" "%s: %s has a real-time section.\n" "%s: Aborting.\n" msgstr "" "%s: %s ma sekcjÄ™ real-time.\n" "%s: Przerwano.\n" #: .././copy/xfs_copy.c:774 msgid "" "Error: source filesystem log is dirty. Mount the filesystem to replay the\n" "log, unmount and retry xfs_copy.\n" msgstr "" "Błąd: log źródÅ‚owego systemu plików jest brudny. Należy zamontować system\n" "plików, aby odtworzyć log, odmontować i ponownie spróbować xfs_copy.\n" #: .././copy/xfs_copy.c:779 msgid "" "Error: could not determine the log head or tail of the source filesystem.\n" "Mount the filesystem to replay the log or run xfs_repair.\n" msgstr "" "Błąd: nie udaÅ‚o siÄ™ okreÅ›lić poczÄ…tku lub koÅ„ca logu źródÅ‚owego systemu " "plików.\n" "Należy zamontować system plików, aby odtworzyć log, albo uruchomić " "xfs_repair.\n" #: .././copy/xfs_copy.c:795 msgid "" "Error: filesystem block size is smaller than the disk sectorsize.\n" "Aborting XFS copy now.\n" msgstr "" "Błąd: rozmiar bloku systemu plików jest mniejszy niż rozmiar sektora dysku.\n" "Przerwano XFS copy.\n" #: .././copy/xfs_copy.c:812 #, c-format msgid "Creating file %s\n" msgstr "Tworzenie pliku %s\n" #: .././copy/xfs_copy.c:830 #, c-format msgid "" "%s: a filesystem is mounted on target device \"%s\".\n" "%s cannot copy to mounted filesystems. Aborting\n" msgstr "" "%s: na urzÄ…dzeniu docelowym \"%s\" jest zamontowany system plików.\n" "%s nie może kopiować na zamontowane systemy plików. Przerwano.\n" #: .././copy/xfs_copy.c:841 #, c-format msgid "%s: couldn't open target \"%s\"\n" msgstr "%s: nie udaÅ‚o siÄ™ otworzyć celu \"%s\"\n" #: .././copy/xfs_copy.c:851 #, c-format msgid "%s: cannot grow data section.\n" msgstr "%s: nie można powiÄ™kszyć sekcji danych.\n" #: .././copy/xfs_copy.c:859 #, c-format msgid "%s: xfsctl on \"%s\" failed.\n" msgstr "%s: xfsctl na \"%s\" nie powiodÅ‚o siÄ™.\n" #: .././copy/xfs_copy.c:878 #, c-format msgid "%s: failed to write last block\n" msgstr "%s: nie udaÅ‚o siÄ™ zapisać ostatniego bloku\n" #: .././copy/xfs_copy.c:880 #, c-format msgid "\tIs target \"%s\" too small?\n" msgstr "\tCzy cel \"%s\" jest zbyt maÅ‚y?\n" #: .././copy/xfs_copy.c:890 msgid "Couldn't initialize global thread mask\n" msgstr "Nie udaÅ‚o siÄ™ zainicjować globalnej maski wÄ…tków\n" #: .././copy/xfs_copy.c:897 msgid "Error initializing wbuf 0\n" msgstr "Błąd inicjalizacji wbuf 0\n" #: .././copy/xfs_copy.c:905 msgid "Error initializing btree buf 1\n" msgstr "Błąd inicjalizacji btree buf 1\n" #: .././copy/xfs_copy.c:910 msgid "Error creating first semaphore.\n" msgstr "Błąd tworzenia pierwszego semafora.\n" #: .././copy/xfs_copy.c:925 msgid "Couldn't malloc space for thread args\n" msgstr "Nie udaÅ‚o siÄ™ przydzielić miejsca na argumenty wÄ…tku\n" #: .././copy/xfs_copy.c:937 #, c-format msgid "Error creating thread mutex %d\n" msgstr "Błąd podczas tworzenia sekcji krytycznej %d wÄ…tku\n" #: .././copy/xfs_copy.c:954 #, c-format msgid "Error creating thread for target %d\n" msgstr "Błąd podczas tworzenia wÄ…tku dla celu %d\n" #: .././copy/xfs_copy.c:1008 #, c-format msgid "Error: current level %d >= btree levels %d\n" msgstr "Błąd: bieżący poziom %d >= poziomów b-drzewa %d\n" #: .././copy/xfs_copy.c:1027 #, c-format msgid "Bad btree magic 0x%x\n" msgstr "NiewÅ‚aÅ›ciwa liczba magiczna b-drzewa 0x%x\n" #: .././copy/xfs_copy.c:1054 msgid "WARNING: source filesystem inconsistent.\n" msgstr "UWAGA: źródÅ‚owy system plików niespójny.\n" #: .././copy/xfs_copy.c:1056 msgid " A leaf btree rec isn't a leaf. Aborting now.\n" msgstr " Liść rekordu b-drzewa nie jest liÅ›ciem. Przerwano.\n" #: .././db/addr.c:35 msgid "[field-expression]" msgstr "[wyrażenie-pól]" #: .././db/addr.c:36 msgid "set current address" msgstr "ustawienie bieżącego adresu" #: .././db/addr.c:42 msgid "" "\n" " 'addr' uses the given field to set the filesystem address and type\n" "\n" " Examples:\n" "\n" " sb\n" " a rootino - set the type to inode and set position to the root inode\n" " a u.bmx[0].startblock (for inode with blockmap)\n" "\n" msgstr "" "\n" " 'addr' wykorzystuje podane pole do ustawienia adresu w systemie plików i " "typu\n" "\n" " PrzykÅ‚ady:\n" "\n" " sb\n" " a rootino - ustawienie typu na i-wÄ™zeÅ‚ i pozycji na i-wÄ™zeÅ‚ główny\n" " a u.bmx[0].startblock (dla i-wÄ™zÅ‚a z mapÄ… bloków)\n" "\n" #: .././db/addr.c:72 .././db/attrset.c:86 .././db/attrset.c:189 #: .././db/btdump.c:469 .././db/crc.c:76 .././db/fuzz.c:98 .././db/print.c:74 #: .././db/type.c:209 .././db/write.c:110 msgid "no current type\n" msgstr "brak bieżącego typu\n" #: .././db/addr.c:82 #, c-format msgid "no fields for type %s\n" msgstr "brak pól dla typu %s\n" #: .././db/addr.c:94 msgid "array not allowed for addr command\n" msgstr "tablica nie jest dozwolona dla polecenia addr\n" #: .././db/addr.c:103 #, c-format msgid "no next type for field %s\n" msgstr "brak nastÄ™pnego typu dla pola %s\n" #: .././db/addr.c:110 #, c-format msgid "no addr function for field %s (type %s)\n" msgstr "brak funkcji addr dla pola %s (typu %s)\n" #: .././db/agf.c:35 .././db/agfl.c:36 .././db/agi.c:35 .././db/sb.c:44 msgid "[agno]" msgstr "[agno]" #: .././db/agf.c:36 msgid "set address to agf header" msgstr "ustawienie adresu na nagłówek agf" #: .././db/agf.c:100 msgid "" "\n" " set allocation group free block list\n" "\n" " Example:\n" "\n" " agf 2 - move location to AGF in 2nd filesystem allocation group\n" "\n" " Located in the second sector of each allocation group, the AGF\n" " contains the root of two different freespace btrees:\n" " The 'cnt' btree keeps track freespace indexed on section size.\n" " The 'bno' btree tracks sections of freespace indexed on block number.\n" msgstr "" "\n" " ustawienie listy wolnych bloków grupy alokacji\n" "\n" " PrzykÅ‚ad:\n" "\n" " agf 2 - zmiana pozycji na AGF w 2. grupie alokacji systemu plików\n" "\n" " PoÅ‚ożony w drugim sektorze każdej grupy alokacji AGF zawiera korzeÅ„\n" " dwóch różnych b-drzew wolnej przestrzeni:\n" " b-drzewo 'cnt' Å›ledzi wolne miejsce indeksowane rozmiarem sekcji\n" " b-drzewo 'bno' Å›ledzi sekcje wolnego miejsca indeksowane numerem bloku.\n" #: .././db/agf.c:125 .././db/agfl.c:106 .././db/agi.c:95 .././db/sb.c:167 #, c-format msgid "bad allocation group number %s\n" msgstr "błędny numer grupy alokacji %s\n" #: .././db/agfl.c:37 msgid "set address to agfl block" msgstr "ustawienie adresu na blok agfl" #: .././db/agfl.c:79 msgid "" "\n" " set allocation group freelist\n" "\n" " Example:\n" "\n" " agfl 5\n" " Located in the fourth sector of each allocation group,\n" " the agfl freelist for internal btree space allocation is maintained\n" " for each allocation group. This acts as a reserved pool of space\n" " separate from the general filesystem freespace (not used for user data).\n" "\n" msgstr "" "\n" " ustawienie listy wolnego miejsca grupy alokacji\n" "\n" " PrzykÅ‚ad:\n" "\n" " agfl 5\n" " PoÅ‚ożona w 4. sektorze każdej grupy alokacji lista wolnego miejsca agfl\n" " sÅ‚użąca do wewnÄ™trznego przydzielania miejsca dla b-drzew jest utrzymywana\n" " dla każdej grupy alokacji. DziaÅ‚a jako zarezerwowana pula miejsca " "oddzielona\n" " od ogólnego wolnego miejsca w systemie plików (nie używana dla danych\n" " użytkownika).\n" "\n" #: .././db/agi.c:36 msgid "set address to agi header" msgstr "ustawienie adresu na nagłówek agi" #: .././db/agi.c:70 msgid "" "\n" " set allocation group inode btree\n" "\n" " Example:\n" "\n" " agi 3 (set location to 3rd allocation group inode btree and type to 'agi')\n" "\n" " Located in the 3rd 512 byte block of each allocation group,\n" " the agi inode btree tracks all used/free inodes in the allocation group.\n" " Inodes are allocated in 16k 'chunks', each btree entry tracks a 'chunk'.\n" "\n" msgstr "" "\n" " ustawienie b-drzewa i-wÄ™zÅ‚a grupy alokacji\n" "\n" " PrzykÅ‚ad:\n" "\n" " agi 3 (ustawienie poÅ‚ożenia na b-drzewo i-wÄ™zÅ‚a 3. grupy alokacji i typu na " "'agi')\n" "\n" " PoÅ‚ożone w 3. 512-bajtowym bloku każdej grupy alokacji, b-drzewo i-wÄ™zÅ‚a " "agi\n" " Å›ledzi wszystkie używane i wolne i-wÄ™zÅ‚y w grupie alokacji.\n" " I-wÄ™zÅ‚y sÄ… przydzielane w 16k porcjach (chunk), każdy wpis b-drzewa Å›ledzi\n" " jednÄ….\n" "\n" #: .././db/attr.c:636 .././db/attr.c:671 msgid "Unknown attribute buffer type!\n" msgstr "Nieznany typ bufora atrybutów!\n" #: .././db/attr.c:683 msgid "Writing unknown attribute buffer type!\n" msgstr "Zapis nieznanego typu bufora atrybutów!\n" #: .././db/attrset.c:38 msgid "[-r|-s|-p|-u] [-n] [-R|-C] [-v n] name" msgstr "[-r|-s|-p|-u] [-n] [-R|-C] [-v n] nazwa" #: .././db/attrset.c:39 msgid "set the named attribute on the current inode" msgstr "ustawienie atrybutu o podanej nazwie w bieżącym i-węźle" #: .././db/attrset.c:42 msgid "[-r|-s|-p|-u] [-n] name" msgstr "[-r|-s|-p|-u] [-n] nazwa" #: .././db/attrset.c:43 msgid "remove the named attribute from the current inode" msgstr "usuniÄ™cie atrybutu o podanej nazwie z bieżącego i-wÄ™zÅ‚a" #: .././db/attrset.c:49 msgid "" "\n" " The 'attr_set' and 'attr_remove' commands provide interfaces for debugging\n" " the extended attribute allocation and removal code.\n" " Both commands require an attribute name to be specified, and the attr_set\n" " command allows an optional value length (-v) to be provided as well.\n" " There are 4 namespace flags:\n" " -r -- 'root'\n" " -u -- 'user'\t\t(default)\n" " -s -- 'secure'\n" "\n" " For attr_set, these options further define the type of set operation:\n" " -C -- 'create' - create attribute, fail if it already exists\n" " -R -- 'replace' - replace attribute, fail if it does not exist\n" " The backward compatibility mode 'noattr2' can be emulated (-n) also.\n" "\n" msgstr "" "\n" " Polecenia 'attr_set' i 'attr_remove' udostÄ™pniajÄ… interfejsy do " "diagnostyki\n" " kodu przydzielania i usuwania rozszerzonych atrybutów.\n" " Oba polecenia wymagajÄ… podania nazwy atrybutu, a polecenie attr_set\n" " pozwala dodatkowo podać opcjonalnÄ… dÅ‚ugość wartoÅ›ci (-v).\n" " SÄ… 4 flagi przestrzeni nazw:\n" " -r - 'root'\n" " -u - 'user' (domyÅ›lna)\n" " -s - 'secure'\n" "\n" " Dla attr_set poniższe opcje okreÅ›lajÄ… rodzaj operacji ustawiania:\n" " -C - 'create' - utworzenie atrybutu; nie powiedzie siÄ™, jeÅ›li już " "istnieje\n" " -R - 'replace' - zastÄ…pienie atrybutu; nie powiedzie siÄ™, jeÅ›li nie " "istnieje\n" " Możliwa jest także emulacja trybu kompatybilnoÅ›ci wstecznej 'noattr2' (-" "n).\n" "\n" #: .././db/attrset.c:90 .././db/attrset.c:193 msgid "current type is not inode\n" msgstr "bieżący typ nie jest i-wÄ™zÅ‚em\n" #: .././db/attrset.c:125 #, c-format msgid "bad attr_set valuelen %s\n" msgstr "błędna dÅ‚ugość wartoÅ›ci %s dla attr_set\n" #: .././db/attrset.c:131 msgid "bad option for attr_set command\n" msgstr "błędna opcja dla polecenia attr_set\n" #: .././db/attrset.c:137 msgid "too few options for attr_set (no name given)\n" msgstr "za maÅ‚o opcji dla attr_set (nie podano nazwy)\n" #: .././db/attrset.c:146 #, c-format msgid "cannot allocate buffer (%d)\n" msgstr "nie udaÅ‚o siÄ™ przydzielić bufora (%d)\n" #: .././db/attrset.c:155 .././db/attrset.c:230 #, c-format msgid "failed to iget inode %llu\n" msgstr "operacja iget na i-węźle %llu nie powiodÅ‚a siÄ™\n" #: .././db/attrset.c:162 #, c-format msgid "failed to set attr %s on inode %llu\n" msgstr "ustawianie atrybutu %s w i-węźle %llu nie powiodÅ‚o siÄ™\n" #: .././db/attrset.c:217 msgid "bad option for attr_remove command\n" msgstr "błędna opcja dla polecenia attr_remove\n" #: .././db/attrset.c:223 msgid "too few options for attr_remove (no name given)\n" msgstr "za maÅ‚o opcji dla attr_remove (nie podano nazwy)\n" #: .././db/attrset.c:236 #, c-format msgid "failed to remove attr %s from inode %llu\n" msgstr "usuniÄ™cie atrybutu %s z i-wÄ™zÅ‚a %llu nie powiodÅ‚o siÄ™\n" #: .././db/block.c:43 .././db/block.c:49 msgid "filoff" msgstr "filoff" #: .././db/block.c:44 msgid "set address to file offset (attr fork)" msgstr "ustawienie adresu na offset w pliku (gałąź atrybutów)" #: .././db/block.c:46 msgid "[d]" msgstr "[d]" #: .././db/block.c:47 msgid "set address to daddr value" msgstr "ustawienie adresu na wartość daddr" #: .././db/block.c:50 msgid "set address to file offset (data fork)" msgstr "ustawienie adresu na offset w pliku (gałąź danych)" #: .././db/block.c:52 msgid "[fsb]" msgstr "[fsb]" #: .././db/block.c:53 msgid "set address to fsblock value" msgstr "ustawienie adresu na wartość fsblock" #: .././db/block.c:59 msgid "" "\n" " Example:\n" "\n" " 'ablock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's attribute fork. The filesystem block size is specified in\n" " the superblock.\n" "\n" msgstr "" "\n" " PrzykÅ‚ad:\n" "\n" " 'ablock 23' ustawia pozycjÄ™ w pliku na 23. blok systemu plików w gałęzi\n" " atrybutów i-wÄ™zÅ‚a. Rozmiar bloku systemu plików jest okreÅ›lony w " "superbloku.\n" "\n" #: .././db/block.c:82 .././db/block.c:177 #, c-format msgid "bad block number %s\n" msgstr "błędny numer bloku %s\n" #: .././db/block.c:90 msgid "no attribute data for file\n" msgstr "brak danych atrybutów dla pliku\n" #: .././db/block.c:96 msgid "file attr block is unmapped\n" msgstr "blok atrybutów pliku nie ma odwzorowania\n" #: .././db/block.c:119 msgid "" "\n" " Example:\n" "\n" " 'daddr 102' - sets position to the 102nd absolute disk block\n" " (512 byte block).\n" msgstr "" "\n" " PrzykÅ‚ad:\n" "\n" " 'daddr 102' ustawia pozycjÄ™ na 102. (bezwzglÄ™dnie) blok dysku\n" " (blok 512-bajtowy).\n" #: .././db/block.c:135 #, c-format msgid "current daddr is %lld\n" msgstr "bieżący daddr to %lld\n" #: .././db/block.c:141 #, c-format msgid "bad daddr %s\n" msgstr "błędny daddr %s\n" #: .././db/block.c:153 msgid "" "\n" " Example:\n" "\n" " 'dblock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's data fork. The filesystem block size is specified in the\n" " superblock.\n" "\n" msgstr "" "\n" " PrzykÅ‚ad:\n" "\n" " 'dblock 23' ustawia pozycjÄ™ w pliku na 23. blok systemu plików w gałęzi\n" " danych i-wÄ™zÅ‚a. Rozmiar bloku systemu plików jest okreÅ›lony w superbloku.\n" "\n" #: .././db/block.c:185 msgid "no type for file data\n" msgstr "brak typu dla danych pliku\n" #: .././db/block.c:192 msgid "file data block is unmapped\n" msgstr "blok danych plików nie ma odwzorowania\n" #: .././db/block.c:210 msgid "" "\n" " Example:\n" "\n" " 'fsblock 1023' - sets the file position to the 1023rd filesystem block.\n" " The filesystem block size is specified in the superblock and set during\n" " mkfs time. Offset is absolute (not AG relative).\n" "\n" msgstr "" "\n" " PrzykÅ‚ad:\n" "\n" " 'fsblock 1023' ustawia pozycjÄ™ w pliku na 1023. blok systemu plików.\n" " Rozmiar bloku systemu plików jest okreÅ›lony w superbloku i ustawiany w\n" " trakcie wykonywania mkfs. Offset jest bezwzglÄ™dny (nie wzglÄ™dem AG).\n" "\n" #: .././db/block.c:229 #, c-format msgid "current fsblock is %lld\n" msgstr "bieżący fsblock to %lld\n" #: .././db/block.c:235 .././db/block.c:241 #, c-format msgid "bad fsblock %s\n" msgstr "błędny fsblock %s\n" #: .././db/bmap.c:39 msgid "[-ad] [block [len]]" msgstr "[-ad] [blok [dÅ‚ugość]]" #: .././db/bmap.c:40 msgid "show block map for current file" msgstr "pokazanie mapy bloków dla bieżącego pliku" #: .././db/bmap.c:152 .././db/inode.c:426 msgid "no current inode\n" msgstr "brak bieżącego i-wÄ™zÅ‚a\n" #: .././db/bmap.c:165 msgid "bad option for bmap command\n" msgstr "błędna opcja dla polecenia bmap\n" #: .././db/bmap.c:182 #, c-format msgid "bad block number for bmap %s\n" msgstr "błędny numer bloku dla bmap %s\n" #: .././db/bmap.c:190 #, c-format msgid "bad len for bmap %s\n" msgstr "błędna dÅ‚ugość dla bmap %s\n" #: .././db/bmap.c:213 #, c-format msgid "%s offset %lld startblock %llu (%u/%u) count %llu flag %u\n" msgstr "%s oofset %lld blok-pocz %llu (%u/%u) liczba %llu flaga %u\n" #: .././db/bmap.c:215 .././db/check.c:2224 .././db/check.c:2236 #: .././db/check.c:2263 .././io/fsmap.c:105 .././repair/dinode.c:52 msgid "data" msgstr "danych" #: .././db/bmap.c:215 .././db/check.c:2224 .././db/check.c:2236 #: .././db/check.c:2263 .././io/fsmap.c:105 .././repair/dinode.c:53 msgid "attr" msgstr "atrybutów" #: .././db/btblock.c:164 #, c-format msgid "Bad btree magic 0x%x; coercing to %s.\n" msgstr "NiewÅ‚aÅ›ciwa liczba magiczna b-drzewa 0x%x; wymuszenie na %s.\n" #: .././db/btdump.c:32 msgid "" "\n" " If the cursor points to a btree block, 'btdump' dumps the btree\n" " downward from that block. If the cursor points to an inode,\n" " the data fork btree root is selected by default. If the cursor\n" " points to a directory or extended attribute btree node, the tree\n" " will be printed downward from that block.\n" "\n" " Options:\n" " -a -- Display an inode's extended attribute fork btree.\n" " -i -- Print internal btree nodes.\n" "\n" msgstr "" "\n" " JeÅ›li kursor wskazuje na blok b-drzewa, 'btdump' zrzuca b-drzewo\n" " poniżej tego bloku. JeÅ›li kursor wskazuje na i-wÄ™zeÅ‚, domyÅ›lnie\n" " wybierany jest korzeÅ„ b-drzewa gałęzi danych. JeÅ›li kursor wskazuje\n" " na katalog lub wÄ™zeÅ‚ b-drzewa rozszerzonych atrybutów, wypisane\n" " zostanie drzewo poniżej tego bloku.\n" "\n" " Opcje:\n" " -a - wypisanie b-drzewa gałęzi rozszerzonych atrybutów i-wÄ™zÅ‚a.\n" " -i - wypisanie wÄ™złów wewnÄ™trznych b-drzewa.\n" "\n" #: .././db/btdump.c:92 .././db/btdump.c:395 #, c-format msgid "%s level %u block %u daddr %llu\n" msgstr "%s poziom %u blok %u daddr %llu\n" #: .././db/btdump.c:185 msgid "attr fork not in btree format\n" msgstr "gałąź atrybutów nie jest w formacie b-drzewa\n" #: .././db/btdump.c:191 msgid "data fork not in btree format\n" msgstr "gałąź danych nie jest w formacie b-drzewa\n" #: .././db/btdump.c:430 #, c-format msgid "Current location is not part of a dir/attr btree.\n" msgstr "Bieżące poÅ‚ożenie nie jest częściÄ… b-drzewa katalogów/atrybutów.\n" #: .././db/btdump.c:481 msgid "bad option for btdump command\n" msgstr "błędna opcja dla polecenia btdump\n" #: .././db/btdump.c:487 msgid "bad options for btdump command\n" msgstr "błędne opcje dla polecenia btdump\n" #: .././db/btdump.c:491 msgid "attrfork flag doesn't apply here\n" msgstr "flaga attrfork nie ma tu zastosowania\n" #: .././db/btdump.c:513 #, c-format msgid "type \"%s\" is not a btree type or inode\n" msgstr "typ \"%s\" nie jest typem b-drzewa ani i-wÄ™zÅ‚em\n" #: .././db/btdump.c:521 msgid "dump btree" msgstr "zrzut b-drzewa" #: .././db/check.c:378 msgid "free block usage information" msgstr "informacje o wykorzystaniu wolnych bloków" #: .././db/check.c:381 msgid "[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..." msgstr "[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..." #: .././db/check.c:382 msgid "get block usage and check consistency" msgstr "uzyskanie informacji o wykorzystaniu bloków i sprawdzenie spójnoÅ›ci" #: .././db/check.c:385 msgid "[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..." msgstr "[-n liczba] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t typ] ..." #: .././db/check.c:386 msgid "trash randomly selected block(s)" msgstr "zaÅ›miecenie losowo wybranych bloków" #: .././db/check.c:389 msgid "[-n] [-c blockcount]" msgstr "[-n] [-c liczba-bloków]" #: .././db/check.c:390 msgid "print usage for current block(s)" msgstr "wypisanie wykorzystania bieżących bloków" #: .././db/check.c:393 msgid "[-s] [-i ino] ..." msgstr "[-s] [-i ino] ..." #: .././db/check.c:394 msgid "print inode-name pairs" msgstr "wypisanie par i-wÄ™zeÅ‚ - nazwa" #: .././db/check.c:414 #, c-format msgid "-i %lld bad inode number\n" msgstr "-i %lld - błędny numer i-wÄ™zÅ‚a\n" #: .././db/check.c:426 #, c-format msgid "inode %lld add link, now %u\n" msgstr "i-wÄ™zeÅ‚ %lld - dodano dowiÄ…zanie, teraz %u\n" #: .././db/check.c:453 #, c-format msgid "inode %lld parent %lld\n" msgstr "i-wÄ™zeÅ‚ %lld - rodzic %lld\n" #: .././db/check.c:766 msgid "block usage information not allocated\n" msgstr "informacja o wykorzystaniu bloków nie przydzielona\n" #: .././db/check.c:804 msgid "already have block usage information\n" msgstr "już istnieje informacja o wykorzystaniu bloków\n" #: .././db/check.c:821 .././db/check.c:922 msgid "WARNING: this may be a newer XFS filesystem.\n" msgstr "UWAGA: to może być nowszy system plików XFS.\n" #: .././db/check.c:857 #, c-format msgid "sb_icount %lld, counted %lld\n" msgstr "sb_icount %lld, naliczono %lld\n" #: .././db/check.c:863 #, c-format msgid "sb_ifree %lld, counted %lld\n" msgstr "sb_ifree %lld, naliczono %lld\n" #: .././db/check.c:869 #, c-format msgid "sb_fdblocks %lld, counted %lld\n" msgstr "sb_fdblocks %lld, naliczono %lld\n" #: .././db/check.c:875 #, c-format msgid "sb_fdblocks %lld, aggregate AGF count %lld\n" msgstr "sb_fdblocks %lld, łączny licznik AGF %lld\n" #: .././db/check.c:881 #, c-format msgid "sb_frextents %lld, counted %lld\n" msgstr "sb_frextents %lld, naliczono %lld\n" #: .././db/check.c:888 #, c-format msgid "sb_features2 (0x%x) not same as sb_bad_features2 (0x%x)\n" msgstr "sb_features2 (0x%x) różni siÄ™ od sb_bad_features2 (0x%x)\n" #: .././db/check.c:897 #, c-format msgid "sb versionnum missing attr bit %x\n" msgstr "sb versionnum - brak bitu atrybutu %x\n" #: .././db/check.c:904 #, c-format msgid "sb versionnum missing quota bit %x\n" msgstr "sb versionnum - brak bitu quota %x\n" #: .././db/check.c:911 #, c-format msgid "sb versionnum extra align bit %x\n" msgstr "sb versionnum - nadmiarowy bit align %x\n" #: .././db/check.c:950 msgid "zeroed" msgstr "wyzerowano" #: .././db/check.c:950 msgid "set" msgstr "ustawiono" #: .././db/check.c:950 msgid "flipped" msgstr "przełączono" #: .././db/check.c:950 msgid "randomized" msgstr "ulosowiono" #: .././db/check.c:958 #, c-format msgid "zero-length block %u/%u buffer to trash??\n" msgstr "blok zerowej dÅ‚ugoÅ›ci %u/%u bufor do zaÅ›miecenia???\n" #: .././db/check.c:977 #, c-format msgid "can't read block %u/%u for trashing\n" msgstr "nie można odczytać bloku %u/%u w celu zaÅ›miecenia\n" #: .././db/check.c:1006 #, c-format msgid "blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n" msgstr "blocktrash: %u/%u %s blok %d bit%s poczÄ…tek %d:%d %s\n" #: .././db/check.c:1085 #, c-format msgid "bad blocktrash count %s\n" msgstr "błędna liczba bloków do zaÅ›miecenia %s\n" #: .././db/check.c:1097 #, c-format msgid "bad blocktrash offset %s\n" msgstr "błędny offset bloków do zaÅ›miecenia %s\n" #: .././db/check.c:1114 #, c-format msgid "bad blocktrash type %s\n" msgstr "błędny typ zaÅ›miecania %s\n" #: .././db/check.c:1123 #, c-format msgid "bad blocktrash min %s\n" msgstr "błędny poczÄ…tek zaÅ›miecania %s\n" #: .././db/check.c:1131 #, c-format msgid "bad blocktrash max %s\n" msgstr "błędny koniec zaÅ›miecania %s\n" #: .././db/check.c:1139 msgid "bad option for blocktrash command\n" msgstr "błędna opcja polecenia blocktrash\n" #: .././db/check.c:1144 .././db/check.c:1235 msgid "must run blockget first\n" msgstr "najpierw trzeba wykonać blockget\n" #: .././db/check.c:1148 msgid "nothing on stack\n" msgstr "nie ma nic na stosie\n" #: .././db/check.c:1152 msgid "bad min/max for blocktrash command\n" msgstr "błędny poczÄ…tek/koniec polecenia blocktrash\n" #: .././db/check.c:1170 #, c-format msgid "blocktrash: seed %u\n" msgstr "blocktash: zarodek %u\n" #: .././db/check.c:1186 msgid "blocktrash: no matching blocks\n" msgstr "blocktrash: brak pasujÄ…cych bloków\n" #: .././db/check.c:1250 #, c-format msgid "bad blockuse count %s\n" msgstr "błędna liczba bloków dla blockuse: %s\n" #: .././db/check.c:1256 .././db/check.c:1980 msgid "must run blockget -n first\n" msgstr "najpierw trzeba wykonać blockget -n\n" #: .././db/check.c:1262 msgid "bad option for blockuse command\n" msgstr "błędna opcja dla polecenia blockuse\n" #: .././db/check.c:1269 #, c-format msgid "block %llu (%u/%u) type %s" msgstr "blok %llu (%u/%u) typu %s" #: .././db/check.c:1273 #, c-format msgid " inode %lld" msgstr " i-wÄ™zeÅ‚ %lld" #: .././db/check.c:1317 #, c-format msgid "block %u/%u expected type %s got %s\n" msgstr "blok %u/%u: oczekiwano typu %s, otrzymano %s\n" #: .././db/check.c:1350 #, c-format msgid "blocks %u/%u..%u claimed by inode %lld\n" msgstr "blok %u/%u..%u przypisany do i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:1358 #, c-format msgid "block %u/%u claimed by inode %lld, previous inum %lld\n" msgstr "blok %u/%u przypisany do i-wÄ™zÅ‚a %lld, poprzedni inum %lld\n" #: .././db/check.c:1387 #, c-format msgid "link count mismatch for inode %lld (name %s), nlink %d, counted %d\n" msgstr "" "niezgodność liczby dowiÄ…zaÅ„ dla i-wÄ™zÅ‚a %lld (nazwa %s), nlink %d, naliczono " "%d\n" #: .././db/check.c:1395 #, c-format msgid "disconnected inode %lld, nlink %d\n" msgstr "odłączony i-wÄ™zeÅ‚ %lld, nlink %d\n" #: .././db/check.c:1399 #, c-format msgid "allocated inode %lld has 0 link count\n" msgstr "przydzielony i-wÄ™zeÅ‚ %lld ma zerowÄ… liczbÄ™ dowiÄ…zaÅ„\n" #: .././db/check.c:1409 #, c-format msgid "inode %lld name %s\n" msgstr "i-wÄ™zeÅ‚ %lld o nazwie %s\n" #: .././db/check.c:1443 .././db/check.c:1458 #, c-format msgid "block %u/%u out of range\n" msgstr "blok %u/%u poza zakresem\n" #: .././db/check.c:1446 .././db/check.c:1461 #, c-format msgid "blocks %u/%u..%u out of range\n" msgstr "bloki %u/%u..%u poza zakresem\n" #: .././db/check.c:1484 #, c-format msgid "rtblock %llu expected type %s got %s\n" msgstr "rtblok %llu - oczekiwano typu %s, otrzymano %s\n" #: .././db/check.c:1504 #, c-format msgid "rtblocks %llu..%llu claimed by inode %lld\n" msgstr "rtbloki %llu..%llu przypisane do i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:1513 #, c-format msgid "rtblock %llu claimed by inode %lld, previous inum %lld\n" msgstr "rtblok %llu przypisany do i-wÄ™zÅ‚a %lld, poprzedni inum %lld\n" #: .././db/check.c:1531 #, c-format msgid "root inode %lld is missing\n" msgstr "brak głównego i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:1536 #, c-format msgid "root inode %lld is not a directory\n" msgstr "główny i-wÄ™zeÅ‚ %lld nie jest katalogiem\n" #: .././db/check.c:1552 #, c-format msgid "rtblock %llu out of range\n" msgstr "rtblok %llu poza zakresem\n" #: .././db/check.c:1596 #, c-format msgid "blocks %u/%u..%u claimed by block %u/%u\n" msgstr "bloki %u/%u..%u przypisane do bloku %u/%u\n" #: .././db/check.c:1610 #, c-format msgid "setting block %u/%u to %s\n" msgstr "ustawianie bloku %u/%u na %s\n" #: .././db/check.c:1633 #, c-format msgid "setting rtblock %llu to %s\n" msgstr "ustawianie rtbloku %llu na %s\n" #: .././db/check.c:1654 .././repair/rt.c:151 #, c-format msgid "rt summary mismatch, size %d block %llu, file: %d, computed: %d\n" msgstr "" "opis rt nie zgadza siÄ™, rozmiar %d bloku %llu, plik: %d, obliczono: %d\n" #: .././db/check.c:1679 #, c-format msgid "block %u/%u type %s not expected\n" msgstr "blok %u/%u typu %s nie oczekiwany\n" #: .././db/check.c:1700 #, c-format msgid "rtblock %llu type %s not expected\n" msgstr "rtblok %llu typu %s nie oczekiwany\n" #: .././db/check.c:1737 #, c-format msgid "dir ino %lld missing leaf entry for %x/%x\n" msgstr "i-wÄ™zeÅ‚ katalogu %lld - brak wpisu liÅ›cia dla %x/%x\n" #: .././db/check.c:1856 #, c-format msgid "bad superblock magic number %x, giving up\n" msgstr "błędna liczba magiczna superbloku %x, poddajÄ™ siÄ™\n" #: .././db/check.c:1910 msgid "bad option for blockget command\n" msgstr "błędna opcja dla polecenia blockget\n" #: .././db/check.c:1997 #, c-format msgid "bad option -%c for ncheck command\n" msgstr "błędna opcja -%c dla polecenia ncheck\n" #: .././db/check.c:2071 #, c-format msgid "block 0 for directory inode %lld is missing\n" msgstr "brak bloku 0 dla i-wÄ™zÅ‚a katalogu %lld\n" #: .././db/check.c:2091 #, c-format msgid "can't read block 0 for directory inode %lld\n" msgstr "nie można odczytać bloku 0 dla i-wÄ™zÅ‚a katalogu %lld\n" #: .././db/check.c:2137 #, c-format msgid "inode %lld extent [%lld,%lld,%lld,%d]\n" msgstr "ekstent i-wÄ™zÅ‚a %lld [%lld,%lld,%lld,%d]\n" #: .././db/check.c:2140 #, c-format msgid "bmap rec out of order, inode %lld entry %d\n" msgstr "błędna kolejność bmap rec - i-wÄ™zeÅ‚ %lld, wpis %d\n" #: .././db/check.c:2146 #, c-format msgid "inode %lld bad rt block number %lld, offset %lld\n" msgstr "i-wÄ™zeÅ‚ %lld - błędny numer bloku rt %lld, offset %lld\n" #: .././db/check.c:2156 .././db/check.c:2162 #, c-format msgid "inode %lld bad block number %lld [%d,%d], offset %lld\n" msgstr "i-wÄ™zeÅ‚ %lld - błędny numer bloku %lld [%d,%d], offset %lld\n" #: .././db/check.c:2180 .././db/check.c:2194 #, c-format msgid "inode %lld block %lld at offset %lld\n" msgstr "i-wÄ™zeÅ‚ %lld: blok %lld pod offsetem %lld\n" #: .././db/check.c:2221 #, c-format msgid "level for ino %lld %s fork bmap root too large (%u)\n" msgstr "i-wÄ™zeÅ‚ %lld: poziom bmap root gałęzi %s zbyt duży (%u)\n" #: .././db/check.c:2233 #, c-format msgid "numrecs for ino %lld %s fork bmap root too large (%u)\n" msgstr "i-wÄ™zeÅ‚ %lld: liczba rekordów bmap root gałęzi %s zbyt duża (%u)\n" #: .././db/check.c:2260 #, c-format msgid "extent count for ino %lld %s fork too low (%d) for file format\n" msgstr "" "i-wÄ™zeÅ‚ %lld: liczba ekstentów dla gałęzi %s zbyt maÅ‚a (%d) dla formatu " "pliku\n" #: .././db/check.c:2312 .././db/check.c:3336 #, c-format msgid "bad directory data magic # %#x for dir ino %lld block %d\n" msgstr "" "błędna liczba magiczna danych katalogu %#x dla i-wÄ™zÅ‚a katalogu %lld, blok " "%d\n" #: .././db/check.c:2330 #, c-format msgid "bad block directory tail for dir ino %lld\n" msgstr "błędny koniec katalogu bloku dla i-wÄ™zÅ‚a katalogu %lld\n" #: .././db/check.c:2375 #, c-format msgid "dir %lld block %d bad free entry at %d\n" msgstr "katalog %lld, blok %d: błędny wolny wpis pod %d\n" #: .././db/check.c:2399 #, c-format msgid "dir %lld block %d zero length entry at %d\n" msgstr "katalog %lld, blok %d: wpis zerowej dÅ‚ugoÅ›ci pod %d\n" #: .././db/check.c:2408 #, c-format msgid "dir %lld block %d bad entry at %d\n" msgstr "katalog %lld, blok %d: błędny wpis pod %d\n" #: .././db/check.c:2426 #, c-format msgid "dir %lld block %d entry %*.*s %lld\n" msgstr "katalog %lld, blok %d, wpis %*.*s %lld\n" #: .././db/check.c:2433 #, c-format msgid "dir %lld block %d entry %*.*s bad inode number %lld\n" msgstr "katalog %lld, blokd %d, epis %*.*s: błędny number i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2443 #, c-format msgid "multiple .. entries in dir %lld (%lld, %lld)\n" msgstr "wiele wpisów .. w katalogu %lld (%lld, %lld)\n" #: .././db/check.c:2460 #, c-format msgid "dir %lld entry . inode number mismatch (%lld)\n" msgstr "katalog %lld, wpis .: niezgodność numeru i-wÄ™zÅ‚a (%lld)\n" #: .././db/check.c:2474 #, c-format msgid "dir %lld block %d bad count %u\n" msgstr "katalog %lld, blok %d: błędny licznik %u\n" #: .././db/check.c:2485 .././db/check.c:3350 #, c-format msgid "dir %lld block %d extra leaf entry %x %x\n" msgstr "katalog %lld, blok %d: nadmiarowy wpis liÅ›cia %x %x\n" #: .././db/check.c:2497 #, c-format msgid "dir %lld block %d bad bestfree data\n" msgstr "katalog %lld, blok %d: błędne dane bestfree\n" #: .././db/check.c:2505 #, c-format msgid "dir %lld block %d bad block tail count %d (stale %d)\n" msgstr "katalog %lld, blok %d: błędny licznik koÅ„ca bloku %d (stale %d)\n" #: .././db/check.c:2515 #, c-format msgid "dir %lld block %d bad stale tail count %d\n" msgstr "katalog %lld, blok %d: błędny licznik koÅ„ca stale %d\n" #: .././db/check.c:2521 #, c-format msgid "dir %lld block %d consecutive free entries\n" msgstr "katalog %lld, blok %d: kolejne wolne wpisy\n" #: .././db/check.c:2527 #, c-format msgid "dir %lld block %d entry/unused tag mismatch\n" msgstr "katalog %lld, blok %d: niezgodność znacznika wpis/nieużywany\n" #: .././db/check.c:2576 #, c-format msgid "no . entry for directory %lld\n" msgstr "brak wpisu . dla katalogu %lld\n" #: .././db/check.c:2581 #, c-format msgid "no .. entry for directory %lld\n" msgstr "brak wpisu .. dla katalogu %lld\n" #: .././db/check.c:2585 #, c-format msgid ". and .. same for non-root directory %lld\n" msgstr ". i .. sÄ… takie same dla katalogu %lld (nie bÄ™dÄ…cego głównym)\n" #: .././db/check.c:2590 #, c-format msgid "root directory %lld has .. %lld\n" msgstr "główny katalog %lld ma .. %lld\n" #: .././db/check.c:2623 #, c-format msgid "bad size (%lld) or format (%d) for directory inode %lld\n" msgstr "błędny rozmiar (%lld) lub format (%d) dla i-wÄ™zÅ‚a katalogu %lld\n" #: .././db/check.c:2651 #, c-format msgid "bad number of extents %d for inode %lld\n" msgstr "błędna liczba ekstentów %d dla i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2723 #, c-format msgid "bad magic number %#x for inode %lld\n" msgstr "błędna liczba magiczna %#x dla i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2730 #, c-format msgid "bad version number %#x for inode %lld\n" msgstr "błędny numer wersji %#x dla i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2738 #, c-format msgid "bad nblocks %lld for free inode %lld\n" msgstr "błędna liczba bloków %lld dla wolnego i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2745 #, c-format msgid "bad nlink %d for free inode %lld\n" msgstr "błądna liczba dowiÄ…zaÅ„ %d dla wolnego i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2751 #, c-format msgid "bad mode %#o for free inode %lld\n" msgstr "błędne uprawnienia %#o dla wolnego i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2760 #, c-format msgid "bad next unlinked %#x for inode %lld\n" msgstr "błędny nastÄ™pny niedowiÄ…zany %#x dla i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2771 #, c-format msgid "bad format %d for inode %lld type %#o\n" msgstr "błędny format %d dla i-wÄ™zÅ‚a %lld typu %#o\n" #: .././db/check.c:2779 #, c-format msgid "bad fork offset %d for inode %lld\n" msgstr "błędny offset gałęzi %d dla i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2786 #, c-format msgid "bad attribute format %d for inode %lld\n" msgstr "błędny format atrybutu %d dla i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:2792 #, c-format msgid "" "inode %lld mode %#o fmt %s afmt %s nex %d anex %d nblk %lld sz %lld%s%s%s%s%s" "%s%s\n" msgstr "" "i-wÄ™zeÅ‚ %lld mode %#o fmt %s afmt %s nex %d anex %d nblk %lld sz %lld%s%s%s%s" "%s%s%s\n" #: .././db/check.c:2911 #, c-format msgid "bad nblocks %lld for inode %lld, counted %lld\n" msgstr "błędna liczba bloków %lld dla i-wÄ™zÅ‚a %lld, naliczono %lld\n" #: .././db/check.c:2918 #, c-format msgid "bad nextents %d for inode %lld, counted %d\n" msgstr "błędna liczba ekstentów %d dla i-wÄ™zÅ‚a %lld, naliczono %d\n" #: .././db/check.c:2924 #, c-format msgid "bad anextents %d for inode %lld, counted %d\n" msgstr "błędne anextents %d dla i-wÄ™zÅ‚a %lld, naliczono %d\n" #: .././db/check.c:2976 #, c-format msgid "local inode %lld data is too large (size %lld)\n" msgstr "dane lokalnego i-wÄ™zÅ‚a %lld zbyt duże (rozmiar %lld)\n" #: .././db/check.c:2985 #, c-format msgid "local inode %lld attr is too large (size %d)\n" msgstr "atrybuty lokalnego i-wÄ™zÅ‚a %lld zbyt duże (rozmiar %d)\n" #: .././db/check.c:3034 #, c-format msgid "dir inode %lld block %u=%llu\n" msgstr "i-wÄ™zeÅ‚ katalogu %lld, blok %u=%llu\n" #: .././db/check.c:3046 #, c-format msgid "can't read block %u for directory inode %lld\n" msgstr "nie można odczytać bloku %u dla i-wÄ™zÅ‚a katalogu %lld\n" #: .././db/check.c:3060 #, c-format msgid "multiple .. entries in dir %lld\n" msgstr "wiele wpisów .. w katalogu %lld\n" #: .././db/check.c:3082 #, c-format msgid "missing free index for data block %d in dir ino %lld\n" msgstr "" "brak indeksu wolnego miejsca dla bloku danych %d w i-węźle katalogu %lld\n" #: .././db/check.c:3110 .././db/check.c:3188 #, c-format msgid "bad free block firstdb %d for dir ino %lld block %d\n" msgstr "błędne firstdb wolnego bloku %d dla i-wÄ™zÅ‚a katalogu %lld, blok %d\n" #: .././db/check.c:3121 .././db/check.c:3199 #, c-format msgid "bad free block nvalid/nused %d/%d for dir ino %lld block %d\n" msgstr "" "błędne liczby nvalid/nused (%d/%d) wolnych bloków w i-węźle katalogu %lld, " "blok %d\n" #: .././db/check.c:3135 .././db/check.c:3213 #, c-format msgid "bad free block ent %d is %d should be %d for dir ino %lld block %d\n" msgstr "" "błędna liczba ent %d (równa %d, powinna być %d) wolnego bloku w i-węźle " "katalogu %lld, blok %d\n" #: .././db/check.c:3149 .././db/check.c:3227 #, c-format msgid "bad free block nused %d should be %d for dir ino %lld block %d\n" msgstr "" "błędna liczba nused (%d, powinna być %d) wolnego bloku w i-węźle katalogu " "%lld, blok %d\n" #: .././db/check.c:3174 #, c-format msgid "bad free block magic # %#x for dir ino %lld block %d\n" msgstr "" "błędna liczba magiczna wolnego bloku %#x dla i-wÄ™zÅ‚a katalogu %lld, blok %d\n" #: .././db/check.c:3281 #, c-format msgid "bad leaf block forw/back pointers %d/%d for dir ino %lld block %d\n" msgstr "" "błędne wskaźniki przód/tyÅ‚ (%d/%d) bloku liÅ›cia w i-węźle katalogu %lld, " "blok %d\n" #: .././db/check.c:3290 #, c-format msgid "single leaf block for dir ino %lld block %d should be at block %d\n" msgstr "" "blok pojedynczego liÅ›cia dla i-wÄ™zÅ‚u katalogu %lld, blok %d powinien być w " "bloku %d\n" #: .././db/check.c:3302 #, c-format msgid "bestfree %d for dir ino %lld block %d doesn't match table value %d\n" msgstr "" "bestfree %d dla i-wÄ™zÅ‚a katalogu %lld, blok %d nie zgadza siÄ™ z wartoÅ›ciÄ… w " "tablicy %d\n" #: .././db/check.c:3327 #, c-format msgid "bad node block level %d for dir ino %lld block %d\n" msgstr "błędny poziom bloku wÄ™zÅ‚a %d dla i-wÄ™zÅ‚a katalogu %lld, blok %d\n" #: .././db/check.c:3359 #, c-format msgid "dir3 %lld block %d stale mismatch %d/%d\n" msgstr "katalog dir3 %lld, blok %d: niezgodność liczby stale %d/%d\n" #: .././db/check.c:3366 #, c-format msgid "dir %lld block %d stale mismatch %d/%d\n" msgstr "katalog %lld, blok %d: niezgodność liczby stale %d/%d\n" #: .././db/check.c:3422 #, c-format msgid "can't read block %lld for %s quota inode (fsblock %lld)\n" msgstr "nie można odczytać bloku %lld i-wÄ™zÅ‚a limitów %s (blok fs %lld)\n" #: .././db/check.c:3432 #, c-format msgid "%s dqblk %lld entry %d id %u bc %lld ic %lld rc %lld\n" msgstr "%s dqblk %lld wpis %d id %u bc %lld ic %lld rc %lld\n" #: .././db/check.c:3440 #, c-format msgid "bad magic number %#x for %s dqblk %lld entry %d id %u\n" msgstr "błędna liczba magiczna %#x dla dqblk %s %lld, wpis %d, id %u\n" #: .././db/check.c:3449 #, c-format msgid "bad version number %#x for %s dqblk %lld entry %d id %u\n" msgstr "błędny numer wersji %#x dla dqblk %s %lld, wpis %d, id %u\n" #: .././db/check.c:3459 #, c-format msgid "bad flags %#x for %s dqblk %lld entry %d id %u\n" msgstr "błędne flagi %#x dla dqblk %s %lld, wpis %d, id %u\n" #: .././db/check.c:3468 #, c-format msgid "bad id %u for %s dqblk %lld entry %d id %u\n" msgstr "błędne id %u dla dqblk %s %lld, wpis %d, id %u\n" #: .././db/check.c:3514 #, c-format msgid "block %lld for rtbitmap inode is missing\n" msgstr "brak bloku %lld dla i-wÄ™zÅ‚a rtbitmapy\n" #: .././db/check.c:3525 #, c-format msgid "can't read block %lld for rtbitmap inode\n" msgstr "nie można odczytać bloku %lld dla i-wÄ™zÅ‚a rtbitmapy\n" #: .././db/check.c:3581 #, c-format msgid "block %lld for rtsummary inode is missing\n" msgstr "brak bloku %lld dla i-wÄ™zÅ‚a rtsummary\n" #: .././db/check.c:3592 #, c-format msgid "can't read block %lld for rtsummary inode\n" msgstr "nie można odczytać bloku %lld dla i-wÄ™zÅ‚a rtsummary\n" #: .././db/check.c:3625 #, c-format msgid "dir %lld entry . %lld\n" msgstr "katalog %lld, wpis . %lld\n" #: .././db/check.c:3633 #, c-format msgid "dir %llu bad size in entry at %d\n" msgstr "katalog %llu: błędny rozmiar we wpisie przy %d\n" #: .././db/check.c:3645 #, c-format msgid "dir %lld entry %*.*s bad inode number %lld\n" msgstr "katalog %lld wpis %*.*s: błędny numer i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:3657 #, c-format msgid "dir %lld entry %*.*s offset %d %lld\n" msgstr "katalog %lld wpis %*.*s offset %d %lld\n" #: .././db/check.c:3662 #, c-format msgid "dir %lld entry %*.*s bad offset %d\n" msgstr "katalog %lld wpis %*.*s błędny offset %d\n" #: .././db/check.c:3675 #, c-format msgid "dir %llu size is %lld, should be %u\n" msgstr "katalog %llu: rozmiar %lld, powinien być %u\n" #: .././db/check.c:3683 #, c-format msgid "dir %llu offsets too high\n" msgstr "katalog %llu: offsety zbyt duże\n" #: .././db/check.c:3694 #, c-format msgid "dir %lld entry .. bad inode number %lld\n" msgstr "katalog %lld wpis .. - błędny numer i-wÄ™zÅ‚a %lld\n" #: .././db/check.c:3699 #, c-format msgid "dir %lld entry .. %lld\n" msgstr "katalog %lld wpis .. %lld\n" #: .././db/check.c:3702 #, c-format msgid "dir %lld i8count mismatch is %d should be %d\n" msgstr "katalog %lld: niezgodność i8count: jest %d, powinno być %d\n" #: .././db/check.c:3784 #, c-format msgid "%s quota id %u, have/exp" msgstr "limit %s id %u: jest/exp" #: .././db/check.c:3787 #, c-format msgid " bc %lld/%lld" msgstr " bc %lld/%lld" #: .././db/check.c:3791 #, c-format msgid " ic %lld/%lld" msgstr " ic %lld/%lld" #: .././db/check.c:3795 #, c-format msgid " rc %lld/%lld" msgstr " rc %lld/%lld" #: .././db/check.c:3851 #, c-format msgid "can't read superblock for ag %u\n" msgstr "nie można odczytać superbloku dla ag %u\n" #: .././db/check.c:3860 #, c-format msgid "bad sb magic # %#x in ag %u\n" msgstr "błędna liczba magiczna %#x superbloku w ag %u\n" #: .././db/check.c:3866 #, c-format msgid "bad sb version # %#x in ag %u\n" msgstr "błędny numer wersji %#x superbloku w ag %u\n" #: .././db/check.c:3876 .././db/sb.c:217 msgid "mkfs not completed successfully\n" msgstr "mkfs nie zakoÅ„czony pomyÅ›lnie\n" #: .././db/check.c:3888 .././db/frag.c:370 #, c-format msgid "can't read agf block for ag %u\n" msgstr "nie można odczytać bloku agf dla ag %u\n" #: .././db/check.c:3894 #, c-format msgid "bad agf magic # %#x in ag %u\n" msgstr "błędna liczba magiczna agf %#x w ag %u\n" #: .././db/check.c:3900 #, c-format msgid "bad agf version # %#x in ag %u\n" msgstr "błędny numer wersji agf %#x w ag %u\n" #: .././db/check.c:3916 .././db/frag.c:379 #, c-format msgid "can't read agi block for ag %u\n" msgstr "nie można odczytać bloku agi w ag %u\n" #: .././db/check.c:3922 #, c-format msgid "bad agi magic # %#x in ag %u\n" msgstr "błędna liczba magiczna agi %#x w ag %u\n" #: .././db/check.c:3928 #, c-format msgid "bad agi version # %#x in ag %u\n" msgstr "błędny numer wersji agi # %#x w ag %u\n" #: .././db/check.c:3971 .././repair/scan.c:2258 #, c-format msgid "agf_freeblks %u, counted %u in ag %u\n" msgstr "agf_freeblks %u, naliczono %u w ag %u\n" #: .././db/check.c:3978 .././repair/scan.c:2263 #, c-format msgid "agf_longest %u, counted %u in ag %u\n" msgstr "agf_longest %u, naliczono %u w ag %u\n" #: .././db/check.c:3986 #, c-format msgid "agf_btreeblks %u, counted %u in ag %u\n" msgstr "agf_btreeblks %u, naliczono %u w ag %u\n" #: .././db/check.c:3994 .././repair/scan.c:2312 #, c-format msgid "agi_count %u, counted %u in ag %u\n" msgstr "agi_count %u, naliczono %u w ag %u\n" #: .././db/check.c:4001 .././repair/scan.c:2317 #, c-format msgid "agi_freecount %u, counted %u in ag %u\n" msgstr "agi_freecount %u, naliczono %u w ag %u\n" #: .././db/check.c:4010 #, c-format msgid "agi unlinked bucket %d is %u in ag %u (inode=%lld)\n" msgstr "agi unlinked bucket %d is %u in ag %u (inode=%lld)\n" #: .././db/check.c:4048 #, c-format msgid "can't read agfl block for ag %u\n" msgstr "nie można odczytać bloku agfl dla ag %u\n" #: .././db/check.c:4058 .././db/freesp.c:259 .././repair/scan.c:2148 #, c-format msgid "agf %d freelist blocks bad, skipping freelist scan\n" msgstr "" "błędne bloki listy wolnych agf %d, pominiÄ™to przeszukanie listy wolnych\n" #: .././db/check.c:4080 #, c-format msgid "freeblk count %u != flcount %u in ag %u\n" msgstr "liczba freeblk %u != flcount %u w ag %u\n" #: .././db/check.c:4109 .././db/check.c:4137 .././db/frag.c:402 #: .././db/frag.c:425 .././db/freesp.c:293 #, c-format msgid "can't read btree block %u/%u\n" msgstr "nie można odczytać bloku b-drzewa %u/%u\n" #: .././db/check.c:4171 #, c-format msgid "bad magic # %#x in inode %lld bmbt block %u/%u\n" msgstr "błędna liczba magiczna %#x w i-węźle %lld, blok bmbt %u/%u\n" #: .././db/check.c:4178 #, c-format msgid "expected level %d got %d in inode %lld bmbt block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w i-węźle %lld, blok bmbt %u/%u\n" #: .././db/check.c:4190 .././db/check.c:4207 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in inode %lld bmap block %lld\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w i-węźle %lld, blok " "bitmapy %lld\n" #: .././db/check.c:4236 #, c-format msgid "bad magic # %#x in btbno block %u/%u\n" msgstr "błędna liczba magiczna %#x w bloku btbno %u/%u\n" #: .././db/check.c:4245 #, c-format msgid "expected level %d got %d in btbno block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku btbno %u/%u\n" #: .././db/check.c:4254 .././db/check.c:4282 .././db/check.c:4328 #: .././db/check.c:4359 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in btbno block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bloku btbno %u/%u\n" #: .././db/check.c:4269 .././repair/scan.c:672 #, c-format msgid "out-of-order bno btree record %d (%u %u) block %u/%u\n" msgstr "rekord b-drzewa bno poza kolejnoÅ›ciÄ…: %d (%u %u), blok %u/%u\n" #: .././db/check.c:4310 #, c-format msgid "bad magic # %#x in btcnt block %u/%u\n" msgstr "błędna liczba magiczna %#x w bloku btcbt %u/%u\n" #: .././db/check.c:4319 #, c-format msgid "expected level %d got %d in btcnt block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku btcnt %u/%u\n" #: .././db/check.c:4347 .././repair/scan.c:684 #, c-format msgid "out-of-order cnt btree record %d (%u %u) block %u/%u\n" msgstr "rekord b-drzewa cnt poza kolejnoÅ›ciÄ…: %d (%u %u), blok %u/%u\n" #: .././db/check.c:4405 #, c-format msgid "bad magic # %#x in inobt block %u/%u\n" msgstr "błędna liczba magiczna %#x w bloku inobt %u/%u\n" #: .././db/check.c:4412 #, c-format msgid "expected level %d got %d in inobt block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku inobt %u/%u\n" #: .././db/check.c:4421 .././db/check.c:4507 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in inobt block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bloku inobt %u/%u\n" #: .././db/check.c:4464 .././db/frag.c:494 #, c-format msgid "can't read inode block %u/%u\n" msgstr "nie można odczytać bloku i-wÄ™zÅ‚a %u/%u\n" #: .././db/check.c:4495 #, c-format msgid "ir_freecount/free mismatch, inode chunk %u/%u, freecount %d nfree %d\n" msgstr "" "niezgodność ir_freecount/free, porcja i-wÄ™złów %u/%u, freecount %d nfree %d\n" #: .././db/check.c:4548 #, c-format msgid "bad magic # %#x in finobt block %u/%u\n" msgstr "błędna liczba magiczna %#x w bloku finobt %u/%u\n" #: .././db/check.c:4555 #, c-format msgid "expected level %d got %d in finobt block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku finobt %u/%u\n" #: .././db/check.c:4564 .././db/check.c:4607 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in finobt block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bloku finobt %u/%u\n" #: .././db/check.c:4634 #, c-format msgid "bad magic # %#x in rmapbt block %u/%u\n" msgstr "błędna liczba magiczna %#x w bloku rmapbt %u/%u\n" #: .././db/check.c:4641 #, c-format msgid "expected level %d got %d in rmapbt block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku rmapbt %u/%u\n" #: .././db/check.c:4654 .././db/check.c:4678 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in rmapbt block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bloku rmapbt %u/%u\n" #: .././db/check.c:4666 #, c-format msgid "out-of-order rmap btree record %d (%u %u) block %u/%u\n" msgstr "rekord b-drzewa rmap poza kolejnoÅ›ciÄ…: %d (%u %u), blok %u/%u\n" #: .././db/check.c:4706 #, c-format msgid "bad magic # %#x in refcntbt block %u/%u\n" msgstr "błędna liczba magiczna %#x w bloku refcntbt %u/%u\n" #: .././db/check.c:4713 #, c-format msgid "expected level %d got %d in refcntbt block %u/%u\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku refcntbt %u/%u\n" #: .././db/check.c:4722 .././db/check.c:4774 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in refcntbt block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bloku refcntbt %u/%u\n" #: .././db/check.c:4740 .././repair/scan.c:1356 #, c-format msgid "leftover CoW extent (%u/%u) len %u\n" msgstr "pozostaÅ‚ość ekstentu CoW (%u/%u) dÅ‚ugość %u\n" #: .././db/check.c:4743 #, c-format msgid "leftover CoW extent at unexpected address (%u/%u) len %u\n" msgstr "" "pozostaÅ‚ość ekstentu CoW pod nie oczekiwanym adresem (%u/%u) dÅ‚ugość %u\n" #: .././db/check.c:4761 #, c-format msgid "out-of-order refcnt btree record %d (%u %u) block %u/%u\n" msgstr "rekord b-drzewa refcnt poza kolejnoÅ›ciÄ…: %d (%u %u), blok %u/%u\n" #: .././db/check.c:4817 #, c-format msgid "setting inode to %lld for block %u/%u\n" msgstr "ustawianie i-wÄ™zÅ‚a na %lld dla bloku %u/%u\n" #: .././db/check.c:4849 #, c-format msgid "setting inode to %lld for rtblock %llu\n" msgstr "ustawianie i-wÄ™zÅ‚a na %lld dla rtbloku %llu\n" #: .././db/check.c:4865 #, c-format msgid "inode %lld nlink %u %s dir\n" msgstr "i-wÄ™zeÅ‚ %lld nlink %u katalog %s\n" #: .././db/command.c:86 .././db/help.c:56 .././libxcmd/help.c:50 #, c-format msgid "command %s not found\n" msgstr "nie znaleziono polecenia %s\n" #: .././db/command.c:90 #, c-format msgid "bad argument count %d to %s, expected " msgstr "błędny argument liczby %d dla %s, oczekiwano " #: .././db/command.c:92 #, c-format msgid "at least %d" msgstr "przynajmniej %d" #: .././db/command.c:96 #, c-format msgid "between %d and %d" msgstr "od %d do %d" #: .././db/command.c:97 msgid " arguments\n" msgstr " argumentów\n" #: .././db/convert.c:171 #, c-format msgid "bad argument count %d to convert, expected 3,5,7,9 arguments\n" msgstr "" "błędna liczba argumentów %d do konwersji, oczekiwano 3,5,7,9 argumentów\n" #: .././db/convert.c:176 .././db/convert.c:183 #, c-format msgid "unknown conversion type %s\n" msgstr "nieznany rodzaj konwersji %s\n" #: .././db/convert.c:187 msgid "result type same as argument\n" msgstr "typ wyniku taki sam jak argument\n" #: .././db/convert.c:191 #, c-format msgid "conflicting conversion type %s\n" msgstr "konflikt typu konwersji %s\n" #: .././db/convert.c:269 #, c-format msgid "%s is not a number\n" msgstr "%s nie jest liczbÄ…\n" #: .././db/crc.c:37 msgid "manipulate crc values for V5 filesystem structures" msgstr "operowanie na wartoÅ›ciach crc struktur systemu plików V5" #: .././db/crc.c:50 msgid "" "\n" " 'crc' validates, invalidates, or recalculates the crc value for\n" " the current on-disk metadata structures in Version 5 filesystems.\n" "\n" " Usage: \"crc [-i|-r|-v]\"\n" "\n" msgstr "" "\n" " 'crc' sprawdza, unieważnia lub przelicza wartość crc dla bieżących\n" " struktur metadanych na dysku w systemach plików w wersji 5.\n" "\n" " SkÅ‚adnia: \"crc [-i|-r|-v]\"\n" "\n" #: .././db/crc.c:81 #, c-format msgid "current type (%s) is not a structure\n" msgstr "bieżący typ (%s) nie jest strukturÄ…\n" #: .././db/crc.c:98 msgid "bad option for crc command\n" msgstr "błędna opcja dla polecenia crc\n" #: .././db/crc.c:105 msgid "crc command accepts only one option\n" msgstr "polecenie crc przyjmuje tylko jednÄ… opcjÄ™\n" #: .././db/crc.c:111 #, c-format msgid "%s not in expert mode, writing disabled\n" msgstr "%s: nie w trybie expert, zapis wyłączony\n" #: .././db/crc.c:128 #, c-format msgid "No CRC field found for type %s\n" msgstr "Brak pola CRC dla typu %s\n" #: .././db/crc.c:135 .././db/fuzz.c:419 .././db/write.c:700 msgid "parsing error\n" msgstr "błąd skÅ‚adni\n" #: .././db/crc.c:171 msgid "Invalidating CRC:\n" msgstr "Unieważnianie CRC:\n" #: .././db/crc.c:173 msgid "Recalculating CRC:\n" msgstr "Przeliczanie CRC:\n" #: .././db/crc.c:181 msgid "Verifying CRC:\n" msgstr "Sprawdzanie CRC:\n" #: .././db/debug.c:27 msgid "[flagbits]" msgstr "[bity flag]" #: .././db/debug.c:28 msgid "set debug option bits" msgstr "ustawienie bitów opcji diagnostycznych" #: .././db/debug.c:42 #, c-format msgid "bad value for debug %s\n" msgstr "błędna wartość diagnostyki %s\n" #: .././db/dir2.c:1019 #, c-format msgid "Unknown directory buffer type! %x %x\n" msgstr "Nieznany typ bufora katalogu! %x %x\n" #: .././db/dir2.c:1063 msgid "Unknown directory buffer type!\n" msgstr "Nieznany typ bufora katalogu!\n" #: .././db/dir2.c:1075 msgid "Writing unknown directory buffer type!\n" msgstr "Zapis nieznanego typu bufora katalogu!\n" #: .././db/dquot.c:37 msgid "[-g|-p|-u] id" msgstr "[g|-p|-u] id" #: .././db/dquot.c:38 msgid "" "set current address to a group, project or user quota block for given ID" msgstr "" "ustawienie bieżącego adresu na blok limitu grupy, projektu lub użytkownika o " "podanym ID" #: .././db/dquot.c:129 msgid "bad option for dquot command\n" msgstr "błędna opcja dla polecenia dquot\n" #: .././db/dquot.c:133 msgid "project" msgstr "projekt" #: .././db/dquot.c:133 msgid "group" msgstr "grupÄ™" #: .././db/dquot.c:133 msgid "user" msgstr "użytkownika" #: .././db/dquot.c:135 #, c-format msgid "dquot command requires one %s id argument\n" msgstr "polecenie dquot wymaga jednego argumentu identyfikujÄ…cego %s\n" #: .././db/dquot.c:145 #, c-format msgid "no %s quota inode present\n" msgstr "i-wÄ™zeÅ‚ limitów na %s nie jest dostÄ™pny\n" #: .././db/dquot.c:150 #, c-format msgid "bad %s id for dquot %s\n" msgstr "błędna liczba identyfikujÄ…ca %s dla dquot %s\n" #: .././db/dquot.c:162 #, c-format msgid "no %s quota data for id %d\n" msgstr "brak danych limitów na %s dla id %d\n" #: .././db/echo.c:27 msgid "[args]..." msgstr "[argumenty]..." #: .././db/echo.c:28 msgid "echo arguments" msgstr "wypisanie argumentów" #: .././db/faddr.c:40 .././db/faddr.c:63 msgid "no current allocation group, cannot set new addr\n" msgstr "brak bieżącej grupy alokacji, nie można ustawić nowego adresu\n" #: .././db/faddr.c:45 .././db/faddr.c:117 .././db/faddr.c:148 #: .././db/faddr.c:180 .././db/faddr.c:202 .././db/faddr.c:232 #: .././db/faddr.c:262 .././db/faddr.c:316 .././db/faddr.c:335 msgid "null block number, cannot set new addr\n" msgstr "pusty numer bloku, nie można ustawić nowego adresu\n" #: .././db/faddr.c:68 .././db/faddr.c:353 .././db/faddr.c:370 #: .././db/faddr.c:387 msgid "null inode number, cannot set new addr\n" msgstr "pusty numer i-wÄ™zÅ‚a, nie można ustawić nowego adresu\n" #: .././db/faddr.c:88 msgid "null attribute block number, cannot set new addr\n" msgstr "pusty number bloku atrybutów, nie można ustawić nowego adresu\n" #: .././db/faddr.c:94 msgid "attribute block is unmapped\n" msgstr "blok atrybutów jest nieodwzorowany\n" #: .././db/faddr.c:123 .././db/faddr.c:155 .././db/faddr.c:208 #: .././db/faddr.c:239 msgid "file block is unmapped\n" msgstr "blok pliku jest nieodwzorowany\n" #: .././db/faddr.c:285 msgid "null directory block number, cannot set new addr\n" msgstr "pusty numer bloku katalogu, nie można ustawić nowego adresu\n" #: .././db/faddr.c:292 msgid "directory block is unmapped\n" msgstr "blok katalogu jest nieodwzorowany\n" #: .././db/flist.c:149 #, c-format msgid "field %s not found\n" msgstr "nie znaleziono pola %s\n" #: .././db/flist.c:159 #, c-format msgid "no elements in %s\n" msgstr "brak elementów w %s\n" #: .././db/flist.c:165 #, c-format msgid "indices %d-%d for field %s out of range %d-%d\n" msgstr "indeksy %d-%d dla pola %s sÄ… poza zakresem %d-%d\n" #: .././db/flist.c:173 #, c-format msgid "index %d for field %s out of range %d-%d\n" msgstr "indeks %d dla pola %s jest poza zakresem %d-%d\n" #: .././db/flist.c:187 #, c-format msgid "field %s is not an array\n" msgstr "pole %s nie jest tablicÄ…\n" #: .././db/flist.c:200 #, c-format msgid "field %s has no subfields\n" msgstr "pole %s nie ma podpól\n" #: .././db/flist.c:220 #, c-format msgid "fl@%p:\n" msgstr "fl@%p:\n" #: .././db/flist.c:221 #, c-format msgid "\tname=%s, fld=%p, child=%p, sibling=%p\n" msgstr "\tnazwa=%s, fld=%p, child=%p, sibling=%p\n" #: .././db/flist.c:223 #, c-format msgid "\tlow=%d, high=%d, flags=%d (%s%s), offset=%d\n" msgstr "\tlow=%d, high=%d, flagi=%d (%s%s), offset=%d\n" #: .././db/flist.c:225 msgid "oklow " msgstr "oklow " #: .././db/flist.c:226 msgid "okhigh" msgstr "okhigh" #: .././db/flist.c:227 #, c-format msgid "\tfld->name=%s, fld->ftyp=%d (%s)\n" msgstr "\tfld->name=%s, fld->ftyp=%d (%s)\n" #: .././db/flist.c:230 #, c-format msgid "\tfld->flags=%d (%s%s%s%s%s)\n" msgstr "\tfld->flags=%d (%s%s%s%s%s)\n" #: .././db/flist.c:322 #, c-format msgid "bad syntax in field name %s\n" msgstr "błędna skÅ‚adnia w nazwie pola %s\n" #: .././db/flist.c:378 #, c-format msgid "missing closing quote %s\n" msgstr "brak cudzysÅ‚owu zamykajÄ…cego %s\n" #: .././db/flist.c:395 #, c-format msgid "bad character in field %s\n" msgstr "błędny znak w polu %s\n" #: .././db/fprint.c:99 msgid "null" msgstr "nic" #: .././db/frag.c:173 #, c-format msgid "actual %llu, ideal %llu, fragmentation factor %.2f%%\n" msgstr "obecnie %llu, idealnie %llu, współczynnik fragmentacji %.2f%%\n" #: .././db/frag.c:175 msgid "Note, this number is largely meaningless.\n" msgstr "Uwaga, ta liczba jest zbyt duża, żeby miaÅ‚a znaczenie.\n" #: .././db/frag.c:177 #, c-format msgid "Files on this filesystem average %.2f extents per file\n" msgstr "Pliki w tym systemie plików majÄ… Å›rednio %.2f ekstentów na plik\n" #: .././db/frag.c:218 msgid "bad option for frag command\n" msgstr "błędna opcja dla polecenia frag\n" #: .././db/frag.c:354 #, c-format msgid "inode %lld actual %lld ideal %lld\n" msgstr "i-wÄ™zeÅ‚ %lld obecnie %lld idealnie %lld\n" #: .././db/frag.c:448 .././db/frag.c:458 #, c-format msgid "invalid numrecs (%u) in %s block\n" msgstr "błędne numrecs (%u) w bloku %s\n" #: .././db/freesp.c:111 .././spaceman/freesp.c:365 #, c-format msgid "total free extents %lld\n" msgstr "razem wolnych ekstentów: %lld\n" #: .././db/freesp.c:112 .././spaceman/freesp.c:366 #, c-format msgid "total free blocks %lld\n" msgstr "razem wolnych bloków: %lld\n" #: .././db/freesp.c:113 .././spaceman/freesp.c:367 #, c-format msgid "average free extent size %g\n" msgstr "Å›redni rozmiar wolnego ekstentu: %g\n" #: .././db/freesp.c:207 msgid "" "freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... [-m binmult]\n" msgstr "" "argumenty freesp: [-bcds] [-a agno] [-e binsize] [-h h1]... [-m binmult]\n" #: .././db/freesp.c:434 .././spaceman/freesp.c:131 msgid "from" msgstr "od" #: .././db/freesp.c:434 .././spaceman/freesp.c:131 msgid "to" msgstr "do" #: .././db/freesp.c:434 .././repair/progress.c:26 .././spaceman/freesp.c:131 msgid "extents" msgstr "ekstentów" #: .././db/freesp.c:434 .././repair/progress.c:18 .././spaceman/freesp.c:131 msgid "blocks" msgstr "bloków" #: .././db/freesp.c:434 .././spaceman/freesp.c:131 msgid "pct" msgstr "proc." #: .././db/fsmap.c:39 #, c-format msgid "" "%llu: %u/%u len %u owner %lld offset %llu bmbt %d attrfork %d extflag %d\n" msgstr "" "%llu: %u/%u dÅ‚ugość %u wÅ‚aÅ›c. %lld offset %llu bmbt %d attrfork %d extflag " "%d\n" #: .././db/fsmap.c:86 #, c-format msgid "Error %d while reading AGF.\n" msgstr "Błąd %d podczas odczytu AGF.\n" #: .././db/fsmap.c:93 msgid "Not enough memory.\n" msgstr "Za maÅ‚o pamiÄ™ci.\n" #: .././db/fsmap.c:103 #, c-format msgid "Error %d while querying fsmap btree.\n" msgstr "Błąd %d podczas odpytywania b-drzewa fsmap.\n" #: .././db/fsmap.c:127 msgid "Filesystem does not support reverse mapping btree.\n" msgstr "System plików nie obsÅ‚uguje b-drzewa odwrotnego odwzorowania.\n" #: .././db/fsmap.c:134 msgid "Bad option for fsmap command.\n" msgstr "Błędna opcja dla polecenia fsmap.\n" #: .././db/fsmap.c:142 #, c-format msgid "Bad fsmap start_fsb %s.\n" msgstr "Błędna wartość start_fsb dla fsmap: %s.\n" #: .././db/fsmap.c:150 #, c-format msgid "Bad fsmap end_fsb %s.\n" msgstr "Błędna wartość end_fsb dla fsmap: %s.\n" #: .././db/fsmap.c:162 msgid "[start_fsb] [end_fsb]" msgstr "[start_fsb] [end_fsb]" #: .././db/fsmap.c:163 msgid "display reverse mapping(s)" msgstr "wyÅ›wietlenie odwrotnych odwzorowaÅ„" #: .././db/fuzz.c:41 msgid "[-c] [-d] field fuzzcmd..." msgstr "[-c] [-d] pole polecenie-fuzz..." #: .././db/fuzz.c:42 msgid "fuzz values on disk" msgstr "zaburzanie wartoÅ›ci na dysku" #: .././db/fuzz.c:58 msgid "" "\n" " The 'fuzz' command fuzzes fields in any on-disk data structure. For\n" " block fuzzing, see the 'blocktrash' or 'write' commands.\n" " Examples:\n" " Struct mode: 'fuzz core.uid zeroes' - set an inode uid field to 0.\n" " 'fuzz crc ones' - set a crc filed to all ones.\n" " 'fuzz bno[11] firstbit' - set the high bit of a block " "array.\n" " 'fuzz keys[5].startblock add' - increase a btree key " "value.\n" " 'fuzz uuid random' - randomize the superblock uuid.\n" "\n" " Type 'fuzz' by itself for a list of specific commands.\n" "\n" " Specifying the -c option will allow writes of invalid (corrupt) data with\n" " an invalid CRC. Specifying the -d option will allow writes of invalid " "data,\n" " but still recalculate the CRC so we are forced to check and detect the\n" " invalid data appropriately.\n" "\n" msgstr "" "\n" " Polecenie 'fuzz' zaburza pola w dowolnej strukturze danych na dysky.\n" " Zaburzanie bloków jest dostÄ™pne w poleceniach 'blocktrash' lub 'write'.\n" " PrzykÅ‚ady:\n" " Tryb struktur: 'fuzz core.uid zeroes' - ustawienie pole uid i-wÄ™zÅ‚a na " "0.\n" " 'fuzz src ones' - wypeÅ‚nienie CRC samymi " "jedynkami.\n" " 'fuzz bno[11] firstbit' - ust. najstarszego bitu tab. " "bloków.\n" " 'fuzz keys[5].startblock add' - zwiÄ™kszenie klucza b-" "drzewa.\n" " 'fuzz uuid random' - losowy UUID superbloku.\n" "\n" " Samo 'fuzz' wyÅ›wietli listÄ™ konkretnych poleceÅ„.\n" "\n" " Podanie opcji -c pozwala na zapis nieprawidÅ‚owych (uszkodzonych) danych\n" " z błędnÄ… sumÄ… CRC. Podanie opcji -d pozwala na zapis nieprawidÅ‚owych " "danych,\n" " ale z przeliczeniem CRC, wymuszajÄ…c odpowiednie sprawdzanie i wykrycie\n" " błędnych danych.\n" "\n" #: .././db/fuzz.c:92 #, c-format msgid "%s started in read only mode, fuzzing disabled\n" msgstr "%s uruchomiono w trybie tylko do odczytu, zaburzanie wyłączone\n" #: .././db/fuzz.c:104 #, c-format msgid "no handler function for type %s, fuzz unsupported.\n" msgstr "brak funkcji obsÅ‚ugujÄ…cej dla typu %s, zaburzanie nie obsÅ‚ugiwane.\n" #: .././db/fuzz.c:118 msgid "bad option for fuzz command\n" msgstr "błędna opcja dla polecenia fuzz\n" #: .././db/fuzz.c:124 .././db/write.c:136 msgid "Cannot specify both -c and -d options\n" msgstr "Nie można podać jednoczeÅ›nie opcji -c i -d\n" #: .././db/fuzz.c:131 .././db/write.c:143 msgid "Cannot recalculate CRCs on this type of object\n" msgstr "Nie można przeliczyć CRC dla tego typu obiektu\n" #: .././db/fuzz.c:158 msgid "Allowing fuzz of corrupted data and bad CRC\n" msgstr "Zezwolenie na zaburzanie z uszkodzonymi danymi i błędnÄ… sumÄ… CRC\n" #: .././db/fuzz.c:161 .././db/fuzz.c:164 msgid "Allowing fuzz of corrupted data with good CRC\n" msgstr "Zezwolenie na zaburzanie z uszkodzonymi danymi i dobrÄ… sumÄ… CRC\n" #: .././db/fuzz.c:387 msgid "Usage: fuzz fieldname fuzzcmd\n" msgstr "SkÅ‚adnia: fuzz nazwa-pola polecenie-fuzz\n" #: .././db/fuzz.c:397 .././db/write.c:686 #, c-format msgid "unable to parse '%s'.\n" msgstr "nie można przeanalizować '%s'.\n" #: .././db/fuzz.c:406 #, c-format msgid "Unknown fuzz command '%s'.\n" msgstr "Nieznane polecenie fuzz '%s'.\n" #: .././db/fuzz.c:452 #, c-format msgid "unable to fuzz field '%s'\n" msgstr "nie można zaburzyć pola '%s'\n" #: .././db/hash.c:30 msgid "string" msgstr "Å‚aÅ„cuch" #: .././db/hash.c:31 msgid "calculate hash value" msgstr "obliczenie wartoÅ›ci skrótu" #: .././db/hash.c:37 msgid "" "\n" " 'hash' prints out the calculated hash value for a string using the\n" "directory/attribute code hash function.\n" "\n" " Usage: \"hash \"\n" "\n" msgstr "" "\n" " 'hash' wypisuje wartość skrótu dla Å‚aÅ„cucha obliczonÄ… przy użyciu funkcji\n" " haszujÄ…cej dla katalogów/atrybutów.\n" "\n" " SkÅ‚adnia: \"hash <Å‚aÅ„cuch>\"\n" "\n" #: .././db/help.c:30 .././db/io.c:51 .././libxcmd/help.c:93 msgid "[command]" msgstr "[polecenie]" #: .././db/help.c:31 .././libxcmd/help.c:94 msgid "help for one or all commands" msgstr "opis dla jednego lub wszystkich poleceÅ„" #: .././db/help.c:40 .././libxcmd/help.c:34 #, c-format msgid "" "\n" "Use 'help commandname' for extended help.\n" msgstr "" "\n" "Rozszerzony opis można uzyskać przez 'help nazwa_polecenia'.\n" #: .././db/help.c:89 #, c-format msgid "(or %s) " msgstr "(lub %s) " #: .././db/init.c:49 #, c-format msgid "Usage: %s [-ifFrxV] [-p prog] [-l logdev] [-c cmd]... device\n" msgstr "" "SkÅ‚adnia: %s [-ifFrxV] [-p prog] [-l urz-log] [-c polecenie]... urzÄ…dzenie\n" #: .././db/init.c:117 msgid "" "\n" "fatal error -- couldn't initialize XFS library\n" msgstr "" "\n" "błąd krytyczny - nie udaÅ‚o siÄ™ zainicjować biblioteki XFS\n" #: .././db/init.c:132 #, c-format msgid "%s: %s is invalid (cannot read first 512 bytes)\n" msgstr "%s: %s jest nieprawidÅ‚owy (nie można odczytać pierwszych 512 bajtów)\n" #: .././db/init.c:144 #, c-format msgid "" "%s: %s is not a valid XFS filesystem (unexpected SB magic number 0x%08x)\n" msgstr "" "%s: %s nie jest poprawnym systemem plików XFS (nieoczekiwana liczba magiczna " "SB 0x%08x)\n" #: .././db/init.c:147 #, c-format msgid "Use -F to force a read attempt.\n" msgstr "Opcja -F pozwala wymusić próbÄ™ odczytu.\n" #: .././db/init.c:157 #, c-format msgid "%s: device %s unusable (not an XFS filesystem?)\n" msgstr "" "%s: urzÄ…dzenie %s nie nadaje siÄ™ do użycia (to nie jest system plików XFS?)\n" #: .././db/init.c:176 #, c-format msgid "%s: cannot init perag data (%d). Continuing anyway.\n" msgstr "" "%s: nie można zainicjować danych perag (%d). Kontynuacja mimo wszystko.\n" #: .././db/inode.c:421 #, c-format msgid "bad value for inode number %s\n" msgstr "błędna wartość numeru i-wÄ™zÅ‚a %s\n" #: .././db/inode.c:428 #, c-format msgid "current inode number is %lld\n" msgstr "numer bieżącego i-wÄ™zÅ‚a to %lld\n" #: .././db/inode.c:662 #, c-format msgid "bad inode number %lld\n" msgstr "błędny numer i-wÄ™zÅ‚a %lld\n" #: .././db/inode.c:709 #, c-format msgid "Metadata CRC error detected for ino %lld\n" msgstr "Wykryto błąd CRC metadanych dla i-wÄ™zÅ‚a %lld\n" #: .././db/input.c:43 msgid "source-file" msgstr "plik-źródÅ‚owy" #: .././db/input.c:44 msgid "get commands from source-file" msgstr "odczyt poleceÅ„ z pliku-źródÅ‚owego" #: .././db/input.c:331 #, c-format msgid "can't open %s\n" msgstr "nie można otworzyć %s\n" #: .././db/io.c:49 msgid "pop location from the stack" msgstr "odtworzenie pozycji ze stosu" #: .././db/io.c:52 msgid "push location to the stack" msgstr "zapisanie pozycji na stos" #: .././db/io.c:55 msgid "view the location stack" msgstr "podejrzenie stosu pozycji" #: .././db/io.c:58 msgid "move forward to next entry in the position ring" msgstr "przejÅ›cie na nastÄ™pnÄ… pozycjÄ™ w krÄ™gu" #: .././db/io.c:61 msgid "move to the previous location in the position ring" msgstr "przejÅ›cie na poprzedniÄ… pozycjÄ™ w krÄ™gu" #: .././db/io.c:64 msgid "show position ring or move to a specific entry" msgstr "pokazanie krÄ™gu pozycji lub przejÅ›cie do okreÅ›lonego wpisu" #: .././db/io.c:94 #, c-format msgid "can't set block offset to %d\n" msgstr "nie można ustawić offsetu bloku na %d\n" #: .././db/io.c:107 msgid "can't pop anything from I/O stack\n" msgstr "nie można pobrać nic ze stosu we/wy\n" #: .././db/io.c:141 msgid "" "\n" " Changes the address and data type to the first entry on the stack.\n" "\n" msgstr "" "\n" " Zmiana adresu i typu danych na pierwszy wpis ze stosu.\n" "\n" #: .././db/io.c:155 #, c-format msgid "\tbyte offset %lld, length %d\n" msgstr "\toffset w bajtach %lld, dÅ‚ugość %d\n" #: .././db/io.c:156 #, c-format msgid "\tbuffer block %lld (fsbno %lld), %d bb%s\n" msgstr "\tblok bufora %lld (fsbno %lld), %d bb%s\n" #: .././db/io.c:160 .././db/io.c:547 #, c-format msgid "\tblock map" msgstr "\tmapa bloków" #: .././db/io.c:166 #, c-format msgid "\tinode %lld, dir inode %lld, type %s\n" msgstr "\ti-wÄ™zeÅ‚ %lld, i-wÄ™zeÅ‚ katalogu %lld, typ %s\n" #: .././db/io.c:167 .././growfs/xfs_growfs.c:88 .././logprint/log_misc.c:107 #: .././mkfs/xfs_mkfs.c:2587 #, c-format msgid "none" msgstr "brak" #: .././db/io.c:177 msgid "no entries in location ring.\n" msgstr "brak wpisów w krÄ™gu pozycji.\n" #: .././db/io.c:181 msgid " type bblock bblen fsbno inode\n" msgstr " typ bblok bblen fsbno i-wÄ™zeÅ‚\n" #: .././db/io.c:248 #, c-format msgid "no such command %s\n" msgstr "nieznane polecenie %s\n" #: .././db/io.c:252 #, c-format msgid "no push form allowed for %s\n" msgstr "forma push niedozwolona dla %s\n" #: .././db/io.c:269 msgid "" "\n" " Allows you to push the current address and data type on the stack for\n" " later return. 'push' also accepts an additional command to execute after\n" " storing the current address (ex: 'push a rootino' from the superblock).\n" "\n" msgstr "" "\n" " Pozwala zapisać bieżący adres i typ danych na stos w celu późniejszego\n" " powrotu. 'push' akceptuje także dodatkowe polecenie do wykonania po " "zapisaniu\n" " bieżącego adresu (np. 'push a rootino' z superbloku).\n" "\n" #: .././db/io.c:285 .././db/io.c:325 msgid "ring is empty\n" msgstr "krÄ…g jest pusty\n" #: .././db/io.c:289 msgid "no further entries\n" msgstr "brak dalszych wpisów\n" #: .././db/io.c:308 msgid "" "\n" " The 'forward' ('f') command moves to the next location in the position\n" " ring, updating the current position and data type. If the current " "location\n" " is the top entry in the ring, then the 'forward' command will have\n" " no effect.\n" "\n" msgstr "" "\n" " Polecenie 'forward' ('f') przechodzi do nastÄ™pnej pozycji w krÄ™gu,\n" " uaktualniajÄ…c bieżącÄ… pozycjÄ™ i typ danych. JeÅ›li bieżąca pozycja\n" " jest szczytowym wpisem w krÄ™gu, polecenie nie przyniesie efektu.\n" "\n" #: .././db/io.c:329 msgid "no previous entries\n" msgstr "brak poprzednich wpisów\n" #: .././db/io.c:348 msgid "" "\n" " The 'back' ('b') command moves to the previous location in the position\n" " ring, updating the current position and data type. If the current " "location\n" " is the last entry in the ring, then the 'back' command will have no " "effect.\n" "\n" msgstr "" "\n" " Polecenie 'back' ('b') przechodzi do poprzedniej pozycji w krÄ™gu,\n" " uaktualniajÄ…c bieżącÄ… pozycjÄ™ i typ danych. JeÅ›li bieżąca pozycja\n" " jest ostatnim wpisem w krÄ™gu, polecenie nie przyniesie efektu.\n" "\n" #: .././db/io.c:371 #, c-format msgid "invalid entry: %d\n" msgstr "błędny wpis: %d\n" #: .././db/io.c:390 #, c-format msgid "" "\n" " The position ring automatically keeps track of each disk location and\n" " structure type for each change of position you make during your xfs_db\n" " session. The last %d most recent entries are kept in the ring.\n" "\n" " To display the current list of ring entries type 'ring' by itself on\n" " the command line. The entry highlighted by an asterisk ('*') is the\n" " current entry.\n" "\n" " To move to another entry in the ring type 'ring ' where is\n" " your desired entry from the ring position list.\n" "\n" " You may also use the 'forward' ('f') or 'back' ('b') commands to move\n" " to the previous or next entry in the ring, respectively.\n" "\n" " Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n" " location implicitly. Use the 'push' and 'pop' commands if you wish to\n" " store a specific location explicitly for later return.\n" "\n" msgstr "" "\n" " KrÄ…g pozycji automatycznie Å›ledzi każde poÅ‚ożenie na dysku i typ struktury\n" " dla każdej zmiany pozycji wykonywanej podczas sesji xfs_db. Ostatenie %d\n" " pozycji jest trzymane w krÄ™gu.\n" "\n" " Aby wyÅ›wietlić bieżącÄ… listÄ™ wpisów w krÄ™gu należy napisać w linii poleceÅ„\n" " po prostu 'ring'. Wpis oznaczony gwiazdkÄ… ('*') jest wpisem bieżącym.\n" "\n" " Aby przejść do innego wpisu w krÄ™gu, należy wpisać 'ring ', gdzie\n" " jest numerem pożądanego wpisu na liÅ›cie pozycji.\n" "\n" " Można także używać poleceÅ„ 'forward' ('f') i 'back' ('b'), aby przenieść\n" " siÄ™ odpowiednio na poprzedni lub nastÄ™pny wpis w krÄ™gu.\n" "\n" " Uwaga: w przeciwieÅ„stwie do poleceÅ„ 'stack', 'push' i 'pop', krÄ…g Å›ledzi\n" " pozycje niejawnie. Aby zapisać jawnie dane poÅ‚ożenie w celu późniejszego\n" " powrotu, należy użyć poleceÅ„ 'push' i 'pop'.\n" "\n" #: .././db/io.c:443 .././db/io.c:459 #, c-format msgid "write error: %s\n" msgstr "błąd zapisu: %s\n" #: .././db/io.c:449 .././db/io.c:465 #, c-format msgid "read error: %s\n" msgstr "błąd odczytu: %s\n" #: .././db/io.c:488 msgid "nothing to write\n" msgstr "nie ma nic do zapisania\n" #: .././db/io.c:533 msgid "set_cur no stack element to set\n" msgstr "set_cur: brak elementu stosu do ustawienia\n" #: .././db/io.c:546 #, c-format msgid "xfs_db got a bbmap for %lld\n" msgstr "xfs_db ma bbmap dla %lld\n" #: .././db/io.c:646 msgid "" "\n" " The stack is used to explicitly store your location and data type\n" " for later return. The 'push' operation stores the current address\n" " and type on the stack, the 'pop' operation returns you to the\n" " position and datatype of the top entry on the stack.\n" "\n" " The 'stack' allows explicit location saves, see 'ring' for implicit\n" " position tracking.\n" "\n" msgstr "" "\n" " Stos sÅ‚uży do jawnego zapisania pozycji i typu danych w celu późniejszego\n" " powrotu. Operacja 'push' zapisuje bieżący adres i typ na stosie, a " "operacja\n" " 'pop' odtwarza bieżący adres i typ danych z wierzchu stosu.\n" "\n" " Stos ('stack') pozwala na jawne zapisywanie pozycji; domyÅ›lnie pozycje sÄ…\n" " Å›ledzone poprzez krÄ…g (p. 'ring').\n" "\n" #: .././db/logformat.c:89 msgid "The log is dirty. Please mount to replay the log.\n" msgstr "Log jest brudny. ProszÄ™ zamontować, aby odtworzyć log.\n" #: .././db/logformat.c:121 msgid "" "\n" " The 'logformat' command reformats (clears) the log to the specified log\n" " cycle and log stripe unit. If the log cycle is not specified, the log is\n" " reformatted to the current cycle. If the log stripe unit is not specified,\n" " the stripe unit from the filesystem superblock is used.\n" "\n" msgstr "" "\n" " Polecenie 'logformat' reformatuje (czyÅ›ci) log do okreÅ›lonego cyklu logu\n" " oraz jednostki pasa logu. JeÅ›li nie podano cyklu logu, log jest " "reformatowany\n" " do cyklu bieżącego. JeÅ›li nie podano jednostki pasa, używana jest " "jednostka\n" " pasa z superbloku systemu plików.\n" "\n" #: .././db/logformat.c:137 msgid "[-c cycle] [-s sunit]" msgstr "[-c cykl] [-s jednostka-pasa]" #: .././db/logformat.c:138 msgid "reformat the log" msgstr "reformatowanie logu" #: .././db/malloc.c:27 #, c-format msgid "%s: out of memory\n" msgstr "%s: brak pamiÄ™ci\n" #: .././db/metadump.c:60 msgid "[-a] [-e] [-g] [-m max_extent] [-w] [-o] filename" msgstr "[-a] [-e] [-g] [-m max_extent] [-w] [-o] nazwa-pliku" #: .././db/metadump.c:61 msgid "dump metadata to a file" msgstr "zrzut metadanych do pliku" #: .././db/metadump.c:93 #, c-format msgid "" "\n" " The 'metadump' command dumps the known metadata to a compact file suitable\n" " for compressing and sending to an XFS maintainer for corruption analysis \n" " or xfs_repair failures.\n" "\n" " Options:\n" " -a -- Copy full metadata blocks without zeroing unused space\n" " -e -- Ignore read errors and keep going\n" " -g -- Display dump progress\n" " -m -- Specify max extent size in blocks to copy (default = %d blocks)\n" " -o -- Don't obfuscate names and extended attributes\n" " -w -- Show warnings of bad metadata information\n" "\n" msgstr "" "\n" " Polecenie 'metadump' zrzuca znane metadane do zwiÄ™zÅ‚ego pliku nadajÄ…cego " "siÄ™\n" " do skompresowania i wysÅ‚ania prowadzÄ…cym projekt XFS w celu analizy " "uszkodzeÅ„\n" " lub błędów xfs_repair.\n" "\n" " Opcje:\n" " -a - skopiowanie peÅ‚nych bloków metadanych bez zerowania nie używanego " "miejsca\n" " -e - ignorowanie błędów odczytu i kontynuowanie\n" " -g - wyÅ›wietlanie postÄ™pu\n" " -m - okreÅ›lenie maksymalnego rozmiaru ekstentu (w blokach) do " "skopiowania\n" " (domyÅ›lnie %d bloków)\n" " -o - bez zaciemniania nazw i rozszerzonych atrybutów\n" " -w - wyÅ›wietlanie ostrzeżeÅ„ o błędnych metadanych\n" "\n" #: .././db/metadump.c:2765 msgid "" "Warning: log recovery of an obfuscated metadata image can leak unobfuscated " "metadata and/or cause image corruption. If possible, please mount the " "filesystem to clean the log, or disable obfuscation." msgstr "" "Uwaga: odtworzenie logu obrazu zaciemnionych metadanych może spowodować " "wyciek zaciemnionych metadanych i/lub uszkodzenie obrazu. W miarÄ™ możliwoÅ›ci " "proszÄ™ zamontować system plików, aby wyczyÅ›cić log, lub wyłączyć " "zaciemnianie." #: .././db/metadump.c:2773 msgid "Could not discern log; image will contain unobfuscated metadata in log." msgstr "" "Nie udaÅ‚o siÄ™ doszukać logu; obraz bÄ™dzie zawieraÅ‚ niezaciemnione metadane w " "logu." #: .././db/output.c:30 msgid "[stop|start ]" msgstr "[stop|start ]" #: .././db/output.c:31 msgid "start or stop logging to a file" msgstr "rozpoczÄ™cie lub zakoÅ„czenie logowania do pliku" #: .././db/output.c:68 #, c-format msgid "logging to %s\n" msgstr "logowanie do %s\n" #: .././db/output.c:70 .././db/output.c:77 msgid "no log file\n" msgstr "brak pliku logu\n" #: .././db/output.c:80 #, c-format msgid "already logging to %s\n" msgstr "już ustawiono logowanie do %s\n" #: .././db/output.c:84 #, c-format msgid "can't open %s for writing\n" msgstr "nie można otworzyć %s do zapisu\n" #: .././db/output.c:90 msgid "bad log command, ignored\n" msgstr "błędne polecenie logowania, zignorowano\n" #: .././db/print.c:41 msgid "[value]..." msgstr "[wartość]..." #: .././db/print.c:42 msgid "print field values" msgstr "wypisanie wartoÅ›ci pól" #: .././db/print.c:79 #, c-format msgid "no print function for type %s\n" msgstr "brak funkcji wypisujÄ…cej dla typu %s\n" #: .././db/print.c:165 msgid "(empty)\n" msgstr "(puste)\n" #: .././db/print.c:227 msgid "(empty)" msgstr "(puste)" #: .././db/print.c:287 msgid "no arguments allowed\n" msgstr "argumenty nie sÄ… dozwolone\n" #: .././db/quit.c:27 msgid "exit xfs_db" msgstr "zakoÅ„czenie xfs_db" #: .././db/sb.c:45 msgid "set current address to sb header" msgstr "ustawienie bieżącego adresu na nagłówek sb" #: .././db/sb.c:47 msgid "[uuid]" msgstr "[uuid]" #: .././db/sb.c:48 msgid "write/print FS uuid" msgstr "zapisanie/wypisanie uuida FS" #: .././db/sb.c:50 msgid "[label]" msgstr "[etykieta]" #: .././db/sb.c:51 msgid "write/print FS label" msgstr "zapisanie/wypisanie etykiety FS" #: .././db/sb.c:53 msgid "[feature | [vnum fnum]]" msgstr "[cecha | [vnum fnum]]" #: .././db/sb.c:54 msgid "set feature bit(s) in the sb version field" msgstr "ustawienie bitów cech w polu wersji sb" #: .././db/sb.c:140 msgid "" "\n" " set allocation group superblock\n" "\n" " Example:\n" "\n" " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" "\n" " Located in the first sector of each allocation group, the superblock\n" " contains the base information for the filesystem.\n" " The superblock in allocation group 0 is the primary. The copies in the\n" " remaining allocation groups only serve as backup for filesystem recovery.\n" " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" "\n" msgstr "" "\n" " ustawienie superbloku grupy alokacji\n" "\n" " PrzykÅ‚ad:\n" "\n" " 'sb 7' - ustawienie pozycji na superblok 7. grupy alokacji i typu na 'sb'\n" "\n" " PoÅ‚ożony w 1. sektorze każdej grupy alokacji superblok zawiera podstawowe\n" " informacje o systemie plików.\n" " Superblok w grupie alokacji 0 jest główny. Kopie w pozostaÅ‚ych grupach\n" " alokacji sÅ‚użą tylko jako kopie zapasowe do odtwarzania systemu plików.\n" " Liczby icount/ifree/fdblocks/frextents sÄ… uaktualniane tylko w superbloku " "0.\n" "\n" #: .././db/sb.c:199 #, c-format msgid "can't read superblock for AG %u\n" msgstr "nie można odczytać superbloku dla AG %u\n" #: .././db/sb.c:207 #, c-format msgid "bad sb magic # %#x in AG %u\n" msgstr "błędna liczba magiczna superbloku %#x w AG %u\n" #: .././db/sb.c:212 #, c-format msgid "bad sb version # %#x in AG %u\n" msgstr "błędny numer wersji superbloku %#x w AG %u\n" #: .././db/sb.c:236 msgid "aborting - external log specified for FS with an internal log\n" msgstr "" "przerwano - podano log zewnÄ™trzny dla systemu plików z logiem wewnÄ™trznym\n" #: .././db/sb.c:242 msgid "aborting - no external log specified for FS with an external log\n" msgstr "" "przerwano - nie podano logu zewnÄ™trznego dla systemu plików z logiem " "zewnÄ™trznym\n" #: .././db/sb.c:252 msgid "ERROR: cannot find log head/tail, run xfs_repair\n" msgstr "" "BÅÄ„D: nie odnaleziono poczÄ…tku/koÅ„ca logu, proszÄ™ uruchomić xfs_repair\n" #: .././db/sb.c:256 #, c-format msgid "" "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running %s. If you are unable to mount the filesystem, then use\n" "the xfs_repair -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n" msgstr "" "BÅÄ„D: system plików zawiera wartoÅ›ciowe zmiany metadanych w logu, który\n" "musi być odtworzony. Należy zamontować system plików, aby odtworzyć log,\n" "a nastÄ™pnie odmontować go przed ponownym uruchomieniem %s. JeÅ›li\n" "systemu plików nie da siÄ™ zamontować, można użyć opcji -L, aby zniszczyć\n" "log i spróbować naprawić system plików.\n" "Należy zauważyć, że zniszczenie logu może spowodować uszkodzenia danych -\n" "proszÄ™ najpierw spróbować zamontować system plików.\n" #: .././db/sb.c:284 msgid "Clearing log and setting UUID\n" msgstr "Czyszczenei logu i ustawianie UUID-a\n" #: .././db/sb.c:293 msgid "ERROR: cannot clear the log\n" msgstr "BÅÄ„D: nie można wyczyÅ›cić logu\n" #: .././db/sb.c:305 msgid "" "\n" " write/print FS uuid\n" "\n" " Example:\n" "\n" " 'uuid' - print UUID\n" " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" " 'uuid generate' - generate and write\n" " 'uuid rewrite' - copy UUID from SB 0\n" "\n" "The print function checks the UUID in each SB and will warn if the UUIDs\n" "differ between AGs (the log is not checked). The write commands will\n" "set the uuid in all AGs to either a specified value, a newly generated\n" "value or the value found in the first superblock (SB 0) respectively.\n" "As a side effect of writing the UUID, the log is cleared (which is fine\n" "on a CLEANLY unmounted FS).\n" "\n" msgstr "" "\n" " zapisanie/wypisanie uuida systemu plików\n" "\n" "PrzykÅ‚ad:\n" "\n" " 'uuid' - wypisanie UUID-a\n" " 'uuid 01234567-0123-0123-0123-0123456789ab' - zapisanie UUID-a\n" " 'uuid generate' - wygenerowanie i zapisanie\n" " 'uuid rewrite' - skopiowanie UUID-a z sb 0\n" "\n" "Funkcja wypisujÄ…ca sprawdza UUID w każdym superbloku i ostrzega, jeÅ›li UUID-" "y\n" "siÄ™ różniÄ… miÄ™dzy AG (log nie jest sprawdzany). Polecenia zapisu ustawiajÄ…\n" "UUID we wszystkich AG odpowiednio na okreÅ›lonÄ… wartość, nowo wygenerowanÄ…\n" "wartość lub wartość znalezionÄ… w pierwszym superbloku (SB 0).\n" "Jako efekt uboczny zapisu UUID-a czyszczony jest log (co nie jest problemem\n" "przy CZYSTO odmontowanym systemie plików).\n" "\n" #: .././db/sb.c:383 .././db/sb.c:546 msgid "invalid parameters\n" msgstr "błędne parametry\n" #: .././db/sb.c:390 .././db/sb.c:553 .././db/sb.c:722 #, c-format msgid "%s: not in expert mode, writing disabled\n" msgstr "%s: nie w trybie expert, zapis wyłączony\n" #: .././db/sb.c:402 msgid "failed to read UUID from AG 0\n" msgstr "nie udaÅ‚o siÄ™ odczytać UUID-a z AG 0\n" #: .././db/sb.c:407 #, c-format msgid "old UUID = %s\n" msgstr "stary UUID = %s\n" #: .././db/sb.c:421 msgid "invalid UUID\n" msgstr "błędny UUID\n" #: .././db/sb.c:430 .././db/sb.c:558 .././db/sb.c:808 msgid "writing all SBs\n" msgstr "zapisywanie wszystkich superbloków\n" #: .././db/sb.c:433 #, c-format msgid "failed to set UUID in AG %d\n" msgstr "nie udaÅ‚o siÄ™ ustawić UUID-a w AG %d\n" #: .././db/sb.c:438 #, c-format msgid "new UUID = %s\n" msgstr "nowy UUID = %s\n" #: .././db/sb.c:446 #, c-format msgid "failed to read UUID from AG %d\n" msgstr "nie udaÅ‚o siÄ™ odczytać UUID-a z AG %d\n" #: .././db/sb.c:452 #, c-format msgid "warning: UUID in AG %d differs to the primary SB\n" msgstr "uwaga: UUID w AG %d różni siÄ™ od głównego SB\n" #: .././db/sb.c:463 msgid "warning - external log specified for FS with an internal log\n" msgstr "uwaga: podano log zewnÄ™trzny dla systemu plików z logiem wewnÄ™trznym\n" #: .././db/sb.c:466 msgid "warning - no external log specified for FS with an external log\n" msgstr "" "uwaga: nie podano logu zewnÄ™trznego dla systemu plików z logiem zewnÄ™trznym\n" #: .././db/sb.c:471 #, c-format msgid "UUID = %s\n" msgstr "UUID = %s\n" #: .././db/sb.c:482 msgid "" "\n" " write/print FS label\n" "\n" " Example:\n" "\n" " 'label' - print label\n" " 'label 123456789012' - write label\n" " 'label --' - write an empty label\n" "\n" "The print function checks the label in each SB and will warn if the labels\n" "differ between AGs. The write commands will set the label in all AGs to the\n" "specified value. The maximum length of a label is 12 characters - use of a\n" "longer label will result in truncation and a warning will be issued.\n" "\n" msgstr "" "\n" " zapisanie/wypisanie etykiety systemu plików\n" "\n" " PrzykÅ‚ad:\n" "\n" " 'label' - wypisanie etykiety\n" " 'label 123456789012' - zapisanie etykiety\n" " 'label --' - zapisanie etykiety pustej\n" "\n" "Funkcja wypisujÄ…ca sprawdza etykietÄ™ w każdym superbloku i ostrzega, jeÅ›li\n" "etykiety różniÄ… siÄ™ miÄ™dzy AG. Polecenia zapisu ustawiajÄ… etykietw we\n" "wszystkich AG na okreÅ›lonÄ… wartość. Maksymalna dÅ‚ugość etykiety to 12 " "znaków;\n" "użycie etykiety dÅ‚uższej zaskutkuje uciÄ™ciem jej i wypisaniem ostrzeżenia.\n" "\n" #: .././db/sb.c:519 #, c-format msgid "%s: truncating label length from %d to %d\n" msgstr "%s: skrócono dÅ‚ugość etykiety z %d do %d\n" #: .././db/sb.c:561 #, c-format msgid "failed to set label in AG %d\n" msgstr "nie udaÅ‚o siÄ™ ustawić etykiety w AG %d\n" #: .././db/sb.c:564 #, c-format msgid "new label = \"%s\"\n" msgstr "nowa etykieta = \"%s\"\n" #: .././db/sb.c:571 #, c-format msgid "failed to read label in AG %d\n" msgstr "nie udaÅ‚o siÄ™ odczytać etykiety w AG %d\n" #: .././db/sb.c:577 #, c-format msgid "warning: AG %d label differs\n" msgstr "uwaga: etykieta w AG %d różni siÄ™\n" #: .././db/sb.c:579 #, c-format msgid "label = \"%s\"\n" msgstr "etykieta = \"%s\"\n" #: .././db/sb.c:589 msgid "" "\n" " set/print feature bits in sb version\n" "\n" " Example:\n" "\n" " 'version' - print current feature bits\n" " 'version extflg' - enable unwritten extents\n" " 'version attr1' - enable v1 inline extended attributes\n" " 'version attr2' - enable v2 inline extended attributes\n" " 'version log2' - enable v2 log format\n" "\n" "The version function prints currently enabled features for a filesystem\n" "according to the version field of its primary superblock.\n" "It can also be used to enable selected features, such as support for\n" "unwritten extents. The updated version is written into all AGs.\n" "\n" msgstr "" "\n" " ustawienie/wypisanie bitów cech w wersji superbloku\n" "\n" " PrzykÅ‚ad:\n" "\n" " 'version' - wypisanie bieżących bitów cech\n" " 'version extflg' - włączenie nie zapisanych ekstentów\n" " 'version attr1' - włączenie rozszerzonych atrybutów inline v1\n" " 'version attr2' - włączenie rozszerzonych atrybutów inline v2\n" " 'version log2' - włączenie formatu logu v2\n" "\n" "Funkcja 'version' wypisuje aktualnie włączone cechy dla systemu plików\n" "zgodnie z polem wersji w głównym superbloku.\n" "Może być używana także do włączania wybranych cech, takich jak obsÅ‚uga\n" "nie zapisanych ekstentów. Uaktualniona wersja jest zapisywana we wszystkich\n" "AG.\n" "\n" #: .././db/sb.c:617 msgid "Superblock has mismatched features2 fields, skipping modification\n" msgstr "Superblok ma niepasujÄ…ce pola features2, pominiÄ™to modyfikacjÄ™\n" #: .././db/sb.c:742 msgid "unwritten extents flag is already enabled\n" msgstr "flaga nie zapisanych ekstentów jest już włączona\n" #: .././db/sb.c:749 msgid "unwritten extents always enabled for v5 superblocks.\n" msgstr "nie zapisane ekstenty sÄ… zawsze włączone dla superbloków v5.\n" #: .././db/sb.c:766 msgid "version 2 log format is already in use\n" msgstr "format logu w wersji 2 jest już w użyciu\n" #: .././db/sb.c:773 msgid "Version 2 logs always enabled for v5 superblocks.\n" msgstr "Logi w wersji 2 sÄ… zawsze włączone dla superbloków v5.\n" #: .././db/sb.c:778 #, c-format msgid "%s: Cannot change %s on v5 superblocks.\n" msgstr "%s: Nie można zmienić %s przy superblokach v5.\n" #: .././db/sb.c:802 #, c-format msgid "%s: invalid version change command \"%s\"\n" msgstr "%s: błędne polecenie zmiany wersji \"%s\"\n" #: .././db/sb.c:811 #, c-format msgid "failed to set versionnum in AG %d\n" msgstr "nie udaÅ‚o siÄ™ ustawić versionnum w AG %d\n" #: .././db/sb.c:829 #, c-format msgid "versionnum [0x%x+0x%x] = %s\n" msgstr "versionnum [0x%x+0x%x] = %s\n" #: .././db/type.c:50 msgid "[newtype]" msgstr "[nowy-typ]" #: .././db/type.c:51 msgid "set/show current data type" msgstr "ustawienie/wyÅ›wietlenie bieżącego typu danych" #: .././db/type.c:211 #, c-format msgid "current type is \"%s\"\n" msgstr "bieżący typ to \"%s\"\n" #: .././db/type.c:213 msgid "" "\n" " supported types are:\n" " " msgstr "" "\n" " obsÅ‚ugiwane typy to:\n" " " #: .././db/type.c:230 #, c-format msgid "no such type %s\n" msgstr "nie ma typu %s\n" #: .././db/type.c:233 msgid "no current object\n" msgstr "brak bieżącego obiektu\n" #: .././db/type.c:286 msgid "string fuzzing not supported.\n" msgstr "zaburzanie Å‚aÅ„cuchów znaków nie jest obsÅ‚ugiwane.\n" #: .././db/type.c:306 msgid "use 'blocktrash' or 'write' to fuzz a block.\n" msgstr "do zaburzenia bloki można użyć polecenia 'blocktrash' lub 'write'.\n" #: .././db/type.c:322 msgid "text writing/fuzzing not supported.\n" msgstr "zapis/zaburzanie tekstu nie jest obsÅ‚ugiwane.\n" #: .././db/write.c:41 msgid "[-c] [field or value]..." msgstr "[-c] [pole lub wartość]..." #: .././db/write.c:42 msgid "write value to disk" msgstr "zapis wartoÅ›ci na dysk" #: .././db/write.c:58 msgid "" "\n" " The 'write' command takes on different personalities depending on the\n" " type of object being worked with.\n" "\n" " Write has 3 modes:\n" " 'struct mode' - is active anytime you're looking at a filesystem object\n" " which contains individual fields (ex: an inode).\n" " 'data mode' - is active anytime you set a disk address directly or set\n" " the type to 'data'.\n" " 'string mode' - only used for writing symlink blocks.\n" "\n" " Examples:\n" " Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n" " 'write fname \"hello\\000\"' - write superblock fname.\n" " (note: in struct mode strings are not null terminated)\n" " 'write fname #6669736800' - write superblock fname with " "hex.\n" " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n" " - write superblock uuid.\n" " Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n" " 'write lshift 3' - shift the block 3 bytes to the left\n" " 'write sequence 1 5' - write a cycle of number [1-5] through\n" " the entire block.\n" " String mode: 'write \"This_is_a_filename\" - write null terminated " "string.\n" "\n" " In data mode type 'write' by itself for a list of specific commands.\n" "\n" " Specifying the -c option will allow writes of invalid (corrupt) data with\n" " an invalid CRC. Specifying the -d option will allow writes of invalid " "data,\n" " but still recalculate the CRC so we are forced to check and detect the\n" " invalid data appropriately.\n" "\n" msgstr "" "\n" " Polecenie 'write' ma różne osobowoÅ›ci w zależnoÅ›ci od rodzaju obiektu,\n" " na jakim pracuje.\n" "\n" " Zapis ma trzy tryby:\n" " 'struct' (strukturalny) - aktywny w przypadku oglÄ…dania obiektu systemu\n" " plików zawierajÄ…cego poszczególne pola (np. i-wÄ™zeÅ‚).\n" " 'data' (danych) - aktywny w przypadku bezpoÅ›redniego ustawienia adresu\n" " na dysku lub ustawienia typu na 'data'.\n" " 'string' (znakowy) - używany tylko przy zapisie bloków dowiÄ…zaÅ„\n" " symbolicznych.\n" "\n" " PrzykÅ‚ady:\n" " Tryb strukturalny: 'write core.uid 23' - ustawienie pola uid i-wÄ™zÅ‚a na " "23\n" " 'write fname \"hello\\000\"' - zapis nazwy pliku sb\n" " (uwaga: w trybie strukturalnym Å‚aÅ„cuchy nie sÄ… " "zakaÅ„czane)\n" " 'write fname #6669736800' - zapis nazwy pliku sb w " "hex.\n" " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n" " - zapis UUID-a superbloku.\n" " Tryb danych: 'write fill 0xff' - wypeÅ‚nienie bloku bajtami 0xff\n" " 'write lshift 3' - przesuniÄ™cie bloku o 3 bajty w lewo\n" " 'write sequence 1 5' zapis cyklicznie liczb [1-5] " "przez\n" " caÅ‚y blok.\n" " Tryb znakowy: 'write \"To_jest_nazwa_pliku\" - zapis Å‚aÅ„cucha\n" " zakoÅ„czonego znakiem NUL.\n" "\n" " W trybie danych samo 'write' wypisze listÄ™ bardziej specyficznych poleceÅ„.\n" "\n" " Podanie opcji -c pozwala na zapis nieprawidÅ‚owych (uszkodzonych) danych,\n" " z błędnÄ… sumÄ… CRC. Podanie opcji -d pozwala na zapis błędnych danych, ale\n" " przeliczy CRC, co zmusza do sprawdzenia i odpowiedniego wykrycia\n" " nieprawidÅ‚owych danych.\n" "\n" #: .././db/write.c:104 #, c-format msgid "%s started in read only mode, writing disabled\n" msgstr "%s uruchomiono w trybie tylko do odczytu, zapis wyłączony\n" #: .././db/write.c:116 #, c-format msgid "no handler function for type %s, write unsupported.\n" msgstr "brak funkcji obsÅ‚ugujÄ…cej dla typu %s, zapis nie obsÅ‚ugiwany.\n" #: .././db/write.c:130 msgid "bad option for write command\n" msgstr "błędna opcja dla polecenia write\n" #: .././db/write.c:170 msgid "Allowing write of corrupted data and bad CRC\n" msgstr "Zezwolenie na zapis uszkodzonych danych i błędnej sumy CRC\n" #: .././db/write.c:173 .././db/write.c:176 msgid "Allowing write of corrupted data with good CRC\n" msgstr "Zezwolenie na zapis uszkodzonych danych z dobrÄ… sumÄ… CRC\n" #: .././db/write.c:232 .././db/write.c:261 .././db/write.c:291 #: .././db/write.c:324 .././db/write.c:360 .././db/write.c:409 #: .././db/write.c:438 #, c-format msgid "length (%d) too large for data block size (%d)" msgstr "dÅ‚ugość (%d) zbyt duża dla rozmiaru bloku danych (%d)" #: .././db/write.c:680 msgid "usage: write fieldname value\n" msgstr "skÅ‚adnia: write nazwa-pola wartość\n" #: .././db/write.c:735 #, c-format msgid "unable to convert value '%s'.\n" msgstr "nie można przekonwertować wartoÅ›ci '%s'.\n" #: .././db/write.c:759 msgid "usage (in string mode): write \"string...\"\n" msgstr "skÅ‚adnia (w trybie znakowym): write \"Å‚aÅ„cuch...\"\n" #: .././db/write.c:801 msgid "write: invalid subcommand\n" msgstr "write: błędne podpolecenie\n" #: .././db/write.c:806 #, c-format msgid "write %s: invalid number of arguments\n" msgstr "write %s: błędna liczba argumentów\n" #: .././db/write.c:830 msgid "usage: write (in data mode)\n" msgstr "skÅ‚adnia: write (w trybie danych)\n" #: .././estimate/xfs_estimate.c:78 #, c-format msgid "" "Usage: %s [opts] directory [directory ...]\n" "\t-b blocksize (fundamental filesystem blocksize)\n" "\t-i logsize (internal log size)\n" "\t-e logsize (external log size)\n" "\t-v prints more verbose messages\n" "\t-V prints version and exits\n" "\t-h prints this usage message\n" "\n" "Note:\tblocksize may have 'k' appended to indicate x1024\n" "\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n" msgstr "" "SkÅ‚adnia: %s [opcje] katalog [katalog ...]\n" "\t-b rozmiar_bloku (rozmiar bloku zasadniczego systemu plików)\n" "\t-i rozmiar_logu (rozmiar logu wewnÄ™trznego)\n" "\t-e rozmiar_logu (rozmiar logu zewnÄ™trznego)\n" "\t-v wypisywanie bardziej szczegółowych komunikatów\n" "\t-V wypisanie informacji o wersji i zakoÅ„czenie\n" "\t-h wypisanie tej informacji o sposobie użycia\n" "\n" #: .././estimate/xfs_estimate.c:109 #, c-format msgid "blocksize %llu too small\n" msgstr "rozmiar bloku %llu jest zbyt maÅ‚y\n" #: .././estimate/xfs_estimate.c:114 #, c-format msgid "blocksize %llu too large\n" msgstr "rozmiar bloku %llu jest zbyt duży\n" #: .././estimate/xfs_estimate.c:121 #, c-format msgid "already have external log noted, can't have both\n" msgstr "już jest przypisany zewnÄ™trzny log, nie mogÄ… istnieć oba\n" #: .././estimate/xfs_estimate.c:130 #, c-format msgid "already have internal log noted, can't have both\n" msgstr "już jest przypisany wewnÄ™trzny log, nie mogÄ… istnieć oba\n" #: .././estimate/xfs_estimate.c:160 #, c-format msgid "" "directory bsize blocks megabytes " "logsize\n" msgstr "" "katalog rozmb bloków megabajtów rozm." "logu\n" #: .././estimate/xfs_estimate.c:174 #, c-format msgid "dirsize=%llu\n" msgstr "dirsize=%llu\n" #: .././estimate/xfs_estimate.c:175 #, c-format msgid "fullblocks=%llu\n" msgstr "fullblocks=%llu\n" #: .././estimate/xfs_estimate.c:176 #, c-format msgid "isize=%llu\n" msgstr "isize=%llu\n" #: .././estimate/xfs_estimate.c:178 #, c-format msgid "%llu regular files\n" msgstr "%llu plików zwykÅ‚ych\n" #: .././estimate/xfs_estimate.c:179 #, c-format msgid "%llu symbolic links\n" msgstr "%llu dowiÄ…zaÅ„ symbolicznych\n" #: .././estimate/xfs_estimate.c:180 #, c-format msgid "%llu directories\n" msgstr "%llu katalogów\n" #: .././estimate/xfs_estimate.c:181 #, c-format msgid "%llu special files\n" msgstr "%llu plików specjalnych\n" #: .././estimate/xfs_estimate.c:194 #, c-format msgid "%s will take about %.1f megabytes\n" msgstr "%s zajmie okoÅ‚o %.1f megabajtów\n" #: .././estimate/xfs_estimate.c:201 #, c-format msgid "%-39s %5llu %8llu %10.1fMB %10llu\n" msgstr "%-39s %5llu %8llu %10.1fMB %10llu\n" #: .././estimate/xfs_estimate.c:207 #, c-format msgid "\twith the external log using %llu blocks " msgstr "\tz zewnÄ™trznym logiem zajmujÄ…cym %llu bloków " #: .././estimate/xfs_estimate.c:209 #, c-format msgid "or about %.1f megabytes\n" msgstr "lub okoÅ‚o %.1f megabajtów\n" #: .././fsr/xfs_fsr.c:268 #, c-format msgid "%s: Stats not yet supported for XFS\n" msgstr "%s: statystyki nie sÄ… jeszcze obsÅ‚ugiwane dla XFS-a\n" #: .././fsr/xfs_fsr.c:332 .././scrub/xfs_scrub.c:653 #, c-format msgid "%s: could not stat: %s: %s\n" msgstr "%s: nie można wykonać stat: %s: %s\n" #: .././fsr/xfs_fsr.c:351 #, c-format msgid "%s: char special not supported: %s\n" msgstr "%s: urzÄ…dzenia znakowe nie sÄ… obsÅ‚ugiwane: %s\n" #: .././fsr/xfs_fsr.c:357 #, c-format msgid "%s: cannot defragment: %s: Not XFS\n" msgstr "%s: nie można zdefragmentować: %s: to nie jest XFS\n" #: .././fsr/xfs_fsr.c:367 #, c-format msgid "%s: not fsys dev, dir, or reg file, ignoring\n" msgstr "" "%s: nie jest urzÄ…dzeniem z systemem plików, katalogiem ani zwykÅ‚ym plikiem, " "zignorowano\n" #: .././fsr/xfs_fsr.c:382 #, c-format msgid "" "Usage: %s [-d] [-v] [-g] [-t time] [-p passes] [-f leftf] [-m mtab]\n" " %s [-d] [-v] [-g] xfsdev | dir | file ...\n" " %s -V\n" "\n" "Options:\n" " -g Print to syslog (default if stdout not a tty).\n" " -t time How long to run in seconds.\n" " -p passes Number of passes before terminating global re-org.\n" " -f leftoff Use this instead of %s.\n" " -m mtab Use something other than /etc/mtab.\n" " -d Debug, print even more.\n" " -v Verbose, more -v's more verbose.\n" " -V Print version number and exit.\n" msgstr "" "SkÅ‚adnia: %s [-d] [-v] [-g] [-t czas] [-p przebiegi] [-f leftf] [-m mtab]\n" " %s [-d] [-v] [-g] xfsdev | katalog | plik ...\n" " %s -V\n" "\n" "Opcje:\n" " -g Pisanie do sysloga (domyÅ›lne jeÅ›li stdout to nie " "tty).\n" " -t czas Czas dziaÅ‚ania w sekundach.\n" " -p przebiegi Liczba przebiegów przed zakoÅ„czeniem reorganizacji.\n" " -f leftoff Użycie tego pliku zamiast %s.\n" " -m mtab Użycie pliku innego niż /etc/mtab.\n" " -d Diagnostyka, dużo wiÄ™cej informacji.\n" " -v Tym wiÄ™cej szczegółów, im wiÄ™cej opcji -v.\n" " -V Wypisanie informacji o wersji i zakoÅ„czenie.\n" #: .././fsr/xfs_fsr.c:412 .././fsr/xfs_fsr.c:450 #, c-format msgid "out of memory: %s\n" msgstr "brak pamiÄ™ci: %s\n" #: .././fsr/xfs_fsr.c:441 #, c-format msgid "Skipping %s: not mounted rw\n" msgstr "PominiÄ™to %s: nie zamontowany rw\n" #: .././fsr/xfs_fsr.c:455 #, c-format msgid "out of memory on realloc: %s\n" msgstr "brak pamiÄ™ci przy realloc: %s\n" #: .././fsr/xfs_fsr.c:466 .././fsr/xfs_fsr.c:470 #, c-format msgid "strdup(%s) failed\n" msgstr "strdup(%s) nie powiodÅ‚o siÄ™\n" #: .././fsr/xfs_fsr.c:481 #, c-format msgid "no rw xfs file systems in mtab: %s\n" msgstr "brak w pliku mtab systemów plików xfs w trybie rw: %s\n" #: .././fsr/xfs_fsr.c:485 #, c-format msgid "Found %d mounted, writable, XFS filesystems\n" msgstr "" "Liczba znalezionych zamontowanych, zapisywalnych systemów plików XFS: %d\n" #: .././fsr/xfs_fsr.c:515 #, c-format msgid "%s: open failed\n" msgstr "%s: open nie powiodÅ‚o siÄ™\n" #: .././fsr/xfs_fsr.c:530 #, c-format msgid "Can't use %s: mode=0%o own=%d nlink=%d\n" msgstr "Nie można użyć %s: mode=0%o own=%d nlink=%d\n" #: .././fsr/xfs_fsr.c:550 #, c-format msgid "could not read %s, starting with %s\n" msgstr "nie można odczytać %s, rozpoczÄ™cie z %s\n" #: .././fsr/xfs_fsr.c:589 #, c-format msgid "START: pass=%d ino=%llu %s %s\n" msgstr "START: przebieg=%d i-wÄ™zeÅ‚=%llu %s %s\n" #: .././fsr/xfs_fsr.c:611 msgid "couldn't fork sub process:" msgstr "nie udaÅ‚o siÄ™ uruchomić podprocesu:" #: .././fsr/xfs_fsr.c:632 #, c-format msgid "Completed all %d passes\n" msgstr "ZakoÅ„czono wszystkie przebiegi w liczbie %d\n" #: .././fsr/xfs_fsr.c:652 #, c-format msgid "%s startpass %d, endpass %d, time %d seconds\n" msgstr "%s pocz. przebieg %d, koÅ„c. przebieg %d, czas %d sekund\n" #: .././fsr/xfs_fsr.c:659 #, c-format msgid "open(%s) failed: %s\n" msgstr "open(%s) nie powiodÅ‚o siÄ™: %s\n" #: .././fsr/xfs_fsr.c:665 #, c-format msgid "write(%s) failed: %s\n" msgstr "write(%s) nie powiodÅ‚o siÄ™: %s\n" #: .././fsr/xfs_fsr.c:689 #, c-format msgid "%s start inode=%llu\n" msgstr "%s pocz. i-wÄ™zeÅ‚=%llu\n" #: .././fsr/xfs_fsr.c:694 #, c-format msgid "unable to get handle: %s: %s\n" msgstr "nie udaÅ‚o siÄ™ uzyskać uchwytu: %s: %s\n" #: .././fsr/xfs_fsr.c:700 #, c-format msgid "unable to open: %s: %s\n" msgstr "nie udaÅ‚o siÄ™ otworzyć: %s: %s\n" #: .././fsr/xfs_fsr.c:707 #, c-format msgid "Skipping %s: could not get XFS geometry\n" msgstr "PominiÄ™to %s: nie można odczytać geometrii XFS\n" #: .././fsr/xfs_fsr.c:742 #, c-format msgid "could not open: inode %llu\n" msgstr "nie udaÅ‚o siÄ™ otworzyć: i-wÄ™zeÅ‚ %llu\n" #: .././fsr/xfs_fsr.c:772 #, c-format msgid "%s: xfs_bulkstat: %s\n" msgstr "%s: xfs_bulkstat: %s\n" #: .././fsr/xfs_fsr.c:799 #, c-format msgid "%s: Directory defragmentation not supported\n" msgstr "%s: Defragmentacja katalogów nie jest obsÅ‚ugiwana\n" #: .././fsr/xfs_fsr.c:818 #, c-format msgid "unable to construct sys handle for %s: %s\n" msgstr "nie udaÅ‚o siÄ™ utworzyć uchwytu systemowego dla %s: %s\n" #: .././fsr/xfs_fsr.c:829 #, c-format msgid "unable to open sys handle for %s: %s\n" msgstr "nie udaÅ‚o siÄ™ otworzyć uchwytu systemowego dla %s: %s\n" #: .././fsr/xfs_fsr.c:835 #, c-format msgid "unable to get bstat on %s: %s\n" msgstr "nie udaÅ‚o siÄ™ uzyskać bstat na %s: %s\n" #: .././fsr/xfs_fsr.c:842 #, c-format msgid "unable to open handle %s: %s\n" msgstr "nie udaÅ‚o siÄ™ otworzyć uchwytu %s: %s\n" #: .././fsr/xfs_fsr.c:849 #, c-format msgid "Unable to get geom on fs for: %s\n" msgstr "Nie udaÅ‚o siÄ™ odczytać geometrii systemu plików dla: %s\n" #: .././fsr/xfs_fsr.c:900 #, c-format msgid "sync failed: %s: %s\n" msgstr "sync nie powiodÅ‚o siÄ™: %s: %s\n" #: .././fsr/xfs_fsr.c:906 #, c-format msgid "%s: zero size, ignoring\n" msgstr "%s: zerowy rozmiar, zignorowano\n" #: .././fsr/xfs_fsr.c:925 #, c-format msgid "locking check failed: %s\n" msgstr "sprawdzenie blokowania nie powiodÅ‚o siÄ™: %s\n" #: .././fsr/xfs_fsr.c:932 #, c-format msgid "mandatory lock: %s: ignoring\n" msgstr "obowiÄ…zkowa blokada: %s: zignorowano\n" #: .././fsr/xfs_fsr.c:945 #, c-format msgid "unable to get fs stat on %s: %s\n" msgstr "nie udaÅ‚o siÄ™ uzyskać stat fs na %s: %s\n" #: .././fsr/xfs_fsr.c:952 #, c-format msgid "insufficient freespace for: %s: size=%lld: ignoring\n" msgstr "niewystarczajÄ…ca ilość miejsca dla: %s: rozmiar=%lld: zignorowano\n" #: .././fsr/xfs_fsr.c:959 #, c-format msgid "failed to get inode attrs: %s\n" msgstr "nie udaÅ‚o siÄ™ uzyskać atrybutów i-wÄ™zÅ‚a: %s\n" #: .././fsr/xfs_fsr.c:964 #, c-format msgid "%s: immutable/append, ignoring\n" msgstr "%s: niezmienny/tylko do dołączania, zignorowano\n" #: .././fsr/xfs_fsr.c:969 #, c-format msgid "%s: marked as don't defrag, ignoring\n" msgstr "%s: oznaczony jako nie do defragmentacji, zignorowano\n" #: .././fsr/xfs_fsr.c:975 #, c-format msgid "cannot get realtime geometry for: %s\n" msgstr "nie można uzyskać geometrii realtime dla: %s\n" #: .././fsr/xfs_fsr.c:980 #, c-format msgid "low on realtime free space: %s: ignoring file\n" msgstr "maÅ‚o wolnego miejsca realtime: %s: plik zignorowany\n" #: .././fsr/xfs_fsr.c:987 #, c-format msgid "cannot open: %s: Permission denied\n" msgstr "nie można otworzyć: %s: brak uprawnieÅ„\n" #: .././fsr/xfs_fsr.c:1046 .././fsr/xfs_fsr.c:1096 .././fsr/xfs_fsr.c:1176 msgid "could not set ATTR\n" msgstr "nie udaÅ‚o siÄ™ ustawić ATTR\n" #: .././fsr/xfs_fsr.c:1055 #, c-format msgid "unable to stat temp file: %s\n" msgstr "nie udaÅ‚o siÄ™ wykonać stat na pliku tymczasowym: %s\n" #: .././fsr/xfs_fsr.c:1073 #, c-format msgid "unable to get bstat on temp file: %s\n" msgstr "nie udaÅ‚o siÄ™ uzyskać bstat pliku tymczasowego: %s\n" #: .././fsr/xfs_fsr.c:1078 #, c-format msgid "orig forkoff %d, temp forkoff %d\n" msgstr "orig forkoff %d, temp forkoff %d\n" #: .././fsr/xfs_fsr.c:1131 msgid "big ATTR set failed\n" msgstr "duży zbiór ATTR nie powiódÅ‚ siÄ™\n" #: .././fsr/xfs_fsr.c:1152 #, c-format msgid "forkoff diff %d too large!\n" msgstr "różnica forkoff %d zbyt duża!\n" #: .././fsr/xfs_fsr.c:1169 #, c-format msgid "data fork growth unimplemented\n" msgstr "powiÄ™kszanie gałęzi danych nie jest zaimplementowane\n" #: .././fsr/xfs_fsr.c:1184 msgid "set temp attr\n" msgstr "ustawianie atrybutów pliku tymczasowego\n" #: .././fsr/xfs_fsr.c:1187 msgid "failed to match fork offset\n" msgstr "nie udaÅ‚o siÄ™ dopasować offsetu gałęzi\n" #: .././fsr/xfs_fsr.c:1234 #, c-format msgid "%s already fully defragmented.\n" msgstr "%s jest już caÅ‚kowicie zdefragmentowany.\n" #: .././fsr/xfs_fsr.c:1240 #, c-format msgid "%s extents=%d can_save=%d tmp=%s\n" msgstr "%s extents=%d can_save=%d tmp=%s\n" #: .././fsr/xfs_fsr.c:1246 #, c-format msgid "could not open tmp file: %s: %s\n" msgstr "nie udaÅ‚o siÄ™ otworzyć pliku tymczasowego: %s: %s\n" #: .././fsr/xfs_fsr.c:1254 #, c-format msgid "failed to set ATTR fork on tmp: %s:\n" msgstr "nie udaÅ‚o siÄ™ ustawić gałęzi ATTR na tmp: %s\n" #: .././fsr/xfs_fsr.c:1261 #, c-format msgid "could not set inode attrs on tmp: %s\n" msgstr "nie udaÅ‚o siÄ™ ustawić atrybutów i-wÄ™zÅ‚a na tmp: %s\n" #: .././fsr/xfs_fsr.c:1268 #, c-format msgid "could not get DirectIO info on tmp: %s\n" msgstr "nie udaÅ‚o siÄ™ uzyskać informacji o bezpoÅ›rednim we/wy na tmp: %s\n" #: .././fsr/xfs_fsr.c:1283 #, c-format msgid "DEBUG: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n" msgstr "DEBUG: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n" #: .././fsr/xfs_fsr.c:1290 #, c-format msgid "could not allocate buf: %s\n" msgstr "nie udaÅ‚o siÄ™ przydzielić bufora: %s\n" #: .././fsr/xfs_fsr.c:1300 #, c-format msgid "could not open fragfile: %s : %s\n" msgstr "nie udaÅ‚o siÄ™ otworzyć pliku frag: %s: %s\n" #: .././fsr/xfs_fsr.c:1315 #, c-format msgid "could not trunc tmp %s\n" msgstr "nie udaÅ‚o siÄ™ uciąć tmp %s\n" #: .././fsr/xfs_fsr.c:1319 .././fsr/xfs_fsr.c:1339 .././fsr/xfs_fsr.c:1367 #, c-format msgid "could not lseek in tmpfile: %s : %s\n" msgstr "nie udaÅ‚o siÄ™ przemieÅ›cić (lseek) w pliku tymczasowym: %s: %s\n" #: .././fsr/xfs_fsr.c:1334 #, c-format msgid "could not pre-allocate tmp space: %s\n" msgstr "nie udaÅ‚o siÄ™ wstÄ™pnie przydzielić miejsca tmp: %s\n" #: .././fsr/xfs_fsr.c:1347 msgid "Couldn't rewind on temporary file\n" msgstr "Nie udaÅ‚o siÄ™ przewinąć pliku tymczasowego\n" #: .././fsr/xfs_fsr.c:1354 #, c-format msgid "Temporary file has %d extents (%d in original)\n" msgstr "Plik tymczasowy ma ekstentów: %d (%d w oryginale)\n" #: .././fsr/xfs_fsr.c:1357 #, c-format msgid "No improvement will be made (skipping): %s\n" msgstr "Nie nastÄ…pi poprawa (pominiÄ™to): %s\n" #: .././fsr/xfs_fsr.c:1372 #, c-format msgid "could not lseek in file: %s : %s\n" msgstr "nie udaÅ‚o siÄ™ przemieÅ›cić (lseek) w pliku: %s: %s\n" #: .././fsr/xfs_fsr.c:1408 #, c-format msgid "bad read of %d bytes from %s: %s\n" msgstr "błędny odczyt %d bajtów z %s: %s\n" #: .././fsr/xfs_fsr.c:1412 .././fsr/xfs_fsr.c:1444 #, c-format msgid "bad write of %d bytes to %s: %s\n" msgstr "błędny zapis %d bajtów do %s: %s\n" #: .././fsr/xfs_fsr.c:1429 #, c-format msgid "bad write2 of %d bytes to %s: %s\n" msgstr "błędny zapis 2 %d bajtów do %s: %s\n" #: .././fsr/xfs_fsr.c:1434 #, c-format msgid "bad copy to %s\n" msgstr "błędna kopia do %s\n" #: .././fsr/xfs_fsr.c:1452 #, c-format msgid "could not truncate tmpfile: %s : %s\n" msgstr "nie udaÅ‚o siÄ™ obciąć pliku tymczasowego: %s: %s\n" #: .././fsr/xfs_fsr.c:1457 #, c-format msgid "could not fsync tmpfile: %s : %s\n" msgstr "nie udaÅ‚o siÄ™ wykonać fsync pliku tymczasowego: %s: %s\n" #: .././fsr/xfs_fsr.c:1472 #, c-format msgid "failed to fchown tmpfile %s: %s\n" msgstr "nie udaÅ‚o siÄ™ wykonać fchown na pliku tymczasowym %s: %s\n" #: .././fsr/xfs_fsr.c:1482 #, c-format msgid "%s: file type not supported\n" msgstr "%s: typ pliku nie obsÅ‚ugiwany\n" #: .././fsr/xfs_fsr.c:1486 #, c-format msgid "%s: file modified defrag aborted\n" msgstr "%s: plik zmodyfikowany, defragmentacja przerwana\n" #: .././fsr/xfs_fsr.c:1491 #, c-format msgid "%s: file busy\n" msgstr "%s: plik zajÄ™ty\n" #: .././fsr/xfs_fsr.c:1493 #, c-format msgid "XFS_IOC_SWAPEXT failed: %s: %s\n" msgstr "XFS_IOC_SWAPEXT nie powiodÅ‚o siÄ™: %s: %s\n" #: .././fsr/xfs_fsr.c:1501 #, c-format msgid "extents before:%d after:%d %s %s\n" msgstr "ekstentów przed: %d po: %d %s %s\n" #: .././fsr/xfs_fsr.c:1535 #, c-format msgid "tmp file name too long: %s\n" msgstr "nazwa pliku tymczasowego zbyt dÅ‚uga: %s\n" #: .././fsr/xfs_fsr.c:1585 #, c-format msgid "realloc failed: %s\n" msgstr "realloc nie powiodÅ‚o siÄ™: %s\n" #: .././fsr/xfs_fsr.c:1598 #, c-format msgid "malloc failed: %s\n" msgstr "malloc nie powiodÅ‚o siÄ™: %s\n" #: .././fsr/xfs_fsr.c:1628 #, c-format msgid "failed reading extents: inode %llu" msgstr "nie udaÅ‚o siÄ™ odczytać ekstentów: i-wÄ™zeÅ‚ %llu" #: .././fsr/xfs_fsr.c:1678 msgid "failed reading extents" msgstr "nie udaÅ‚o siÄ™ odczytać ekstentów" #: .././fsr/xfs_fsr.c:1766 .././fsr/xfs_fsr.c:1780 #, c-format msgid "tmpdir already exists: %s\n" msgstr "katalog tymczasowy już istnieje: %s\n" #: .././fsr/xfs_fsr.c:1769 #, c-format msgid "could not create tmpdir: %s: %s\n" msgstr "nie udaÅ‚o siÄ™ utworzyć katalogu tymczasowego: %s: %s\n" #: .././fsr/xfs_fsr.c:1782 #, c-format msgid "cannot create tmpdir: %s: %s\n" msgstr "nie można utworzyć katalogu tymczasowego: %s: %s\n" #: .././fsr/xfs_fsr.c:1820 .././fsr/xfs_fsr.c:1828 #, c-format msgid "could not remove tmpdir: %s: %s\n" msgstr "nie udaÅ‚o siÄ™ usunąć katalogu tymczasowego: %s: %s\n" #: .././growfs/xfs_growfs.c:26 #, c-format msgid "" "Usage: %s [options] mountpoint\n" "\n" "Options:\n" "\t-d grow data/metadata section\n" "\t-l grow log section\n" "\t-r grow realtime section\n" "\t-n don't change anything, just show geometry\n" "\t-i convert log from external to internal format\n" "\t-t alternate location for mount table (/etc/mtab)\n" "\t-x convert log from internal to external format\n" "\t-D size grow data/metadata section to size blks\n" "\t-L size grow/shrink log section to size blks\n" "\t-R size grow realtime section to size blks\n" "\t-e size set realtime extent size to size blks\n" "\t-m imaxpct set inode max percent to imaxpct\n" "\t-V print version information\n" msgstr "" "SkÅ‚adnia: %s [opcje] punkt_montowania\n" "\n" "Opcje:\n" "\t-d powiÄ™kszenie sekcji danych/metadanych\n" "\t-l powiÄ™kszenie sekcji logu\n" "\t-r powiÄ™kszenie sekcji realtime\n" "\t-n bez zmian, tylko pokazanie geometrii\n" "\t-i przeksztaÅ‚cenie logu z formatu zewnÄ™trznego na wewnÄ™trzny\n" "\t-t inne poÅ‚ożenie tabeli montowaÅ„ (/etc/mtab)\n" "\t-x przeksztaÅ‚cenie logu z formatu wewnÄ™trznego na zewnÄ™trzny\n" "\t-D rozmiar powiÄ™kszenie sekcji danych/metadanych do rozmiaru w blokach\n" "\t-L rozmiar powiÄ™kszenie/zmniejszenie sekcji logu do rozmiaru w blokach\n" "\t-R rozmiar powiÄ™kszenie sekcji realtime do rozmiaru w blokach\n" "\t-e rozmiar stawienie rozmiaru ekstentu realtime na rozmiar w blokach\n" "\t-m imaxpct ustawienie maksymalnego procentu i-wÄ™złów na imaxpct\n" "\t-V wypisanie informacji o wersji\n" #: .././growfs/xfs_growfs.c:66 #, c-format msgid "" "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u spinodes=%u rmapbt=%u\n" " =%-22s reflink=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n" "log =%-22s bsize=%-6u blocks=%u, version=%u\n" " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n" "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n" msgstr "" "metadane=%-22s isize=%-6u agcount=%u, agsize=%u bloków\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u spinodes=%u rmapbt=%u\n" " =%-22s reflink=%u\n" "dane =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u bloków\n" "nazwy =wersja %-14u bsize=%-6u ascii-ci=%d ftype=%d\n" "log =%-22s bsize=%-6u blocks=%u, wersja=%u\n" " =%-22s sectsz=%-5u sunit=%u bloków, lazy-count=%u\n" "realtime=%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n" #: .././growfs/xfs_growfs.c:85 .././growfs/xfs_growfs.c:474 #: .././growfs/xfs_growfs.c:475 msgid "internal" msgstr "wewnÄ™trzny" #: .././growfs/xfs_growfs.c:85 .././growfs/xfs_growfs.c:88 #: .././growfs/xfs_growfs.c:474 .././growfs/xfs_growfs.c:475 msgid "external" msgstr "zewnÄ™trzny" #: .././growfs/xfs_growfs.c:208 #, c-format msgid "%s: path resolution failed for %s: %s\n" msgstr "%s: nie udaÅ‚o siÄ™ rozwiÄ…zać Å›cieżki dla %s: %s\n" #: .././growfs/xfs_growfs.c:215 #, c-format msgid "%s: %s is not a mounted XFS filesystem\n" msgstr "%s: %s nie jest zamontowanym systemem plików XFS\n" #: .././growfs/xfs_growfs.c:232 #, c-format msgid "%s: specified file [\"%s\"] is not on an XFS filesystem\n" msgstr "%s: podany plik [\"%s\"] nie jest na systemie plików XFS\n" #: .././growfs/xfs_growfs.c:249 #, c-format msgid "%s: cannot determine geometry of filesystem mounted at %s: %s\n" msgstr "" "%s: nie można okreÅ›lić geometrii systemu plików zamontowanego pod %s: %s\n" #: .././growfs/xfs_growfs.c:293 #, c-format msgid "%s: failed to access data device for %s\n" msgstr "%s: nie udaÅ‚o siÄ™ uzyskać dostÄ™pu do urzÄ…dzenia z danymi dla %s\n" #: .././growfs/xfs_growfs.c:298 #, c-format msgid "%s: failed to access external log for %s\n" msgstr "%s: nie udaÅ‚o siÄ™ uzyskać dostÄ™pu do zewnÄ™trznego logu dla %s\n" #: .././growfs/xfs_growfs.c:304 #, c-format msgid "%s: failed to access realtime device for %s\n" msgstr "%s: nie udaÅ‚o siÄ™ uzyskać dostÄ™pu do urzÄ…dzenia realtime dla %s\n" #: .././growfs/xfs_growfs.c:344 #, c-format msgid "data size %lld too large, maximum is %lld\n" msgstr "rozmiar danych %lld zbyt duży, maksymalny to %lld\n" #: .././growfs/xfs_growfs.c:351 #, c-format msgid "data size %lld too small, old size is %lld\n" msgstr "rozmiar danych %lld zbyt maÅ‚y, stary rozmiar to %lld\n" #: .././growfs/xfs_growfs.c:359 #, c-format msgid "data size unchanged, skipping\n" msgstr "rozmiar danych nie zmieniony, pominiÄ™to\n" #: .././growfs/xfs_growfs.c:362 #, c-format msgid "inode max pct unchanged, skipping\n" msgstr "maksymalny procent i-wÄ™złów nie zmieniony, pominiÄ™to\n" #: .././growfs/xfs_growfs.c:369 .././growfs/xfs_growfs.c:408 #: .././growfs/xfs_growfs.c:443 #, c-format msgid "%s: growfs operation in progress already\n" msgstr "%s: operacja growfs już trwa\n" #: .././growfs/xfs_growfs.c:373 #, c-format msgid "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n" msgstr "%s: xfsctl XFS_IOC_FSGROWFSDATA nie powiodÅ‚o siÄ™: %s\n" #: .././growfs/xfs_growfs.c:389 #, c-format msgid "realtime size %lld too large, maximum is %lld\n" msgstr "rozmiar realtime %lld zbyt duży, maksymalny to %lld\n" #: .././growfs/xfs_growfs.c:395 #, c-format msgid "realtime size %lld too small, old size is %lld\n" msgstr "rozmiar realtime %lld zbyt maÅ‚y, stary rozmiar to %lld\n" #: .././growfs/xfs_growfs.c:401 #, c-format msgid "realtime size unchanged, skipping\n" msgstr "rozmiar realtime nie zmieniony, pominiÄ™to\n" #: .././growfs/xfs_growfs.c:412 #, c-format msgid "%s: realtime growth not implemented\n" msgstr "%s: powiÄ™kszanie realtime nie jest zaimplementowane\n" #: .././growfs/xfs_growfs.c:416 #, c-format msgid "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n" msgstr "%s: xfsctl XFS_IOC_FSGROWFSRT nie powiodÅ‚o siÄ™: %s\n" #: .././growfs/xfs_growfs.c:437 #, c-format msgid "log size unchanged, skipping\n" msgstr "rozmiar logu nie zmieniony, pominiÄ™to\n" #: .././growfs/xfs_growfs.c:447 #, c-format msgid "%s: log growth not supported yet\n" msgstr "%s: powiÄ™kszanie logu nie jest jeszcze obsÅ‚ugiwane\n" #: .././growfs/xfs_growfs.c:451 #, c-format msgid "%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n" msgstr "%s: xfsctl XFS_IOC_FSGROWFSLOG nie powiodÅ‚o siÄ™: %s\n" #: .././growfs/xfs_growfs.c:459 #, c-format msgid "%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n" msgstr "%s: xfsctl XFS_IOC_FSGEOMETRY nie powiodÅ‚o siÄ™: %s\n" #: .././growfs/xfs_growfs.c:464 #, c-format msgid "data blocks changed from %lld to %lld\n" msgstr "bloki danych zmienione z %lld na %lld\n" #: .././growfs/xfs_growfs.c:467 #, c-format msgid "inode max percent changed from %d to %d\n" msgstr "maksymalny procent i-wÄ™złów zmieniony z %d na %d\n" #: .././growfs/xfs_growfs.c:470 #, c-format msgid "log blocks changed from %d to %d\n" msgstr "bloki logu zmienione z %d na %d\n" #: .././growfs/xfs_growfs.c:473 #, c-format msgid "log changed from %s to %s\n" msgstr "log zmieniony - byÅ‚ %s, jest %s\n" #: .././growfs/xfs_growfs.c:477 #, c-format msgid "realtime blocks changed from %lld to %lld\n" msgstr "bloki realtime zmienione z %lld na %lld\n" #: .././growfs/xfs_growfs.c:480 #, c-format msgid "realtime extent size changed from %d to %d\n" msgstr "rozmiar ekstentu realtime zmieniony z %d na %d\n" #: .././io/attr.c:60 #, c-format msgid "" "\n" " displays the set of extended inode flags associated with the current file\n" "\n" " Each individual flag is displayed as a single character, in this order:\n" " r -- file data is stored in the realtime section\n" " p -- file has preallocated extents (cannot be changed using chattr)\n" " i -- immutable, file cannot be modified\n" " a -- append-only, file can only be appended to\n" " s -- all updates are synchronous\n" " A -- the access time is not updated for this inode\n" " d -- do not include this file in a dump of the filesystem\n" " t -- child created in this directory has realtime bit set by default\n" " P -- child created in this directory has parents project ID by default\n" " n -- symbolic links cannot be created in this directory\n" " e -- for non-realtime files, observe the inode extent size value\n" " E -- children created in this directory inherit the extent size value\n" " f -- do not include this file when defragmenting the filesystem\n" " S -- enable filestreams allocator for this directory\n" " x -- Use direct access (DAX) for data in this file\n" " C -- for files with shared blocks, observe the inode CoW extent size value\n" "\n" " Options:\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, but only list attributes on directories\n" " -a -- show all flags which can be set alongside those which are set\n" " -v -- verbose mode; show long names of flags, not single characters\n" "\n" msgstr "" "\n" " wyÅ›wietlenie zbioru rozszerzonych flag i-wÄ™złów zwiÄ…zanych z bieżącym " "plikiem\n" "\n" " Każda flaga jest wyÅ›wietlana jako pojedynczy znak, w tej kolejnoÅ›ci:\n" " r - dane pliku sÄ… zapisane w sekcji realtime\n" " p - plik ma już przydzielone ekstenty (nie do zmiany przez chattr)\n" " i - niezmienny, pliku nie można modyfikować\n" " a - tylko do dopisywania, do pliku można tylko dopisywać\n" " s - wszystkie uaktualnienia sÄ… synchroniczne\n" " A - czas dostÄ™pu nie jest uaktualniany dla tego i-wÄ™zÅ‚a\n" " d - niedołączanie pliku do zrzutu systemu plików\n" " t - wpisy tworzone w tym katalogu majÄ… domyÅ›lnie ustawiony bit realtime\n" " P - wpisy tworzone w tym katalogu majÄ… domyÅ›lnie ID projektu rodzica\n" " n - w tym katalogu nie można tworzyć dowiÄ…zaÅ„ symbolicznych\n" " e - dla plików nie-realtime - przestrzeganie wartoÅ›ci rozmiaru ekstentu i-" "wÄ™zÅ‚a\n" " E - wpisy tworzone w tym katalogu dziedziczÄ… wartość rozmiaru ekstentu\n" " f - nieuwzglÄ™dnianie tego pliku przy defragmentacji systemu plików\n" " S - włączenie przydzielania strumieni plikowych dla tego katalogu\n" " x - użycie bezpoÅ›redniego dostÄ™pu (DAX) dla danych w tym pliku\n" " C - dla plików z blokami współdzielonymi: obserw. rozm. ekstentu CoW i-" "wÄ™zÅ‚a\n" "\n" " Opcje:\n" " -R - rekurencyjne zagłębianie siÄ™ (przydatne kiedy bieżący plik jest " "katalogiem)\n" " -D - rekurencyjne zagłębianie siÄ™, ale wypisywanie atrybutów tylko " "katalogów\n" " -a - pokazywanie wszystkich flag, które można ustawić, obok ustawionych\n" " -v - tryb szczegółowy; pokazywanie dÅ‚ugich nazw flag zamiast pojedynczych " "znaków\n" "\n" #: .././io/attr.c:93 #, c-format msgid "" "\n" " modifies the set of extended inode flags associated with the current file\n" "\n" " Examples:\n" " 'chattr +a' - sets the append-only flag\n" " 'chattr -a' - clears the append-only flag\n" "\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, only modifying attributes on directories\n" " +/-r -- set/clear the realtime flag\n" " +/-i -- set/clear the immutable flag\n" " +/-a -- set/clear the append-only flag\n" " +/-s -- set/clear the sync flag\n" " +/-A -- set/clear the no-atime flag\n" " +/-d -- set/clear the no-dump flag\n" " +/-t -- set/clear the realtime inheritance flag\n" " +/-P -- set/clear the project ID inheritance flag\n" " +/-n -- set/clear the no-symbolic-links flag\n" " +/-e -- set/clear the extent-size flag\n" " +/-E -- set/clear the extent-size inheritance flag\n" " +/-f -- set/clear the no-defrag flag\n" " +/-S -- set/clear the filestreams allocator flag\n" " +/-x -- set/clear the direct access (DAX) flag\n" " +/-C -- set/clear the CoW extent-size flag\n" " Note1: user must have certain capabilities to modify immutable/append-" "only.\n" " Note2: immutable/append-only files cannot be deleted; removing these files\n" " requires the immutable/append-only flag to be cleared first.\n" " Note3: the realtime flag can only be set if the filesystem has a realtime\n" " section, and the (regular) file must be empty when the flag is set.\n" "\n" msgstr "" "\n" " zmiana zbioru rozszerzonych flag i-wÄ™złów zwiÄ…zanych z bieżącym plikiem\n" "\n" " PrzykÅ‚ady:\n" " 'chattr +a' - ustawia flagÄ™ tylko do dopisywania\n" " 'chattr -a' - zdejmuje flagÄ™ tylko do dopisywania\n" "\n" " -R - rekurencyjne zagłębianie siÄ™ (przydatne kiedy bieżący plik jest " "katalogiem)\n" " -D - rekurencyjne zagłębianie siÄ™, ale zmiana atrybutów tylko katalogów\n" " +/-r - ustawienie/zdjÄ™cie flagi realtime\n" " +/-i - ustawienie/zdjÄ™cie flagi immutable (niezmiennoÅ›ci)\n" " +/-a - ustawienie/zdjÄ™cie flagi append-only (tylko do dopisywania)\n" " +/-s - ustawienie/zdjÄ™cie flagi sync (synchronicznego zapisu)\n" " +/-A - ustawienie/zdjÄ™cie flagi no-atime\n" " +/-d - ustawienie/zdjÄ™cie flagi no-dump\n" " +/-t - ustawienie/zdjÄ™cie flagi dziedziczenia realtime\n" " +/-P - ustawienie/zdjÄ™cie flagi dziedziczenia ID projektu\n" " +/-n - ustawienie/zdjÄ™cie flagi braku dowiÄ…zaÅ„ symbolicznych\n" " +/-e - ustawienie/zdjÄ™cie flagi rozmiaru ekstentu\n" " +/-E - ustawienie/zdjÄ™cie flagi dziedziczenia rozmiaru ekstentu\n" " +/-f - ustawienie/zdjÄ™cie flagi no-defrag\n" " +/-S - ustawienie/zdjÄ™cie flagi przydzielania strumieni plikowych\n" " +/-x - ustawienie/zdjÄ™cie flagi bezpoÅ›redniego dostÄ™pu (DAX)\n" " +/-C - ustawienie/zdjÄ™cie flagi rozmiaru ekstentu CoW\n" " Uwaga1: użytkownik musi mieć pewne uprawnienia do zmiany flag\n" " immutable/append-only\n" " Uwaga2: plików immutable/append-only nie można usuwać; usuwanie tych " "plików\n" " wymaga zdjÄ™cia flag immutable/append-only przed usuniÄ™ciem.\n" " Uwaga3: flagÄ™ realtime można ustawić tylko jeÅ›li system plików ma sekcjÄ™\n" " realtime i (zwykÅ‚y) plik musi być pusty przy ustawianiu flagi.\n" "\n" #: .././io/attr.c:176 .././io/attr.c:252 .././io/cowextsize.c:109 #: .././io/cowextsize.c:132 .././io/open.c:347 .././io/open.c:419 #: .././io/open.c:543 .././io/open.c:565 .././libxfs/init.c:127 #: .././mkfs/proto.c:302 .././quota/project.c:118 .././quota/project.c:163 #: .././quota/project.c:210 #, c-format msgid "%s: cannot open %s: %s\n" msgstr "%s: nie można otworzyć %s: %s\n" #: .././io/attr.c:179 .././io/attr.c:226 .././io/attr.c:255 .././io/attr.c:326 #: .././quota/project.c:122 .././quota/project.c:168 .././quota/project.c:215 #, c-format msgid "%s: cannot get flags on %s: %s\n" msgstr "%s: nie można pobrać flag %s: %s\n" #: .././io/attr.c:261 .././io/attr.c:332 #, c-format msgid "%s: cannot set flags on %s: %s\n" msgstr "%s: nie można ustawić flag %s: %s\n" #: .././io/attr.c:296 .././io/attr.c:310 #, c-format msgid "%s: unknown flag\n" msgstr "%s: nieznana flaga\n" #: .././io/attr.c:316 #, c-format msgid "%s: bad chattr command, not +/-X\n" msgstr "%s: zÅ‚e polecenie chattr - nie +/-X\n" #: .././io/attr.c:343 msgid "[-R|-D] [+/-" msgstr "[-R|-D] [+/-" #: .././io/attr.c:348 msgid "change extended inode flags on the currently open file" msgstr "zmiana rozszerzonych flag i-wÄ™złów aktualnie otwartego pliku" #: .././io/attr.c:353 msgid "[-R|-D|-a|-v]" msgstr "[-R|-D|-a|-v]" #: .././io/attr.c:358 msgid "list extended inode flags set on the currently open file" msgstr "wypisanie rozszerzonych flag i-wÄ™złów aktualnie otwartego pliku" #: .././io/bmap.c:31 #, c-format msgid "" "\n" " prints the block mapping for an XFS file's data or attribute forks\n" " Example:\n" " 'bmap -vp' - tabular format verbose map, including unwritten extents\n" "\n" " bmap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -c -- prints the copy-on-write fork map instead of the data fork.\n" " -d -- suppresses a DMAPI read event, offline portions shown as holes.\n" " -e -- print delayed allocation extents.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " -n -- query n extents.\n" " -p -- obtain all unwritten extents as well (w/ -v show which are " "unwritten.)\n" " -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n" " Note: the bmap for non-regular files can be obtained provided the file\n" " was opened appropriately (in particular, must be opened read-only).\n" "\n" msgstr "" "\n" " wypisanie mapowania bloków dla danych lub atrybutów pliku na XFS-ie\n" " PrzykÅ‚ad:\n" " 'bmap -vp' - szczegółowa mapa w formacie tabeli wraz z nie zapisanymi\n" " ekstentami\n" "\n" " bmap wypisuje mapÄ™ bloków dysku używanych przez bieżący plik.\n" " Mapa opisuje każdy ekstent użyty przez plik, a także regiony w pliku\n" " nie majÄ…ce przypisanych bloków (dziury).\n" " DomyÅ›lnie każda linia listingu przyjmuje nastÄ™pujÄ…cÄ… postać:\n" " ekstent: [offsetpocz..offsetkoÅ„c]: blokpocz..blokkoÅ„c\n" " Dziury sÄ… oznaczane przez zastÄ…pienie blokpocz..blokkoÅ„c przez 'dziura'.\n" " Wszystkie offsety w plikach i bloki dysku sÄ… w jednostkach 512-bajtowych.\n" " -a - wypisanie mapy gałęzi atrybutów zamiast gałęzi danych.\n" " -c - wypisanie mapy gałęzi CoW zamiast gałęzi danych.\n" " -d - pominiÄ™cie zdarzenia odczytu DMAPI, pokazanie części offline jako " "dziur.\n" " -e - wypisanie ekstentów opóźnionego przydzielania.\n" " -l - wyÅ›wietlenie także dÅ‚ugoÅ›ci każdego ekstentu w 512-bajtowych blokach.\n" " -n - odpytanie n ekstentów.\n" " -p - wypisanie także nie zapisanych ekstentów (z -v pokazuje, które sÄ… nie\n" " zapisane).\n" " -v - szczegółowe informacje z podaniem informacji ag; legenda drugim -v\n" " Uwaga: bmap dla plików nie bÄ™dÄ…cych plikami zwykÅ‚ymi można uzyskać pod\n" " warunkiem, że plik zostaÅ‚ otwarty odpowiednio (w szczególnoÅ›ci musi być\n" " otwarty tylko do odczytu).\n" "\n" #: .././io/bmap.c:122 .././io/fsmap.c:467 #, c-format msgid "%s: can't get geometry [\"%s\"]: %s\n" msgstr "%s: nie można uzyskać geometrii [\"%s\"]: %s\n" #: .././io/bmap.c:130 #, c-format msgid "%s: cannot read attrs on \"%s\": %s\n" msgstr "%s: nie można odczytać atrybutów \"%s\": %s\n" #: .././io/bmap.c:148 .././io/fiemap.c:301 #, c-format msgid "%s: malloc of %d bytes failed.\n" msgstr "%s: przydzielenie %d bajtów nie powiodÅ‚o siÄ™.\n" #: .././io/bmap.c:196 #, c-format msgid "%s: xfsctl(XFS_IOC_GETBMAPX) iflags=0x%x [\"%s\"]: %s\n" msgstr "%s: xfsctl(XFS_IOC_GETBMAPX) iflags=0x%x [\"%s\"]: %s\n" #: .././io/bmap.c:227 #, c-format msgid "%s: cannot realloc %d bytes\n" msgstr "%s: nie można wykonać realloc na %d bajtów\n" #: .././io/bmap.c:236 #, c-format msgid "%s: no extents\n" msgstr "%s: brak ekstentów\n" #: .././io/bmap.c:250 .././io/bmap.c:385 .././io/fiemap.c:82 #, c-format msgid "hole" msgstr "dziura" #: .././io/bmap.c:252 .././io/bmap.c:393 #, c-format msgid "delalloc" msgstr "delalloc" #: .././io/bmap.c:261 #, c-format msgid " %lld blocks\n" msgstr " %lld bloków\n" #: .././io/bmap.c:341 .././io/fiemap.c:117 .././io/fsmap.c:266 msgid "EXT" msgstr "EXT" #: .././io/bmap.c:342 .././io/fiemap.c:118 .././io/fsmap.c:270 msgid "FILE-OFFSET" msgstr "OFFSET-W-PLIKU" #: .././io/bmap.c:343 msgid "RT-BLOCK-RANGE" msgstr "ZAKRES-BLOKÓW-RT" #: .././io/bmap.c:343 .././io/fiemap.c:119 .././io/fsmap.c:268 msgid "BLOCK-RANGE" msgstr "ZAKRES-BLOKÓW" #: .././io/bmap.c:344 .././io/fsmap.c:271 msgid "AG" msgstr "AG" #: .././io/bmap.c:345 .././io/fsmap.c:272 msgid "AG-OFFSET" msgstr "OFFSET-AG" #: .././io/bmap.c:346 .././io/fiemap.c:120 .././io/fsmap.c:273 msgid "TOTAL" msgstr "RAZEM" #: .././io/bmap.c:347 .././io/fsmap.c:274 msgid " FLAGS" msgstr " FLAGI" #: .././io/bmap.c:427 .././io/fsmap.c:364 #, c-format msgid " FLAG Values:\n" msgstr " WartoÅ›ci FLAG:\n" #: .././io/bmap.c:428 .././io/fsmap.c:367 #, c-format msgid " %*.*o Shared extent\n" msgstr " %*.*o Ekstent współdzielony\n" #: .././io/bmap.c:430 .././io/fsmap.c:369 #, c-format msgid " %*.*o Unwritten preallocated extent\n" msgstr " %*.*o Ekstent nie zapisany, już przydzielony\n" #: .././io/bmap.c:432 .././io/fsmap.c:371 #, c-format msgid " %*.*o Doesn't begin on stripe unit\n" msgstr " %*.*o Nie zaczyna siÄ™ od jednostki pasa\n" #: .././io/bmap.c:434 .././io/fsmap.c:373 #, c-format msgid " %*.*o Doesn't end on stripe unit\n" msgstr " %*.*o Nie koÅ„czy siÄ™ na jednostce pasa\n" #: .././io/bmap.c:436 .././io/fsmap.c:375 #, c-format msgid " %*.*o Doesn't begin on stripe width\n" msgstr " %*.*o Nie zaczyna siÄ™ na szerokoÅ›ci pasa\n" #: .././io/bmap.c:438 .././io/fsmap.c:377 #, c-format msgid " %*.*o Doesn't end on stripe width\n" msgstr " %*.*o Nie koÅ„czy siÄ™ na szerokoÅ›ci pasa\n" #: .././io/bmap.c:454 msgid "[-adlpv] [-n nx]" msgstr "[-adlpv] [-n nx]" #: .././io/bmap.c:455 msgid "print block mapping for an XFS file" msgstr "wypisanie mapowania bloków dla pliku na XFS-ie" #: .././io/copy_file_range.c:32 #, c-format msgid "" "\n" " Copies a range of bytes from a file into the open file, overwriting any " "data\n" " already there.\n" "\n" " Example:\n" " 'copy_range -s 100 -d 200 -l 300 some_file' - copies 300 bytes from " "some_file\n" " at offset 100 into the open\n" "\t\t\t\t\t file at offset 200\n" " 'copy_range some_file' - copies all bytes from some_file into the open " "file\n" " at position 0\n" msgstr "" "\n" " Skopiowanie zakresu bajtów z pliku do otwartego pliku, nadpisujÄ…c wszelkie\n" " dane, które siÄ™ tam już znajdujÄ….\n" "\n" " PrzykÅ‚ad:\n" " 'copy_range -s 100 -d 200 -l 300 jakiÅ›_plik' - kopiuje 300 bajtów\n" " z jakiegoÅ›_pliku do " "otwartego\n" " pliku pod offset 200\n" " 'copy_range jakiÅ›_plik' - kopiuje wszystkie bajty z jakiegoÅ›_pliku do\n" " otwartego pliku od pozycji 0\n" #: .././io/copy_file_range.c:105 #, c-format msgid "invalid source offset -- %s\n" msgstr "nieprawidÅ‚owy offset źródÅ‚owy - %s\n" #: .././io/copy_file_range.c:112 #, c-format msgid "invalid destination offset -- %s\n" msgstr "nieprawidÅ‚owy offset docelowy - %s\n" #: .././io/copy_file_range.c:119 #, c-format msgid "invalid length -- %s\n" msgstr "nieprawidÅ‚owa dÅ‚ugość - %s\n" #: .././io/copy_file_range.c:151 msgid "[-s src_off] [-d dst_off] [-l len] src_file" msgstr "[-s off_źródÅ‚owy] [-d off_docelowy] [-l dÅ‚ugość] plik_źródÅ‚owy" #: .././io/copy_file_range.c:152 msgid "Copy a range of data between two files" msgstr "Kopiowanie zakresu danych miÄ™dzy dwoma plikami" #: .././io/cowextsize.c:40 #, c-format msgid "" "\n" " report or modify preferred CoW extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying cowextsize on directories\n" "\n" msgstr "" "\n" " odczyt lub zmiana preferowanego rozmiaru ekstentu CoW (w bajtach) dla " "bieżącej\n" " Å›cieżki\n" "\n" " -R - rekurencyjne zagłębianie siÄ™ (przydatne kiedy bieżący plik jest " "katalogiem)\n" " -D - rekurencyjne zagłębianie siÄ™, ale zmiana cowextsize tylko katalogów\n" "\n" #: .././io/cowextsize.c:81 .././io/open.c:516 #, c-format msgid "invalid target file type - file %s\n" msgstr "nieprawidÅ‚owy rodzaj bliku docelowego - plik %s\n" #: .././io/cowextsize.c:169 #, c-format msgid "non-numeric cowextsize argument -- %s\n" msgstr "nieliczbowy argument cowextsize - %s\n" #: .././io/cowextsize.c:193 msgid "[-D | -R] [cowextsize]" msgstr "[-D | -R] [rozmiar_ekstentu_cow]" #: .././io/cowextsize.c:198 msgid "get/set preferred CoW extent size (in bytes) for the open file" msgstr "" "odczyt/ustawienie rozmiaru ekstentu CoW (w bajtach) dla otwartego pliku" #: .././io/encrypt.c:77 #, c-format msgid "" "\n" " assign an encryption policy to the currently open file\n" "\n" " Examples:\n" " 'set_encpolicy' - assign policy with default key [0000000000000000]\n" " 'set_encpolicy 0000111122223333' - assign policy with specified key\n" "\n" " -c MODE -- contents encryption mode\n" " -n MODE -- filenames encryption mode\n" " -f FLAGS -- policy flags\n" " -v VERSION -- version of policy structure\n" "\n" " MODE can be numeric or one of the following predefined values:\n" " AES-256-XTS, AES-256-CTS, AES-256-GCM, AES-256-CBC\n" " FLAGS and VERSION must be numeric.\n" "\n" " Note that it's only possible to set an encryption policy on an empty\n" " directory. It's then inherited by new files and subdirectories.\n" "\n" msgstr "" "\n" " przypisanie polityki szyfrowania do aktualnie otwartego pliku\n" "\n" " PrzykÅ‚ady:\n" " 'set_encpolicy' - przypisanie polityki z kluczem domyÅ›lnym " "[0000000000000000]\n" " 'set_encpolicy 0000111122223333' - przypisanie polityki z podanym kluczem\n" "\n" " -c TRYB - tryb szyfrowania zawartoÅ›ci\n" " -n TRYB -- tryb szyfrowania nazw plików\n" " -f FLAGI -- flagi polityki\n" " -v WERSJA -- wersja struktury polityki\n" "\n" " TRYB może być liczbÄ… lub jednÄ… z nastÄ™pujÄ…cych, predefiniowanych wartoÅ›ci:\n" " AES-256-XTS, AES-256-CTS, AES-256-GCM, AES-256-CBC\n" " FLAGI i WERSJA muszÄ… być liczbami.\n" "\n" " Uwaga: możliwe jest ustawienie polityki tylko na pustym katalogu. " "NastÄ™pnie\n" " jest ona dziedziczona na nowe pliki i podkatalogi.\n" "\n" #: .././io/encrypt.c:288 msgid "display the encryption policy of the current file" msgstr "wyÅ›wietlenie polityki szyfrowania bieżącego pliku" #: .././io/encrypt.c:293 msgid "[-c mode] [-n mode] [-f flags] [-v version] [keydesc]" msgstr "[-c tryb] [-n tryb] [-f flagi] [-v wersja] [opis_klucza]" #: .././io/encrypt.c:298 msgid "assign an encryption policy to the current file" msgstr "przypisanie polityki szyfrowania do bieżącego pliku" #: .././io/fadvise.c:30 #, c-format msgid "" "\n" " advise the page cache about expected I/O patterns on the current file\n" "\n" " Modifies kernel page cache behaviour when operating on the current file.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_FADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_FADV_DONTNEED) [*]\n" " -n -- data will be accessed once (POSIX_FADV_NOREUSE) [*]\n" " -r -- expect random page references (POSIX_FADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_FADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_FADV_WILLNEED) [*]\n" " Notes: these interfaces are not supported in Linux kernels before 2.6.\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED and NOREUSE are equivalent, and force the maximum readahead.\n" "\n" msgstr "" "\n" " doradzenie buforowi stron w sprawie oczekiwanych schematów we/wy na " "bieżącym\n" " pliku\n" "\n" " fadvise modyfikuje zachowanie bufora stron przy operacjach na bieżącym " "pliku.\n" " Niektóre polecenia fadvise ([*] poniżej) wymagajÄ… podania zakresu.\n" " Bez argumentów zakÅ‚ada siÄ™ doradzenie POSIX_FADV_NORMAL.\n" " -d - podane strony nie sÄ… wymagane (POSIX_FADV_DONTNEED) [*]\n" " -n - dostÄ™p do danych bÄ™dzie jednokrotny (POSIX_FADV_NOREUSE) [*]\n" " -r - należy oczekiwać losowych odwoÅ‚aÅ„ do stron (POSIX_FADV_RANDOM)\n" " -s - należy oczekiwać sekwencyjnych odwoÅ‚aÅ„ do stron " "(POSIX_FADV_SEQUENTIAL)\n" " -w - podane strony bÄ™dÄ… potrzebne (POSIX_FADV_WILLNEED) [*]\n" " Uwagi: te interfejsy nie byÅ‚y obsÅ‚ugiwane przez jÄ…dra Linuksa przed 2.6.\n" " NORMAL ustawia domyÅ›lnÄ… wartość czytania z wyprzedzeniem dla pliku.\n" " RANDOM ustawia czytanie z wyprzedzeniem dla pliku na zero.\n" " SEQUENTIAL ustawia podwójnÄ… domyÅ›lnÄ… wartość czytania z wyprzedzeniem.\n" " WILLNEED i NOREUSE sÄ… równoznaczne i wymuszajÄ… maksymalne czytanie\n" " z wyprzedzeniem.\n" "\n" #: .././io/fadvise.c:91 .././io/madvise.c:86 .././io/mincore.c:47 #: .././io/mmap.c:231 .././io/mmap.c:339 .././io/mmap.c:425 .././io/mmap.c:584 #: .././io/mmap.c:666 .././io/prealloc.c:73 .././io/pwrite.c:397 #: .././io/sendfile.c:124 .././io/sync_file_range.c:74 #, c-format msgid "non-numeric offset argument -- %s\n" msgstr "nieliczbowy argument bÄ™dÄ…cy offsetem - %s\n" #: .././io/fadvise.c:98 .././io/madvise.c:93 .././io/mincore.c:53 #: .././io/mmap.c:237 .././io/mmap.c:346 .././io/mmap.c:432 .././io/mmap.c:591 #: .././io/pread.c:456 .././io/pread.c:464 .././io/prealloc.c:78 #: .././io/pwrite.c:403 .././io/sendfile.c:131 .././io/sync_file_range.c:81 #, c-format msgid "non-numeric length argument -- %s\n" msgstr "nieliczbowy argument bÄ™dÄ…cy dÅ‚ugoÅ›ciÄ… - %s\n" #: .././io/fadvise.c:121 msgid "[-dnrsw] [off len]" msgstr "[-dnrsw] [offset dÅ‚ugość]" #: .././io/fadvise.c:122 msgid "advisory commands for sections of a file" msgstr "polecenia doradcze dla sekcji pliku" #: .././io/fiemap.c:35 #, c-format msgid "" "\n" " prints the block mapping for a file's data or attribute forks\n" " Example:\n" " 'fiemap -v' - tabular format verbose map\n" "\n" " fiemap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " -n -- query n extents.\n" " -v -- Verbose information\n" " offset is the starting offset to map, and is optional. If offset is\n" " specified, mapping length may (optionally) be specified as well.\n" msgstr "" "\n" " wypisanie odwzorowania bloków dla gałęzi danych lub atrybutów pliku\n" " PrzykÅ‚ad:\n" " 'fiemap -v' - szczegółowa mapa w formacie tabeli\n" "\n" " fiemap wypisuje mapÄ™ bloków dysku używanych przez bieżący plik.\n" " Mapa opisuje każdy ekstent użyty przez plik, a także regiony w pliku\n" " nie majÄ…ce przypisanych bloków (dziury).\n" " DomyÅ›lnie każda linia listingu przyjmuje nastÄ™pujÄ…cÄ… postać:\n" " ekstent: [offsetpocz..offsetkoÅ„c]: blokpocz..blokkoÅ„c\n" " Dziury sÄ… oznaczane przez zastÄ…pienie blokpocz..blokkoÅ„c przez 'dziura'.\n" " Wszystkie offsety w plikach i bloki dysku sÄ… w jednostkach 512-bajtowych.\n" " -a - wypisanie mapy gałęzi atrybutów zamiast gałęzi danych.\n" " -l - wyÅ›wietlenie także dÅ‚ugoÅ›ci każdego ekstentu w 512-bajtowych blokach.\n" " -n - odpytanie n ekstentów.\n" " -v - szczegółowe informacje\n" " offset to poczÄ…tkowy oddset mapy i jest opcjonalny. JeÅ›li jest podany,\n" " można także (opcjonalnie) podać dÅ‚ugość odwzorowania.\n" "\n" #: .././io/fiemap.c:74 .././io/fiemap.c:181 #, c-format msgid " %llu blocks\n" msgstr " %llu bloków\n" #: .././io/fiemap.c:121 msgid "FLAGS" msgstr "FLAGI" #: .././io/fiemap.c:405 msgid "[-alv] [-n nx] [offset [len]]" msgstr "[-alv] [-n nx] [offset [dÅ‚ugość]]" #: .././io/fiemap.c:406 msgid "print block mapping for a file" msgstr "wypisanie mapowania bloków dla pliku" #: .././io/file.c:38 #, c-format msgid "%c%03d%c %-14s (%s,%s,%s,%s%s%s%s%s)\n" msgstr "%c%03d%c %-14s (%s,%s,%s,%s%s%s%s%s)\n" #: .././io/file.c:40 msgid "foreign" msgstr "obcy" #: .././io/file.c:40 msgid "xfs" msgstr "xfs" #: .././io/file.c:41 .././io/stat.c:97 msgid "sync" msgstr "synchr" #: .././io/file.c:41 .././io/stat.c:97 msgid "non-sync" msgstr "niesynchr" #: .././io/file.c:42 .././io/stat.c:98 msgid "direct" msgstr "bezpoÅ›redni" #: .././io/file.c:42 .././io/stat.c:98 msgid "non-direct" msgstr "niebezpoÅ›redni" #: .././io/file.c:43 .././io/stat.c:99 msgid "read-only" msgstr "tylko do odczytu" #: .././io/file.c:43 .././io/stat.c:99 msgid "read-write" msgstr "odczyt i zapis" #: .././io/file.c:44 .././io/stat.c:100 msgid ",real-time" msgstr ",real-time" #: .././io/file.c:45 .././io/stat.c:101 msgid ",append-only" msgstr ",tylko dopisywanie" #: .././io/file.c:46 .././io/stat.c:102 msgid ",non-block" msgstr ",nieblokujÄ…cy" #: .././io/file.c:47 .././io/stat.c:103 msgid ",tmpfile" msgstr ",tmpfile" #: .././io/file.c:81 .././io/sendfile.c:101 .././quota/path.c:126 #, c-format msgid "value %d is out of range (0-%d)\n" msgstr "wartość %d jest spoza zakresu (0-%d)\n" #: .././io/file.c:94 .././quota/path.c:140 msgid "[N]" msgstr "[N]" #: .././io/file.c:99 msgid "set the current file" msgstr "ustawienie bieżącego pliku" #: .././io/file.c:108 msgid "list current open files and memory mappings" msgstr "wypisanie aktualnie otwartych plików i odwzorowaÅ„ w pamiÄ™ci" #: .././io/freeze.c:36 #, c-format msgid "%s: cannot freeze filesystem at %s: %s\n" msgstr "%s: nie można zamrozić systemu plików na %s: %s\n" #: .././io/freeze.c:53 #, c-format msgid "%s: cannot unfreeze filesystem mounted at %s: %s\n" msgstr "%s: nie można odmrozić systemu plików zamontowanego pod %s: %s\n" #: .././io/freeze.c:69 msgid "freeze filesystem of current file" msgstr "zamrożenie systemu plików na bieżącym pliku" #: .././io/freeze.c:76 msgid "unfreeze filesystem of current file" msgstr "odmrożenie systemu plików na bieżącym pliku" #: .././io/fsmap.c:34 #, c-format msgid "" "\n" " Prints the block mapping for the filesystem hosting the current file\n" " fsmap prints the map of disk blocks used by the whole filesystem.\n" " When possible, owner and offset information will be included in the\n" " space report.\n" "\n" " By default, each line of the listing takes the following form:\n" " extent: major:minor [startblock..endblock]: owner startoffset.." "endoffset length\n" " The owner field is either an inode number or a special value.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -d -- query only the data device (default).\n" " -l -- query only the log device.\n" " -r -- query only the realtime device.\n" " -n -- query n extents at a time.\n" " -m -- output machine-readable format.\n" " -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -" "v\n" "\n" "The optional start and end arguments require one of -d, -l, or -r to be " "set.\n" "\n" msgstr "" "\n" " wypisanie odwzorowania bloków dla systemu plików przechowujÄ…cego bieżący " "plik\n" " fsmap wypisuje mapÄ™ bloków dysku używanych przez caÅ‚y system plików.\n" " JeÅ›li to możliwe, w raporcie dotyczÄ…cym miejsca dołączone zostanÄ… " "informacje\n" " o wÅ‚aÅ›cicielu i offsecie.\n" "\n" " DomyÅ›lnie każdy wiersz listy ma nastÄ™pujÄ…cÄ… postać:\n" " ekstent: major:minor [blok_pocz..blok_koÅ„c]: wÅ‚aÅ›ciciel offset_pocz.." "offset_koÅ„c dÅ‚ugość\n" " Pole wÅ‚aÅ›ciciel jest numerem i-wÄ™zÅ‚a lub wartoÅ›ciÄ… specjalnÄ….\n" " Wszystkie offsety plików i bloki dysku sÄ… podawane w 512-bajtowych " "sektorach.\n" " -d - odpytanie tylko urzÄ…dzenia danych (domyÅ›lnie).\n" " -l - odpytanie tylko urzÄ…dzenia logu.\n" " -r - odpytanie tylko urzÄ…dzenia realtime.\n" " -n - odpytanie n ekstentów jednoczeÅ›nie.\n" " -m - wyjÅ›cie w formacie czytelnym dla maszyny.\n" " -v - szczegółowe informacje, z AG i offsetami; legenda do flag z drugim -" "v.\n" "\n" "Opcjonalne argumenty poczÄ…tek i koniec wymagajÄ… podania jednej z opcji -d, -" "l\n" "lub -r.\n" "\n" #: .././io/fsmap.c:64 msgid "free space" msgstr "wolne miejsce" #: .././io/fsmap.c:66 msgid "unknown" msgstr "nieznane" #: .././io/fsmap.c:68 msgid "static fs metadata" msgstr "statyczne metadane fs" #: .././io/fsmap.c:70 msgid "journalling log" msgstr "log kroniki" #: .././io/fsmap.c:72 msgid "per-AG metadata" msgstr "metadane dla AG" #: .././io/fsmap.c:74 msgid "inode btree" msgstr "b-drzewo i-wÄ™złów" #: .././io/fsmap.c:76 .././repair/progress.c:16 .././scrub/phase7.c:187 msgid "inodes" msgstr "i-wÄ™zÅ‚y" #: .././io/fsmap.c:78 msgid "refcount btree" msgstr "b-drzewo zliczania odwoÅ‚aÅ„" #: .././io/fsmap.c:80 msgid "cow reservation" msgstr "rezerwa cow" #: .././io/fsmap.c:82 msgid "defective" msgstr "uszkodzone" #: .././io/fsmap.c:84 #, c-format msgid "special %u:%u" msgstr "specjalne %u:%u" #: .././io/fsmap.c:109 #, c-format msgid "inode %lld %s extent map" msgstr "mapa ekstentów %2$s i-wÄ™zÅ‚a %1$lld" #: .././io/fsmap.c:112 #, c-format msgid "inode %lld %s %lld..%lld" msgstr "i-wÄ™zeÅ‚ %2$s %1$lld %3$lld..%4$lld" #: .././io/fsmap.c:116 #, c-format msgid " %lld\n" msgstr " %lld\n" #: .././io/fsmap.c:132 #, c-format msgid "EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n" msgstr "EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n" #: .././io/fsmap.c:143 #, c-format msgid "inode_%lld_%s_bmbt,,," msgstr "inode_%lld_%s_bmbt,,," #: .././io/fsmap.c:146 #, c-format msgid "inode_%lld_%s,%lld,%lld," msgstr "inode_%lld_%s,%lld,%lld," #: .././io/fsmap.c:241 msgid "extent_map" msgstr "mapa_ekstentów" #: .././io/fsmap.c:267 msgid "DEV" msgstr "URZ." #: .././io/fsmap.c:269 msgid "OWNER" msgstr "WÅAÅšC." #: .././io/fsmap.c:339 msgid "extent map" msgstr "mapa ekstentów" #: .././io/fsmap.c:365 #, c-format msgid " %*.*o Attribute fork\n" msgstr " %*.*o Gałąź atrybutów\n" #: .././io/fsmap.c:445 #, c-format msgid "Bad rmap start_bblock %s.\n" msgstr "Błędna wartość start_bblock dla rmap: %s.\n" #: .././io/fsmap.c:456 #, c-format msgid "Bad rmap end_bblock %s.\n" msgstr "Błędna wartość end_bblock dla rmap: %s.\n" #: .././io/fsmap.c:477 #, c-format msgid "%s: malloc of %zu bytes failed.\n" msgstr "%s: przydzielenie %zu bajtów nie powiodÅ‚o siÄ™.\n" #: .././io/fsmap.c:507 .././io/fsmap.c:546 #, c-format msgid "%s: xfsctl(XFS_IOC_GETFSMAP) iflags=0x%x [\"%s\"]: %s\n" msgstr "%s: xfsctl(XFS_IOC_GETFSMAP) iflags=0x%x [\"%s\"]: %s\n" #: .././io/fsmap.c:521 #, c-format msgid "%s: cannot realloc %zu bytes\n" msgstr "%s: nie można wykonać realloc na %zu bajtów\n" #: .././io/fsmap.c:586 msgid "[-d|-l|-r] [-m|-v] [-n nx] [start] [end]" msgstr "[-d|-l|-r] [-m|-v] [-n nx] [poczÄ…tek] [koniec]" #: .././io/fsmap.c:587 msgid "print filesystem mapping for a range of blocks" msgstr "wypisanie mapowania w systemie plików dla przedziaÅ‚u bloków" #: .././io/fsync.c:59 msgid "calls fsync(2) to flush all in-core file state to disk" msgstr "wywoÅ‚anie fsync(2) aby zrzucić caÅ‚y stan pliku z pamiÄ™ci na dysk" #: .././io/fsync.c:66 msgid "calls fdatasync(2) to flush the files in-core data to disk" msgstr "wywoÅ‚anie fdatasync(2) aby zrzucić dane pliku z pamiÄ™ci na dysk" #: .././io/getrusage.c:118 msgid "report process resource usage" msgstr "informacje o wykorzystaniu zasobów przez proces" #: .././io/imap.c:54 #, c-format msgid "ino %10llu count %2d mask %016llx\n" msgstr "i-wÄ™zeÅ‚ %10llu liczba %2d maska %016llx\n" #: .././io/imap.c:74 msgid "[nentries]" msgstr "[liczba_wpisów]" #: .././io/imap.c:76 msgid "inode map for filesystem of current file" msgstr "map i-wÄ™złów dla systemu plików bieżącego pliku" #: .././io/init.c:37 #, c-format msgid "Usage: %s [-adfinrRstVx] [-m mode] [-p prog] [[-c|-C] cmd]... file\n" msgstr "" "SkÅ‚adnia: %s [-adfinrRstVx] [-m tryb] [-p prog] [[-c|-C] polecenie]... plik\n" #: .././io/init.c:119 .././io/mmap.c:176 .././io/mmap.c:183 .././io/mmap.c:186 #: .././io/open.c:215 #, c-format msgid "no files are open, try 'help open'\n" msgstr "nie ma otwartych plików, spróbuj 'help open'\n" #: .././io/init.c:123 .././io/mmap.c:175 .././io/mmap.c:182 #, c-format msgid "no mapped regions, try 'help mmap'\n" msgstr "nie ma podmapowanych regionów, spróbuj 'help mmap'\n" #: .././io/init.c:129 #, c-format msgid "foreign file active, %s command is for XFS filesystems only\n" msgstr "" "aktywny jest plik obcy, polecenie %s jest tylko dla systemów plików XFS\n" #: .././io/init.c:182 .././io/open.c:237 #, c-format msgid "non-numeric mode -- %s\n" msgstr "tryb nieliczbowy - %s\n" #: .././io/inject.c:99 #, c-format msgid "" "\n" " inject errors into the filesystem of the currently open file\n" "\n" " Example:\n" " 'inject readagf' - cause errors on allocation group freespace reads\n" "\n" " Causes the kernel to generate and react to errors within XFS, provided\n" " the XFS kernel code has been built with debugging features enabled.\n" " With no arguments, displays the list of error injection tags.\n" "\n" msgstr "" "\n" " wprowadzenie błędów do systemu plików aktualnie otwartego pliku\n" "\n" " PrzykÅ‚ad:\n" " 'inject readagf' - spowodowanie błędów przy odczytach wolnego miejsca grup\n" " alokacji\n" "\n" " inject powoduje, że jÄ…dro generuje i reaguje na błędy wewnÄ…trz XFS-a,\n" " pod warunkiem, że kod XFS-a w jÄ…drze zostaÅ‚ zbudowany z włączonymi opcjami\n" " diagnostycznymi. Bez argumentów wyÅ›wietla listÄ™ znaczników wprowadzania\n" " błędów.\n" "\n" #: .././io/inject.c:125 #, c-format msgid "no such tag -- %s\n" msgstr "nie ma takiego znacznika - %s\n" #: .././io/inject.c:146 msgid "[tag ...]" msgstr "[znacznik ...]" #: .././io/inject.c:147 msgid "inject errors into a filesystem" msgstr "wprowadzanie błędów do systemu plików" #: .././io/link.c:34 #, c-format msgid "" "\n" "link the open file descriptor to the supplied filename\n" "\n" "\n" msgstr "" "\n" "dowiÄ…zanie otwartego deskryptora pliku do podanej nazwy pliku\n" "\n" "\n" #: .././io/link.c:63 msgid "filename" msgstr "nazwa_pliku" #: .././io/link.c:65 msgid "link the open file descriptor to the supplied filename" msgstr "dowiÄ…zanie otwartego deskryptora pliku do podanej nazwy pliku" #: .././io/log_writes.c:101 msgid "-d device -m mark" msgstr "-d urzÄ…dzenie -m znacznik" #: .././io/log_writes.c:103 msgid "create mark in the dm-log-writes log specified by " msgstr "utworzenie w logu dm-log-writes okreÅ›lonym " #: .././io/madvise.c:31 #, c-format msgid "" "\n" " advise the page cache about access patterns expected for a mapping\n" "\n" " Modifies page cache behavior when operating on the current mapping.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_MADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_MADV_DONTNEED) [*]\n" " -r -- expect random page references (POSIX_MADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_MADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_MADV_WILLNEED) [*]\n" " Notes:\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED forces the maximum readahead.\n" "\n" msgstr "" "\n" " doradzenie buforowi stron w sprawie oczekiwanych schematów dostÄ™pu do " "odwzorowaÅ„\n" "\n" " madvise modyfikuje zachowanie bufora stron przy operacjach na bieżącym\n" " odwzorowaniu. Niektóre polecenia madvise ([*] poniżej) wymagajÄ… podania " "zakresu.\n" " Bez argumentów zakÅ‚ada siÄ™ doradzenie POSIX_MADV_NORMAL.\n" " -d - podane strony nie sÄ… wymagane (POSIX_MADV_DONTNEED) [*]\n" " -r - należy oczekiwać losowych odwoÅ‚aÅ„ do stron (POSIX_MADV_RANDOM)\n" " -s - należy oczekiwać sekwencyjnych odwoÅ‚aÅ„ do stron " "(POSIX_MADV_SEQUENTIAL)\n" " -w - podane strony bÄ™dÄ… potrzebne (POSIX_MADV_WILLNEED) [*]\n" " Uwagi:\n" " NORMAL ustawia domyÅ›lnÄ… wartość czytania z wyprzedzeniem dla pliku.\n" " RANDOM ustawia czytanie z wyprzedzeniem dla pliku na zero.\n" " SEQUENTIAL ustawia podwójnÄ… domyÅ›lnÄ… wartość czytania z wyprzedzeniem.\n" " WILLNEED wymusza maksymalne czytanie z wyprzedzeniem.\n" "\n" #: .././io/madvise.c:97 .././io/mincore.c:57 #, c-format msgid "length argument too large -- %lld\n" msgstr "zbyt duży argument bÄ™dÄ…cy dÅ‚ugoÅ›ciÄ… - %lld\n" #: .././io/madvise.c:126 msgid "[-drsw] [off len]" msgstr "[-drsw] [offset dÅ‚ugość]" #: .././io/madvise.c:127 msgid "give advice about use of memory" msgstr "doradzenie w sprawie użycia pamiÄ™ci" #: .././io/mincore.c:91 .././io/mincore.c:101 #, c-format msgid "0x%lx %lu pages (%llu : %lu)\n" msgstr "0x%lx %lu stron (%llu : %lu)\n" #: .././io/mincore.c:121 msgid "[off len]" msgstr "[offset dÅ‚ugość]" #: .././io/mincore.c:122 msgid "find mapping pages that are memory resident" msgstr "odnalezienie stron odwzorowaÅ„ przechowywanych w pamiÄ™ci" #: .././io/mmap.c:82 #, c-format msgid "offset (%lld) is before start of mapping (%lld)\n" msgstr "offset (%lld) przed poczÄ…tkiem odwzorowania (%lld)\n" #: .././io/mmap.c:88 #, c-format msgid "offset (%lld) is beyond end of mapping (%lld)\n" msgstr "offset (%lld) za koÅ„cem odwzorowania (%lld)\n" #: .././io/mmap.c:93 #, c-format msgid "range (%lld:%lld) is beyond mapping (%lld:%ld)\n" msgstr "przedziaÅ‚ (%lld:%lld) poza odwzorowaniem (%lld:%ld)\n" #: .././io/mmap.c:99 #, c-format msgid "offset address (%p) is not page aligned\n" msgstr "adres offsetu (%p) nie jest wyrównany do rozmiaru strony\n" #: .././io/mmap.c:139 #, c-format msgid "" "\n" " maps a range within the current file into memory\n" "\n" " Example:\n" " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n" "\n" " Memory maps a range of a file for subsequent use by other xfs_io commands.\n" " With no arguments, mmap shows the current mappings. The current mapping\n" " can be set by using the single argument form (mapping number or address).\n" " If two arguments are specified (a range), a new mapping is created and the\n" " following options are available:\n" " -r -- map with PROT_READ protection\n" " -w -- map with PROT_WRITE protection\n" " -x -- map with PROT_EXEC protection\n" " -S -- map with MAP_SYNC and MAP_SHARED_VALIDATE flags\n" " -s -- first do mmap(size)/munmap(size), try to reserve some free " "space\n" " If no protection mode is specified, all are used by default.\n" "\n" msgstr "" "\n" " odwzorowanie przedziaÅ‚u z bieżącego pliku w pamiÄ™ci\n" "\n" "PrzykÅ‚ad:\n" " 'mmap -rw 0 1m' - odwzorowuje 1MB od poczÄ…tku bieżącego pliku\n" "\n" " mmap odwzorowuje w pamiÄ™ci przedziaÅ‚ z pliku do dalszego wykorzystania " "przez\n" " inne polecenia xfs_io.\n" " Bez argumentów mmap pokazuje aktualne odwzorowania. Bieżące odwzorowanie\n" " można ustawić przy użyciu formy jednoargumentowej (mmap numer lub adres).\n" " JeÅ›li podano dwa argumenty (przedziaÅ‚), tworzone jest nowe odwzorowanie\n" " i dostÄ™pne sÄ… nastÄ™pujÄ…ce opcje:\n" " -r - odwzorowanie z ochronÄ… PROT_READ\n" " -w - odwzorowanie z ochronÄ… PROT_WRITE\n" " -x - odwzorowanie z ochronÄ… PROT_EXEC\n" " -S - odwzorowanie z flagami MAP_SYNC i MAP_SHARED_VALIDATE\n" " -s - najpierw wykonanie mmap(rozmiar)/munmap(rozmiar) i próba\n" " zarezerwowania wolnego miejsca\n" " JeÅ›li nie podano trybu ochrony, domyÅ›lnie używane sÄ… wszystkie.\n" "\n" #: .././io/mmap.c:292 #, c-format msgid "" "\n" " flushes a range of bytes in the current memory mapping\n" "\n" " Writes all modified copies of pages over the specified range (or entire\n" " mapping if no range specified) to their backing storage locations. Also,\n" " optionally invalidates so that subsequent references to the pages will be\n" " obtained from their backing storage locations (instead of cached copies).\n" " -a -- perform asynchronous writes (MS_ASYNC)\n" " -i -- invalidate mapped pages (MS_INVALIDATE)\n" " -s -- perform synchronous writes (MS_SYNC)\n" "\n" msgstr "" "\n" " zrzucenie przedziaÅ‚u bajtów w bieżącym odwzorowaniu pamiÄ™ci\n" "\n" " msync zapisuje wszystkie zmodyfikowane kopie stron z podanego przedziaÅ‚u\n" " (lub caÅ‚ego odwzorowania, jeÅ›li nie podano przedziaÅ‚u) do miejsca\n" " przechowywania danych. Opcjonalnie unieważnia bufor, żeby dalsze odwoÅ‚ania\n" " do tych stron odbywaÅ‚y siÄ™ z miejsca przechowywania danych (zamiast kopii\n" " w pamiÄ™ci podrÄ™cznej).\n" " -a - wykonanie zapisu asynchronicznego (MS_ASYNC)\n" " -i - unieważnienie odwzorowanych stron (MS_INVALIDATE)\n" " -s - wykonanie zapisu synchronicznego (MS_SYNC)\n" "\n" #: .././io/mmap.c:368 #, c-format msgid "" "\n" " reads a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n" "\n" " Accesses a range of the current memory mapping, optionally dumping it to\n" " the standard output stream (with -v option) for subsequent inspection.\n" " -f -- verbose mode, dump bytes with offsets relative to start of file.\n" " -r -- reverse order; start accessing from the end of range, moving " "backward\n" " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n" " The accesses are performed sequentially from the start offset by default.\n" " Notes:\n" " References to whole pages following the end of the backing file results\n" " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n" " on various filesystem conditions, including quota exceeded errors, and\n" " for physical device errors (such as unreadable disk blocks). No attempt\n" " has been made to catch signals at this stage...\n" "\n" msgstr "" "\n" " odczytanie przedziaÅ‚u bajtów w bieżącym odwzorowaniu pamiÄ™ci\n" "\n" " PrzykÅ‚ad:\n" " 'mread -v 512 20' - zrzucenie 20 bajtów odczytanych od 512 bajtu\n" " w odwzorowaniu\n" "\n" " mread odwoÅ‚uje siÄ™ do przedziaÅ‚u bieżącego odwzorowania pamiÄ™ci, " "opcjonalnie\n" " zrzucajÄ…c go na strumieÅ„ standardowego wyjÅ›cia (z opcjÄ… -v) do dalszych " "badaÅ„.\n" " -f - tryb szczegółowy, zrzucenie bajtów z offsetami wzglÄ™dem poczÄ…tku " "pliku.\n" " -r - odwrotna kolejność; dostÄ™p poczÄ…wszy od koÅ„ca przedziaÅ‚u do poczÄ…tku.\n" " -v - tryb szczegółowy, zrzucenie bajtów z offsetami wzglÄ™dem poczÄ…tku\n" " odwzorowania.\n" " DostÄ™py sÄ… wykonywane sekwencyjnie, domyÅ›lnie od offsetu poczÄ…tkowego.\n" " Uwagi:\n" " OdwoÅ‚ania do caÅ‚ych stron za koÅ„cem pliku powodujÄ… w efekcie sygnaÅ‚ " "SIGBUS.\n" " SygnaÅ‚y SIGBUS mogÄ… być wywoÅ‚ane także przy różnych zdarzeniach " "zwiÄ…zanych\n" " z systemem plików, włącznie z błędami przekroczenia limitów (quota) oraz\n" " fizycznymi błędami urzÄ…dzenia (takimi jak nieczytelne bloki dysku). Na " "tym\n" " etapie nie ma prób wyÅ‚apania sygnałów...\n" "\n" #: .././io/mmap.c:532 #, c-format msgid "" "\n" " dirties a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n" "\n" " Stores a byte into memory for a range within a mapping.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -S -- use an alternate seed character\n" " -r -- reverse order; start storing from the end of range, moving backward\n" " The stores are performed sequentially from the start offset by default.\n" "\n" msgstr "" "\n" " zmiana przedziaÅ‚u bajtów w bieżącym odwzorowaniu pamiÄ™ci\n" "\n" " PrzykÅ‚ad:\n" " 'mwrite 512 20' - zapisuje 20 bajtów od 512 bajtu w bieżącym odwzorowaniu.\n" "\n" " mwrite zapisuje bajt do przedziaÅ‚u pamiÄ™ci w ramach odwzorowania.\n" " DomyÅ›lnie zapisywanÄ… wartoÅ›ciÄ… jest 'X', powtarzane do wypeÅ‚nienia " "przedziaÅ‚u.\n" " -S - użycie alternatywnego znaku\n" " -r - odwrotna kolejność; rozpoczÄ™cie zapisywania od koÅ„ca przedziaÅ‚u do\n" " poczÄ…tku\n" " Zapisy sÄ… wykonywane kolejno, domyÅ›lnie od offsetu poczÄ…tkowego.\n" "\n" #: .././io/mmap.c:568 .././io/pread.c:441 .././io/pwrite.c:349 #: .././io/pwrite.c:378 #, c-format msgid "non-numeric seed -- %s\n" msgstr "nieliczbowy zarodek - %s\n" #: .././io/mmap.c:620 #, c-format msgid "" "\n" " resizes the current memory mapping\n" "\n" " Examples:\n" " 'mremap 8192' - resizes the current mapping to 8192 bytes.\n" "\n" " Resizes the mapping, growing or shrinking from the current size.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -f -- use MREMAP_FIXED flag to mremap on new_address\n" " -m -- use the MREMAP_MAYMOVE flag\n" "\n" msgstr "" "\n" " zmiana bieżącego odwzorowania w pamiÄ™ci\n" "\n" " PrzykÅ‚ady:\n" " 'mremap 8192' - zmiana bieżącego odwzorowania na 8192 bajty.\n" "\n" " mremap zmienia odwzorowanie, zwiÄ™kszajÄ…c lub zmniejszajÄ…c w stosunku do\n" " bieżącego rozmiaru. DomyÅ›lnÄ… zapisanÄ… wartoÅ›ciÄ… jest 'X', powtarzane do\n" " wypeÅ‚nienia podanego rozmiaru.\n" " -f - użycie flagi MREMAP_FIXED do wykonania mremap na " "nowy_adres\n" " -m - użycie flagi MREMAP_MAYMOVE\n" "\n" #: .././io/mmap.c:698 msgid "[N] | [-rwxS] [-s size] [off len]" msgstr "[N] | [-rwxS] [-s rozmiar] [offset dÅ‚ugość]" #: .././io/mmap.c:700 msgid "mmap a range in the current file, show mappings" msgstr "odwzorowanie przedziaÅ‚u w bieżącym pliku, pokazanie odwzorowaÅ„" #: .././io/mmap.c:709 msgid "[-r] [off len]" msgstr "[-r] [offset dÅ‚ugość]" #: .././io/mmap.c:711 msgid "reads data from a region in the current memory mapping" msgstr "odczyt danych z regionu w bieżącym odwzorowaniu pamiÄ™ci" #: .././io/mmap.c:720 msgid "[-ais] [off len]" msgstr "[-ais] [offset dÅ‚ugość]" #: .././io/mmap.c:721 msgid "flush a region in the current memory mapping" msgstr "zrzucenie regionu w bieżącym odwzorowaniu pamiÄ™ci" #: .././io/mmap.c:730 msgid "unmaps the current memory mapping" msgstr "usuniÄ™cie bieżącego odwzorowania pamiÄ™ci" #: .././io/mmap.c:738 msgid "[-r] [-S seed] [off len]" msgstr "[-r] [-S wartość] [offset dÅ‚ugość]" #: .././io/mmap.c:740 msgid "writes data into a region in the current memory mapping" msgstr "zapis danych do regionu w bieżącym odwzorowaniu pamiÄ™ci" #: .././io/mmap.c:750 msgid "[-m|-f ] newsize" msgstr "[-m|-f ] nowy_rozmiar" #: .././io/mmap.c:752 msgid "alters the size of the current memory mapping" msgstr "zmiana rozmiary bieżącego odwzorowania pamiÄ™ci" #: .././io/open.c:176 #, c-format msgid "" "\n" " opens a new file in the requested mode\n" "\n" " Example:\n" " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n" "\n" " Opens a file for subsequent use by all of the other xfs_io commands.\n" " With no arguments, open uses the stat command to show the current file.\n" " -a -- open with the O_APPEND flag (append-only mode)\n" " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n" " -f -- open with O_CREAT (create the file if it doesn't exist)\n" " -m -- permissions to use in case a new file is created (default 0600)\n" " -n -- open with O_NONBLOCK\n" " -r -- open with O_RDONLY, the default is O_RDWR\n" " -s -- open with O_SYNC\n" " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n" " -R -- mark the file as a realtime XFS file immediately after opening it\n" " -T -- open with O_TMPFILE (create a file not visible in the namespace)\n" " Note1: usually read/write direct IO requests must be blocksize aligned;\n" " some kernels, however, allow sectorsize alignment for direct IO.\n" " Note2: the bmap for non-regular files can be obtained provided the file\n" " was opened correctly (in particular, must be opened read-only).\n" "\n" msgstr "" "\n" " otwarcie nowego pliku w żądanym trybie\n" "\n" " PrzykÅ‚ad:\n" " 'open -cd /tmp/data' - utworzenie/otwarcie pliku danych do odczytu i " "zapisu\n" " z bezpoÅ›rednim we/wy\n" "\n" " open otwiera plik do późniejszego wykorzystania przez wszystkie inne " "polecenia\n" " xfs_io.\n" " Bez argumentów używa polecenia stat do pokazania bieżącego pliku.\n" " -a - otwarcie z flagÄ… O_APPEND (w trybie tylko dopisywania)\n" " -d - otwarcie z flagÄ… O_DIRECT (niebuforowane we/wy, ograniczenia " "wyrównania)\n" " -f - otwarcie z flagÄ… O_CREAT (utworzenie pliku jeÅ›li nie istnieje)\n" " -m - uprawnienia do użycia w przypadku tworzenia pliku (domyÅ›lnie 0600)\n" " -n - otwarcie z flagÄ… O_NONBLOCK\n" " -r - otwarcie z flagÄ… O_RDONLY (domyÅ›lne jest O_RDWR)\n" " -s - otwarcie z flagÄ… O_SYNC\n" " -t - otwarcie z flagÄ… O_TRUNC (uciÄ™cie do zerowej dÅ‚ugoÅ›ci jeÅ›li istnieje)\n" " -R - oznaczenie pliku jako realtime na XFS-ie zaraz po otwarciu\n" " -T - otwarcie z flagÄ… O_TMPFILE (utworzenie pliku niewidocznego w " "przestrzni\n" " nazw)\n" " Uwaga1: zwykle żądania bezpoÅ›redniego we/wy muszÄ… być wyrównane do " "rozmiaru\n" " bloku; niektóre jÄ…dra pozwalajÄ… na wyrównanie do rozmiaru sektora\n" " Uwaga2: bmap dla plików innych niż zwykÅ‚e można uzyskać pod warunkiem, że\n" " plik zostanie poprawnie otwarty (w szczególnoÅ›ci tylko do " "odczytu).\n" "\n" #: .././io/open.c:269 #, c-format msgid "-T and -r options are incompatible\n" msgstr "Opcje -T i -r nie sÄ… zgodne ze sobÄ…\n" #: .././io/open.c:324 #, c-format msgid "" "\n" " displays the project identifier associated with the current path\n" "\n" " Options:\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, but only list projects on directories\n" "\n" msgstr "" "\n" " wyÅ›wietlenie identyfikatora projektu zwiÄ…zanego z bieżącÄ… Å›cieżkÄ…\n" "\n" " Opcje:\n" " -R - rekurencyjne zagłębianie siÄ™ (przydatne kiedy bieżący plik jest " "katalogiem)\n" " -D - rekurencyjne zagłębianie siÄ™, ale wypisywanie projektów tylko " "katalogów\n" "\n" #: .././io/open.c:390 #, c-format msgid "projid = %u\n" msgstr "projid = %u\n" #: .././io/open.c:398 #, c-format msgid "" "\n" " modifies the project identifier associated with the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying projects on directories\n" "\n" msgstr "" "\n" " modyfikacja identyfikatora projektu zwiÄ…zanego z bieżącÄ… Å›cieżkÄ…\n" "\n" " -R - rekurencyjne zagłębianie siÄ™ (przydatne kiedy bieżący plik jest " "katalogiem)\n" " -D - rekurencyjne zagłębianie siÄ™, ale zmiana projektów tylko katalogów\n" "\n" #: .././io/open.c:457 #, c-format msgid "invalid project ID -- %s\n" msgstr "nieprawidÅ‚owy ID projektu - %s\n" #: .././io/open.c:473 #, c-format msgid "" "\n" " report or modify preferred extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying extsize on directories\n" "\n" msgstr "" "\n" " odczyt lub zmiana preferowanego rozmiaru ekstentu (w bajtach) dla bieżącej\n" " Å›cieżki\n" "\n" " -R - rekurencyjne zagłębianie siÄ™ (przydatne kiedy bieżący plik jest " "katalogiem)\n" " -D - rekurencyjne zagłębianie siÄ™, ale zmiana extsize tylko katalogów\n" "\n" #: .././io/open.c:602 #, c-format msgid "non-numeric extsize argument -- %s\n" msgstr "nieliczbowy argument extsize - %s\n" #: .././io/open.c:625 #, c-format msgid "" "\n" "Query physical information about an inode\n" " Default:\t-- Return 1 if any inode number greater than 32 bits exists in\n" "\t\t the filesystem, or 0 if none exist\n" " num\t\t-- Return inode number [num] if in use, or 0 if not in use\n" " -n num\t-- Return the next used inode after [num]\n" " -v\t\t-- Verbose mode - display returned inode number's size in bits\n" "\n" msgstr "" "\n" "Odpytanie o fizyczne informacje dotyczÄ…ce i-wÄ™zÅ‚a\n" " DomyÅ›lnie: - zwraca 1, jeÅ›li numer i-wÄ™zÅ‚a wiÄ™kszy niż 32 bity istnieje\n" " w systemie plików, 0 jeÅ›li nie\n" " num - zwraca numer i-wÄ™zÅ‚a [num], jeÅ›li jest w użyciu, 0 jeÅ›li nie\n" " -n num - zwracan nastÄ™pny używany i-wÄ™zeÅ‚ po [num]\n" " -v - tryb szczegółowy - wyÅ›wietla rozmiar zwracanego i-wÄ™zÅ‚a w bitach\n" "\n" #: .././io/open.c:708 #, c-format msgid "%s is not a numeric inode value\n" msgstr "%s nie jest liczbowÄ… wartoÅ›ciÄ… i-wÄ™zÅ‚a\n" #: .././io/open.c:788 msgid "[-acdrstxT] [-m mode] [path]" msgstr "[-acdrstxT] [-m tryb] [Å›cieżka]" #: .././io/open.c:789 msgid "open the file specified by path" msgstr "otwarcie pliku okreÅ›lonego Å›cieżkÄ…" #: .././io/open.c:798 msgid "close the current open file" msgstr "zamkniÄ™cie bieżącego otwartego pliku" #: .././io/open.c:802 msgid "[-D | -R] projid" msgstr "[-D | -R] projid" #: .././io/open.c:807 msgid "change project identifier on the currently open file" msgstr "zmiana identyfikatora projektu aktualnie otwartego pliku" #: .././io/open.c:812 msgid "[-D | -R]" msgstr "[-D | -R]" #: .././io/open.c:817 msgid "list project identifier set on the currently open file" msgstr "wypisanie identyfikatora projektu aktualnie otwartego pliku" #: .././io/open.c:822 msgid "[-D | -R] [extsize]" msgstr "[-D | -R] [rozmiar_ekstentu]" #: .././io/open.c:827 msgid "get/set preferred extent size (in bytes) for the open file" msgstr "" "pobranie/ustawienie preferowanego rozmiaru ekstentu (w bajtach) dla " "otwartego pliku" #: .././io/open.c:832 msgid "[-nv] [num]" msgstr "[-nv] [num]" #: .././io/open.c:837 msgid "Query inode number usage in the filesystem" msgstr "Zapytanie o wykorzystanie numeru i-wÄ™zÅ‚a w systemie plików" #: .././io/parent.c:48 #, c-format msgid "%s%s" msgstr "%s%s" #: .././io/parent.c:53 #, c-format msgid "inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n" msgstr "" "inode-path dla i-wÄ™zÅ‚a: %llu jest niepoprawna - Å›cieżka \"%s\" nie istnieje\n" #: .././io/parent.c:57 #, c-format msgid "path \"%s\" does not stat for inode: %llu; err = %s\n" msgstr "Å›cieżka \"%s\" nie pozwala na stat dla i-wÄ™zÅ‚a: %llu; błąd = %s\n" #: .././io/parent.c:66 #, c-format msgid "path \"%s\" found\n" msgstr "Å›cieżki \"%s\" nie znaleziono\n" #: .././io/parent.c:72 #, c-format msgid "inode-path for inode: %llu is incorrect - wrong inode#\n" msgstr "" "inode-path dla i-wÄ™zÅ‚a: %llu jest niepoprawna - niewÅ‚aÅ›ciwy numer i-wÄ™zÅ‚a\n" #: .././io/parent.c:76 .././io/parent.c:106 #, c-format msgid "ino mismatch for path \"%s\" %llu vs %llu\n" msgstr "niezgodność i-wÄ™zÅ‚a dla Å›cieżki \"%s\" %llu vs %llu\n" #: .././io/parent.c:84 #, c-format msgid "inode number match: %llu\n" msgstr "zgodność numeru i-wÄ™zÅ‚a: %llu\n" #: .././io/parent.c:94 #, c-format msgid "parent path \"%s\" does not stat: %s\n" msgstr "Å›cieżka nadrzÄ™dna \"%s\" nie pozwala na stat: %s\n" #: .././io/parent.c:102 #, c-format msgid "inode-path for inode: %llu is incorrect - wrong parent inode#\n" msgstr "" "inode-path dla i-wÄ™zÅ‚a: %llu jest niepoprawna - niewÅ‚aÅ›ciwy numer i-wÄ™zÅ‚a " "nadrzÄ™dnego\n" #: .././io/parent.c:115 #, c-format msgid "parent ino match for %llu\n" msgstr "zgodność numeru i-wÄ™zÅ‚a nadrzÄ™dnego dla %llu\n" #: .././io/parent.c:137 #, c-format msgid "parentpaths failed for ino %llu: %s\n" msgstr "parentpaths nie powiodÅ‚o siÄ™ dla i-wÄ™zÅ‚a %llu: %s\n" #: .././io/parent.c:148 #, c-format msgid "inode-path for inode: %llu is missing\n" msgstr "brak inode-path dla i-wÄ™zÅ‚a: %llu\n" #: .././io/parent.c:172 #, c-format msgid "can't stat mount point \"%s\": %s\n" msgstr "nie można wykonać stat na punkcie montowania \"%s\": %s\n" #: .././io/parent.c:193 #, c-format msgid "failed to get bulkstat information for inode %llu\n" msgstr "nie udaÅ‚o siÄ™ uzyskać informacji bulkstat dla i-wÄ™zÅ‚a %llu\n" #: .././io/parent.c:199 #, c-format msgid "failed to get valid bulkstat information for inode %llu\n" msgstr "" "nie udaÅ‚o siÄ™ uzyskać prawidÅ‚owych informacji bulkstat dla i-wÄ™zÅ‚a %llu\n" #: .././io/parent.c:211 #, c-format msgid "checking inode %llu\n" msgstr "sprawdzanie i-wÄ™zÅ‚a %llu\n" #: .././io/parent.c:226 #, c-format msgid "syssgi bulkstat failed: %s\n" msgstr "syssgi bulkstat nie powiodÅ‚o siÄ™: %s\n" #: .././io/parent.c:248 #, c-format msgid "unable to open \"%s\" for jdm: %s\n" msgstr "nie udaÅ‚o siÄ™ otworzyć \"%s\" dla jdm: %s\n" #: .././io/parent.c:258 #, c-format msgid "unable to allocate buffers: %s\n" msgstr "nie udaÅ‚o siÄ™ przydzielić buforów: %s\n" #: .././io/parent.c:268 #, c-format msgid "num errors: %d\n" msgstr "liczba błędów: %d\n" #: .././io/parent.c:270 #, c-format msgid "succeeded checking %llu inodes\n" msgstr "udaÅ‚o siÄ™ sprawdzić %llu i-wÄ™złów\n" #: .././io/parent.c:283 #, c-format msgid "p_ino = %llu\n" msgstr "p_ino = %llu\n" #: .././io/parent.c:284 #, c-format msgid "p_gen = %u\n" msgstr "p_gen = %u\n" #: .././io/parent.c:285 #, c-format msgid "p_reclen = %u\n" msgstr "p_reclen = %u\n" #: .././io/parent.c:287 #, c-format msgid "p_name = \"%s%s\"\n" msgstr "p_name = \"%s%s\"\n" #: .././io/parent.c:289 #, c-format msgid "p_name = \"%s\"\n" msgstr "p_name = \"%s\"\n" #: .././io/parent.c:311 #, c-format msgid "%s: failed path_to_fshandle \"%s\": %s\n" msgstr "%s: path_to_fshandle nie powiodÅ‚o siÄ™ dla \"%s\": %s\n" #: .././io/parent.c:319 #, c-format msgid "%s: path_to_handle failed for \"%s\"\n" msgstr "%s: path_to_handle nie powiodÅ‚o siÄ™ dla \"%s\"\n" #: .././io/parent.c:326 #, c-format msgid "%s: unable to allocate parent buffer: %s\n" msgstr "%s: nie udaÅ‚o siÄ™ przydzielić bufora nadrzÄ™dnego: %s\n" #: .././io/parent.c:347 #, c-format msgid "%s: %s call failed for \"%s\": %s\n" msgstr "%s: wywoÅ‚anie %s nie powiodÅ‚o siÄ™ dla \"%s\": %s\n" #: .././io/parent.c:356 #, c-format msgid "%s: inode-path is missing\n" msgstr "%s: brak inode-path\n" #: .././io/parent.c:388 #, c-format msgid "file argument, \"%s\", is not in a mounted XFS filesystem\n" msgstr "argument plikowy \"%s\" nie jest na zamontowanym systemie plików XFS\n" #: .././io/parent.c:428 #, c-format msgid "" "\n" " list the current file's parents and their filenames\n" "\n" " -c -- check the current file's file system for parent consistency\n" " -p -- list the current file's parents and their full paths\n" " -v -- verbose mode\n" "\n" msgstr "" "\n" " wypisanie rodziców bieżącego pliku i ich nazw\n" "\n" " -c - sprawdzenie systemu plików pod kÄ…tem spójnoÅ›ci rodziców pliku\n" " -p - wypisanie rodziców bieżącego pliku i ich peÅ‚nych Å›cieżek\n" " -v - tryb szczegółowy\n" "\n" #: .././io/parent.c:444 msgid "[-cpv]" msgstr "[-cpv]" #: .././io/parent.c:446 msgid "print or check parent inodes" msgstr "wypisanie lub sprawdzenie i-wÄ™złów nadrzÄ™dnych" #: .././io/pread.c:34 #, c-format msgid "" "\n" " reads a range of bytes in a specified block size from the given offset\n" "\n" " Example:\n" " 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n" "\n" " Reads a segment of the currently open file, optionally dumping it to the\n" " standard output stream (with -v option) for subsequent inspection.\n" " The reads are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different pattern is requested.\n" " -B -- read backwards through the range from offset (backwards N bytes)\n" " -F -- read forwards through the range of bytes from offset (default)\n" " -v -- be verbose, dump out buffers (used when reading forwards)\n" " -R -- read at random offsets in the range of bytes\n" " -Z N -- zeed the random number generator (used when reading randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" " -V N -- use vectored IO with N iovecs of blocksize each (preadv)\n" "\n" " When in \"random\" mode, the number of read operations will equal the\n" " number required to do a complete forward/backward scan of the range.\n" " Note that the offset within the range is chosen at random each time\n" " (an offset may be read more than once when operating in this mode).\n" "\n" msgstr "" "\n" " odczytanie przedziaÅ‚u bajtów w podanym rozmiarze bloku od podanego offsetu\n" "\n" " PrzykÅ‚ad:\n" " 'pread -v 512 20' - zrzucenie 20 bajtów odczytanych od 512 bajtu w pliku\n" "\n" " pread odczytuje segment aktualnie otwartego pliku, opcjonalnie zrzucajÄ…c\n" " zawartość na strumieÅ„ standardowego wyjÅ›cia (z opcjÄ… -v) dla dalszych " "badaÅ„.\n" " Odczyty sÄ… wykonywane sekwencyjnie blokami poczÄ…wszy od offsetu z " "rozmiarem\n" " bloku ustawianym przy użyciu opcji -b (domyÅ›lny rozmiar bloku to 4096 " "bajtów),\n" " chyba że zażądano innego schematu.\n" " -B - odczyt przedziaÅ‚u od tyÅ‚u poczÄ…wszy od offsetu (N bajtów do tyÅ‚u)\n" " -F - odczyt przedziaÅ‚u od przodu poczÄ…wszy od offsetu (domyÅ›lny)\n" " -v - tryb szczegółowy, zrzucenie bufora (przy odczycie od przodu)\n" " -R - odczyt losowych offsetów z przedziaÅ‚u bajtów\n" " -Z N - (\"zeed\") nakarmienie generatora liczb losowych (przy odczycie " "losowym)\n" " (nieztety opcje -s/-S pasujÄ…ce do \"seed\" byÅ‚y już zajÄ™te w " "pwrite)\n" " -V N - użycie wektorowego we/wy z N iovec, każdym o rozmiarze blocksize\n" " (preadv)\n" "\n" " W przypadku trybu losowego liczba operacji odczytu bÄ™dzie równa liczbie\n" " potrzebnej do peÅ‚nego przeskanowania od przodu lub od tyÅ‚u caÅ‚ego " "przedziaÅ‚u.\n" " Należy zauważyć, że offset w przedziale jest wybierany za każdym razem " "losowo\n" " (dowolny offset może być w tym trybie czytany wiÄ™cej niż raz).\n" "\n" #: .././io/pread.c:402 .././io/pwrite.c:307 #, c-format msgid "non-numeric bsize -- %s\n" msgstr "nieliczbowy rozmiar bloku - %s\n" #: .././io/pread.c:432 .././io/pwrite.c:363 #, c-format msgid "non-numeric vector count == %s\n" msgstr "nieliczbowa liczba wektorów - %s\n" #: .././io/pread.c:509 msgid "[-b bs] [-v] [-i N] [-FBR [-Z N]] off len" msgstr "[-b rozm_bloku] [-v] [-i N] [-FBR [-Z N]] offset dÅ‚ugość" #: .././io/pread.c:510 msgid "reads a number of bytes at a specified offset" msgstr "odczyt podanej liczby bajtów od podanego offsetu" #: .././io/prealloc.c:175 #, c-format msgid "" "\n" " modifies space associated with part of a file via fallocate\n" " Example:\n" " 'falloc 0 1m' - fills all holes within the first megabyte\n" "\n" " falloc uses the fallocate system call to alter space allocations in the\n" " open file. The following operations are supported:\n" " All the file offsets are in units of bytes.\n" " -c -- collapses the given range.\n" " -i -- inserts a hole into the given range of the file.\n" " -k -- do not change file size.\n" " -p -- unmap the given range from the file.\n" " -u -- unshare shared extents in the given range.\n" "\n" msgstr "" "\n" " modyfikacja miejsca powiÄ…zanego z częściÄ… pliku poprzez fallocate\n" " PrzykÅ‚ad:\n" " 'falloc 0 1m' - wypeÅ‚nienie wszystkich dziur w pierwszym megabajcie\n" "\n" " falloc wykorzustuje wywoÅ‚anie systemowe fallocate do zmiany przydzielonego\n" " miejsca w otwartym pliku. ObsÅ‚ugiwane sÄ… nastÄ™pujÄ…ce operacje:\n" " (wszystkie offsety plików sÄ… w bajtach)\n" " -c - wyciÄ™cie podanego przedziaÅ‚u.\n" " -i - wstawienie dziury w podanym przedziale pliku.\n" " -k - bez zmiany rozmiaru pliku.\n" " -p - odwiÄ…zane podanego przedziaÅ‚u z pliku.\n" " -u - rozdzielenie współdzielonych ekstentów w podanym przedziale.\n" "\n" #: .././io/prealloc.c:347 .././io/prealloc.c:355 .././io/prealloc.c:363 #: .././io/prealloc.c:371 .././io/prealloc.c:381 .././io/prealloc.c:408 #: .././io/prealloc.c:418 .././io/prealloc.c:428 .././io/prealloc.c:448 msgid "off len" msgstr "offset dÅ‚ugość" #: .././io/prealloc.c:348 msgid "allocates zeroed space for part of a file" msgstr "przydzielenie wyzerowanej przestrzeni dla części pliku" #: .././io/prealloc.c:356 msgid "frees space associated with part of a file" msgstr "zwolnienie miejsca zwiÄ…zanego z częściÄ… pliku" #: .././io/prealloc.c:365 msgid "reserves space associated with part of a file" msgstr "zarezerwowanie miejsca zwiÄ…zanego z częściÄ… pliku" #: .././io/prealloc.c:374 msgid "frees reserved space associated with part of a file" msgstr "zwolnienie zarezerwowanego miejsca zwiÄ…zanego z częściÄ… pliku" #: .././io/prealloc.c:383 msgid "Converts the given range of a file to allocated zeros" msgstr "Zamiana podanego przedziaÅ‚u pliku na przydzielone zera" #: .././io/prealloc.c:397 msgid "[-c] [-k] [-p] [-u] off len" msgstr "[-c] [-k] [-p] [-u] offset dÅ‚ugość" #: .././io/prealloc.c:399 msgid "allocates space associated with part of a file via fallocate" msgstr "przydzielenie miejsca powiÄ…zanego z częściÄ… pliku przez fallocate" #: .././io/prealloc.c:410 msgid "de-allocates space associated with part of a file via fallocate" msgstr "zwolnienie miejsca powiÄ…zanego z częściÄ… pliku przez fallocate" #: .././io/prealloc.c:420 msgid "de-allocates space and eliminates the hole by shifting extents" msgstr "zwolnienie miejsca i usuniÄ™cie dziury poprzez przesuniÄ™cie ekstentów" #: .././io/prealloc.c:430 msgid "creates new space for writing within file by shifting extents" msgstr "" "utworzenie nowego miejsca na zapis wewnÄ…trz pliku poprzez przesuniÄ™cie " "ekstentów" #: .././io/prealloc.c:438 msgid "[-k] off len" msgstr "[-k] offset dÅ‚ugość" #: .././io/prealloc.c:440 msgid "zeroes space and eliminates holes by preallocating" msgstr "wyzerowanie miejsca i usuniÄ™cie dziur poprzez prealokacjÄ™" #: .././io/prealloc.c:450 msgid "unshares shared blocks within the range" msgstr "rozdzielenie współdzielonych bloków o podanym przedziale" #: .././io/pwrite.c:31 #, c-format msgid "" "\n" " writes a range of bytes (in block size increments) from the given offset\n" "\n" " Example:\n" " 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Writes into a segment of the currently open file, using either a buffer\n" " filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n" " The writes are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different write pattern is requested.\n" " -S -- use an alternate seed number for filling the write buffer\n" " -i -- input file, source of data to write (used when writing forward)\n" " -d -- open the input file for direct IO\n" " -s -- skip a number of bytes at the start of the input file\n" " -w -- call fdatasync(2) at the end (included in timing results)\n" " -W -- call fsync(2) at the end (included in timing results)\n" " -B -- write backwards through the range from offset (backwards N bytes)\n" " -F -- write forwards through the range of bytes from offset (default)\n" " -O -- perform pwrite call once and return (maybe partial) bytes written\n" " -R -- write at random offsets in the specified range of bytes\n" " -Z N -- zeed the random number generator (used when writing randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" " -V N -- use vectored IO with N iovecs of blocksize each (pwritev)\n" " -N -- Perform the pwritev2() with RWF_NOWAIT\n" "\n" msgstr "" "\n" " zapisanie przedziaÅ‚u bajtów (w podanym rozmiarze bloku) od podanego " "offsetu\n" "\n" " PrzykÅ‚ad:\n" " 'pwrite 512 20' - zapisanie 20 bajtów od offsetu 512 bajtów w otwartym " "pliku\n" "\n" " pwrite zapisuje segment aktualnie otwartego pliku, używajÄ…c bufora " "wypeÅ‚nionego\n" " ustawionym wzorcem (0xcdcdcdcd) lub danymi odczytanymi z pliku " "wejÅ›ciowego.\n" " Zapisy sÄ… wykonywane sekwencyjnie blokami poczÄ…wszy od offsetu z rozmiarem\n" " bloku ustawianym przy użyciu opcji -b (domyÅ›lny rozmiar bloku to 4096 " "bajtów),\n" " chyba że zażądano innego schematu.\n" " -S - użycie innej liczby do wypeÅ‚nienia bufora zapisu\n" " -i - plik wejÅ›ciowy, źródÅ‚o danych do zapisania (przy pisaniu od przodu)\n" " -d - otwarcie pliku wejÅ›ciowego dla bezpoÅ›redniego we/wy\n" " -s - pominiÄ™cie podanej liczby bajtów od poczÄ…tku pliku wejÅ›ciowego\n" " -w - wywoÅ‚anie fdatasync(2) na koÅ„cu (wliczane w wyniki czasowe)\n" " -W - wywoÅ‚anie fsync(2) na koÅ„cu (wliczane w wyniki czasowe)\n" " -B - zapis przedziaÅ‚u od tyÅ‚u poczÄ…wszy od offsetu (N bajtów do tyÅ‚u)\n" " -F - zapis przedziaÅ‚u od przodu poczÄ…wszy od offsetu (domyÅ›lny)\n" " -O - jednorazowe wywoÅ‚anie pwrite i zwrócenie (ew. niepeÅ‚nej) liczby\n" " zapisanych bajtów\n" " -R - zapis losowych offsetów z przedziaÅ‚u bajtów\n" " -Z N - (\"zeed\") nakarmienie generatora liczb losowych (przy zapisie " "losowym)\n" " (niestety opcje -s/-S pasujÄ…ce do \"seed\" byÅ‚y już zajÄ™te w " "pwrite)\n" " -V N - użycie wektorowego we/wy z N iovec, każdym o rozmiarze blocksize\n" " (pwritev)\n" " -N - wykonanie pwritev2() z RWF_NOWAIT\n" "\n" #: .././io/pwrite.c:342 #, c-format msgid "non-numeric skip -- %s\n" msgstr "nieliczbowy liczba bajtów do pominiÄ™cia - %s\n" #: .././io/pwrite.c:385 #, c-format msgid "%s: command -%c not supported\n" msgstr "%s: polecenie -%c nie jest obsÅ‚ugiwane\n" #: .././io/pwrite.c:472 msgid "" "[-i infile [-dwNOW] [-s skip]] [-b bs] [-S seed] [-FBR [-Z N]] [-V N] off len" msgstr "" "[-i plik_wej [-dwNOW] [-s do_pominiÄ™cia]] [-b rozm_bloku] [-S zarodek] [-FBR " "[-Z N]] [-V N] offset dÅ‚ugość" #: .././io/pwrite.c:474 msgid "writes a number of bytes at a specified offset" msgstr "zapis podanej liczby bajtów od podanego offsetu" #: .././io/readdir.c:198 #, c-format msgid "read %llu bytes from offset %lld\n" msgstr "odczytano %llu bajtów z offsetu %lld\n" #: .././io/readdir.c:199 #, c-format msgid "%s, %d ops, %s (%s/sec and %.4f ops/sec)\n" msgstr "%s, %d operacji; %s (%s/sek i %.4f operacji/sek)\n" #: .././io/readdir.c:212 msgid "[-v][-o offset][-l length]" msgstr "[-v][-o offset][-l dÅ‚ugość]" #: .././io/readdir.c:213 msgid "read directory entries" msgstr "odczyt wpisów katalogu" #: .././io/reflink.c:32 #, c-format msgid "" "\n" " Links a range of bytes (in block size increments) from a file into a range\n" " of bytes in the open file. The contents of both file ranges must match.\n" "\n" " Example:\n" " 'dedupe some_file 0 4096 32768' - links 32768 bytes from some_file at\n" " offset 0 to into the open file at\n" " position 4096\n" "\n" " Reflink a range of blocks from a given input file to the open file. Both\n" " files share the same range of physical disk blocks; a write to the shared\n" " range of either file should result in the write landing in a new block and\n" " that range of the file being remapped (i.e. copy-on-write). Both files\n" " must reside on the same filesystem, and the contents of both ranges must\n" " match.\n" msgstr "" "\n" " DowiÄ…zanie zakresu bajtów (o granicach podzielnych przez rozmiar bloku)\n" " do zakresu bajtów w otwartym pliku. Zawartość obu zakresów plików musi być\n" " taka sama.\n" "\n" " PrzykÅ‚ad:\n" " 'dedupe plik1 0 4096 32768' - dowiÄ…zanie 32768 bajtów z pliku1 od offsetu " "0\n" " do otwartego pliku na pozycji 4096\n" "\n" " dedupe dowiÄ…zuje zakres bloków z podanego pliku wejÅ›ciowego do otwartego\n" " pliku. Oba pliki współdzielÄ… ten sam zakres fizycznych bloków na dysku; " "zapis\n" " do współdzielonego obszaru dowolnego pliku bÄ™dzie skutkowaÅ‚ zapisem do " "nowego\n" " bloku i zmianÄ… odwzorowania tego obszaru pliku (czyli copy-on-write). Oba\n" " pliki muszÄ… siÄ™ mieÅ›cić na tym samym systemie plików, a zawartość obu " "zakresów\n" " musi być taka sama.\n" #: .././io/reflink.c:87 msgid "Extents did not match." msgstr "Ekstenty nie sÄ… takie same." #: .././io/reflink.c:141 .././io/reflink.c:264 #, c-format msgid "non-numeric src offset argument -- %s\n" msgstr "nieliczbowy argument bÄ™dÄ…cy offsetem źródÅ‚owym - %s\n" #: .././io/reflink.c:147 .././io/reflink.c:270 #, c-format msgid "non-numeric dest offset argument -- %s\n" msgstr "nieliczbowy argument bÄ™dÄ…cy offsetem docelowym - %s\n" #: .././io/reflink.c:153 .././io/reflink.c:276 #, c-format msgid "non-positive length argument -- %s\n" msgstr "niedodatni argument bÄ™dÄ…cy dÅ‚ugoÅ›ciÄ… - %s\n" #: .././io/reflink.c:178 #, c-format msgid "" "\n" " Links a range of bytes (in block size increments) from a file into a range\n" " of bytes in the open file. The two extent ranges need not contain " "identical\n" " data.\n" "\n" " Example:\n" " 'reflink some_file 0 4096 32768' - links 32768 bytes from some_file at\n" " offset 0 to into the open file at\n" " position 4096\n" " 'reflink some_file' - links all bytes from some_file into the open file\n" " at position 0\n" "\n" " Reflink a range of blocks from a given input file to the open file. Both\n" " files share the same range of physical disk blocks; a write to the shared\n" " range of either file should result in the write landing in a new block and\n" " that range of the file being remapped (i.e. copy-on-write). Both files\n" " must reside on the same filesystem.\n" msgstr "" "\n" " DowiÄ…zanie zakresu bajtów (o granicach podzielnych przez rozmiar bloku)\n" " do zakresu bajtów w otwartym pliku. Oba zakresy ekstentów nie muszÄ… " "zawierać\n" " takich samych danych.\n" "\n" " PrzykÅ‚ad:\n" " 'reflink plik1 0 4096 32768' - dowiÄ…zanie 32768 bajtów z pliku1 od offsetu " "0\n" " do otwartego pliku na pozycji 4096\n" " 'reflink plik1' - dowiÄ…zanie wszystkich bajtów z pliku1 do otwartego pliku\n" " na pozycji 0\n" "\n" " reflink dowiÄ…zuje zakres bloków z podanego pliku wejÅ›ciowego do otwartego\n" " pliku. Oba pliki współdzielÄ… ten sam zakres fizycznych bloków na dysku; " "zapis\n" " do współdzielonego obszaru dowolnego pliku bÄ™dzie skutkowaÅ‚ zapisem do " "nowego\n" " bloku i zmianÄ… odwzorowania tego obszaru pliku (czyli copy-on-write). Oba\n" " pliki muszÄ… siÄ™ mieÅ›cić na tym samym systemie plików.\n" #: .././io/reflink.c:309 msgid "infile [src_off dst_off len]" msgstr "plik_wej [offset_źr offset_doc dÅ‚ugość]" #: .././io/reflink.c:311 msgid "reflinks an entire file, or a number of bytes at a specified offset" msgstr "dowiÄ…zanie caÅ‚ego pliku lub podanej liczby bajtów od podanego offsetu" #: .././io/reflink.c:323 msgid "infile src_off dst_off len" msgstr "plik_wej offset_źr offset_doc dÅ‚ugość" #: .././io/reflink.c:325 msgid "dedupes a number of bytes at a specified offset" msgstr "deduplikacja podanej liczby bajtów od podanego offsetu" #: .././io/resblks.c:38 #, c-format msgid "non-numeric argument -- %s\n" msgstr "nieliczbowy argument - %s\n" #: .././io/resblks.c:50 #, c-format msgid "reserved blocks = %llu\n" msgstr "zarezerwowane bloki = %llu\n" #: .././io/resblks.c:52 #, c-format msgid "available reserved blocks = %llu\n" msgstr "dostÄ™pne zarezerwowane bloki = %llu\n" #: .././io/resblks.c:65 msgid "[blocks]" msgstr "[bloki]" #: .././io/resblks.c:67 msgid "get and/or set count of reserved filesystem blocks" msgstr "" "pobranie i/lub ustawienie liczby zarezerwowanych bloków w systemie plików" #: .././io/scrub.c:77 #, c-format msgid "" "\n" " Scrubs a piece of XFS filesystem metadata. The first argument is the type\n" " of metadata to examine. Allocation group metadata types take one AG " "number\n" " as the second parameter. Inode metadata types act on the currently open " "file\n" " or (optionally) take an inode number and generation number to act upon as\n" " the second and third parameters.\n" "\n" " Example:\n" " 'scrub inobt 3' - scrub the inode btree in AG 3.\n" " 'scrub bmapbtd 128 13525' - scrubs the extent map of inode 128 gen 13525.\n" "\n" " Known metadata scrub types are:" msgstr "" "\n" " Doczyszczenie fragmentu metadanych systemu plików XFS. Pierwszy argument " "to\n" " typ metadanych do zbadania. Typy metadanych AG przyjmujÄ… jeden numer AG " "jako\n" " drugi parametr. Typy metadanych i-wÄ™złów dziaÅ‚ajÄ… na aktualnie otwartym " "pliku\n" " lub (opcjonalnie) przyjmujÄ… numer i-wÄ™zÅ‚a i numer generacji do dziaÅ‚ania " "jako\n" " drugi i trzeci parametr.\n" "\n" " PrzykÅ‚ad:\n" " 'scrub inobt 3' - doczyszczenie b-drzewa i-wÄ™zÅ‚a w AG 3.\n" " 'scrub bmapbtd 128 13525' - doczyszczenie mapy ekstentów i-wÄ™zÅ‚a 128 gen " "13525.\n" "\n" " Znane typy doczyszczanych metadanych to:" #: .././io/scrub.c:127 #, c-format msgid "Corruption detected.\n" msgstr "Wykryto uszkodzenie.\n" #: .././io/scrub.c:129 #, c-format msgid "Optimization possible.\n" msgstr "Możliwa optymalizacja.\n" #: .././io/scrub.c:131 #, c-format msgid "Cross-referencing failed.\n" msgstr "Tworzenie odsyÅ‚aczy nie powiodÅ‚o siÄ™.\n" #: .././io/scrub.c:133 #, c-format msgid "Corruption detected during cross-referencing.\n" msgstr "Przy tworzeniu odsyÅ‚aczy wykryto uszkodzenie.\n" #: .././io/scrub.c:135 #, c-format msgid "Scan was not complete.\n" msgstr "Skanowanie niekompletne.\n" #: .././io/scrub.c:170 #, c-format msgid "Unknown type '%s'.\n" msgstr "Nieznany typ '%s'.\n" #: .././io/scrub.c:183 #, c-format msgid "Bad inode number '%s'.\n" msgstr "Błędny numer i-wÄ™zÅ‚a '%s'.\n" #: .././io/scrub.c:190 #, c-format msgid "Bad generation number '%s'.\n" msgstr "Błędny numer generacji '%s'.\n" #: .././io/scrub.c:196 #, c-format msgid "Must specify inode number and generation.\n" msgstr "Trzeba podać numer i-wÄ™zÅ‚a i generacji.\n" #: .././io/scrub.c:203 #, c-format msgid "Must specify one AG number.\n" msgstr "Trzeba podać jeden numer AG.\n" #: .././io/scrub.c:209 #, c-format msgid "Bad AG number '%s'.\n" msgstr "Błędny numer AG '%s'.\n" #: .././io/scrub.c:217 #, c-format msgid "No parameters allowed.\n" msgstr "Parametry nie sÄ… dozwolone.\n" #: .././io/scrub.c:247 msgid "type [agno|ino gen]" msgstr "typ [agno|ino gen]" #: .././io/scrub.c:248 msgid "scrubs filesystem metadata" msgstr "doczyszczenie metadanych systemu plików" #: .././io/seek.c:32 #, c-format msgid "" "\n" " returns the next hole and/or data offset at or after the requested offset\n" "\n" " Example:\n" " 'seek -d 512'\t\t- offset of data at or following offset 512\n" " 'seek -a -r 0'\t- offsets of all data and hole in entire file\n" "\n" " Returns the offset of the next data and/or hole. There is an implied hole\n" " at the end of file. If the specified offset is past end of file, or there\n" " is no data past the specified offset, EOF is returned.\n" " -a\t-- return the next data and hole starting at the specified offset.\n" " -d\t-- return the next data starting at the specified offset.\n" " -h\t-- return the next hole starting at the specified offset.\n" " -r\t-- return all remaining type(s) starting at the specified offset.\n" " -s\t-- also print the starting offset.\n" "\n" msgstr "" "\n" " zwrócenie offsetu nastÄ™pnej dziury i/lub danych pod lub za żądanym " "offsetem\n" "\n" " PrzykÅ‚ady:\n" " 'seek -d 512' - offset danych pod lub za offsetem 512\n" " 'seek -a -r 0' - offsety wszystkich danych i dziur w caÅ‚ym pliku\n" "\n" " seek zwraca offset nastÄ™pnych danych i/lub dziury. Istnieje domyÅ›lna " "dziura\n" " na koÅ„cu pliku. JeÅ›li podany offset jest za koÅ„cem pliku lub nie ma danych\n" " za podanym offsetem, zwracany jest EOF.\n" " -a\t- nastÄ™pne dane i dziura od podanego offsetu\n" " -d\t- nastÄ™pne dane poczÄ…wszy od podanego offsetu\n" " -h\t- nastÄ™pna dziura poczÄ…wszy od podanego offsetu\n" " -r\t- wszystkie pozostaÅ‚e typy fragmentów od podanego offsetu\n" " -s\t- wypisane także offsetu poczÄ…tkowego\n" "\n" #: .././io/seek.c:229 msgid "-a | -d | -h [-r] off" msgstr "-a | -d | -h [-r] offset" #: .././io/seek.c:230 msgid "locate the next data and/or hole" msgstr "odnalezienie nastÄ™pnych danych i/lub dziury" #: .././io/sendfile.c:31 #, c-format msgid "" "\n" " transfer a range of bytes from the given offset between files\n" "\n" " Example:\n" " 'send -f 2 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Copies data between one file descriptor and another. Because this copying\n" " is done within the kernel, sendfile does not need to transfer data to and\n" " from user space.\n" " -f -- specifies an input file from which to source data to write\n" " -i -- specifies an input file name from which to source data to write.\n" " An offset and length in the source file can be optionally specified.\n" "\n" msgstr "" "\n" " przesÅ‚anie miÄ™dzy plikami przedziaÅ‚u bajtów od podanego offsetu\n" "\n" " PrzykÅ‚ad:\n" " 'send -f 2 512 20' - zapisanie 20 bajtów od 512 bajtu do otwartego pliku\n" "\n" " sendfile kopiuje dane miÄ™dzy jednym deskryptorem pliku a innym. Ponieważ " "to\n" " kopiowanie jest wykonywane przez jÄ…dro, sendfile nie potrzebuje przesyÅ‚ać\n" " danych do i z przestrzeni użytkownika.\n" " -f - podanie plików wejÅ›ciowego z którego dane majÄ… być czytane\n" " -i - podanie nazwy pliku wejÅ›ciowego z którego dane majÄ… być czytane\n" " Opcjonalnie można podać offset i dÅ‚ugość danych w pliku źródÅ‚owym.\n" "\n" #: .././io/sendfile.c:171 msgid "-i infile | -f N [off len]" msgstr "-i plik_wej | -f N [offset dÅ‚ugość]" #: .././io/sendfile.c:173 msgid "Transfer data directly between file descriptors" msgstr "PrzesÅ‚anie danych bezpoÅ›rednio miÄ™dzy deskryptorami plików" #: .././io/shutdown.c:58 msgid "[-f]" msgstr "[-f]" #: .././io/shutdown.c:60 msgid "shuts down the filesystem where the current file resides" msgstr "wyłączenie systemu plików na którym znajduje siÄ™ bieżący plik" #: .././io/stat.c:52 msgid "socket" msgstr "gniazdo" #: .././io/stat.c:54 .././repair/da_util.c:105 .././scrub/phase5.c:119 #: .././scrub/unicrash.c:374 msgid "directory" msgstr "katalog" #: .././io/stat.c:56 msgid "char device" msgstr "urzÄ…dzenie znakowe" #: .././io/stat.c:58 msgid "block device" msgstr "urzÄ…dzenie blokowe" #: .././io/stat.c:60 msgid "regular file" msgstr "plik zwykÅ‚y" #: .././io/stat.c:62 msgid "symbolic link" msgstr "dowiÄ…zanie symboliczne" #: .././io/stat.c:64 msgid "fifo" msgstr "potok" #: .././io/stat.c:95 .././io/stat.c:193 #, c-format msgid "fd.path = \"%s\"\n" msgstr "fd.path = \"%s\"\n" #: .././io/stat.c:96 #, c-format msgid "fd.flags = %s,%s,%s%s%s%s%s\n" msgstr "fd.flags = %s,%s,%s%s%s%s%s\n" #: .././io/stat.c:115 #, c-format msgid "fsxattr.xflags = 0x%x " msgstr "fsxattr.xflags = 0x%x " #: .././io/stat.c:117 #, c-format msgid "fsxattr.projid = %u\n" msgstr "fsxattr.projid = %u\n" #: .././io/stat.c:118 #, c-format msgid "fsxattr.extsize = %u\n" msgstr "fsxattr.extsize = %u\n" #: .././io/stat.c:119 #, c-format msgid "fsxattr.cowextsize = %u\n" msgstr "fsxattr.cowextsize = %u\n" #: .././io/stat.c:120 #, c-format msgid "fsxattr.nextents = %u\n" msgstr "fsxattr.nextents = %u\n" #: .././io/stat.c:121 #, c-format msgid "fsxattr.naextents = %u\n" msgstr "fsxattr.naextents = %u\n" #: .././io/stat.c:126 #, c-format msgid "dioattr.mem = 0x%x\n" msgstr "dioattr.mem = 0x%x\n" #: .././io/stat.c:127 #, c-format msgid "dioattr.miniosz = %u\n" msgstr "dioattr.miniosz = %u\n" #: .././io/stat.c:128 #, c-format msgid "dioattr.maxiosz = %u\n" msgstr "dioattr.maxiosz = %u\n" #: .././io/stat.c:166 .././io/stat.c:367 #, c-format msgid "stat.ino = %lld\n" msgstr "stat.ino = %lld\n" #: .././io/stat.c:167 .././io/stat.c:368 #, c-format msgid "stat.type = %s\n" msgstr "stat.type = %s\n" #: .././io/stat.c:168 .././io/stat.c:369 #, c-format msgid "stat.size = %lld\n" msgstr "stat.size = %lld\n" #: .././io/stat.c:169 .././io/stat.c:370 #, c-format msgid "stat.blocks = %lld\n" msgstr "stat.blocks = %lld\n" #: .././io/stat.c:171 .././io/stat.c:372 #, c-format msgid "stat.atime = %s" msgstr "stat.atime = %s" #: .././io/stat.c:172 .././io/stat.c:373 #, c-format msgid "stat.mtime = %s" msgstr "stat.mtime = %s" #: .././io/stat.c:173 .././io/stat.c:374 #, c-format msgid "stat.ctime = %s" msgstr "stat.ctime = %s" #: .././io/stat.c:197 #, c-format msgid "statfs.f_bsize = %lld\n" msgstr "statfs.f_bsize = %lld\n" #: .././io/stat.c:198 #, c-format msgid "statfs.f_blocks = %lld\n" msgstr "statfs.f_blocks = %lld\n" #: .././io/stat.c:199 #, c-format msgid "statfs.f_bavail = %lld\n" msgstr "statfs.f_bavail = %lld\n" #: .././io/stat.c:200 #, c-format msgid "statfs.f_files = %lld\n" msgstr "statfs.f_files = %lld\n" #: .././io/stat.c:201 #, c-format msgid "statfs.f_ffree = %lld\n" msgstr "statfs.f_ffree = %lld\n" #: .././io/stat.c:203 #, c-format msgid "statfs.f_flags = 0x%llx\n" msgstr "statfs.f_flags = 0x%llx\n" #: .././io/stat.c:211 #, c-format msgid "geom.bsize = %u\n" msgstr "geom.bsize = %u\n" #: .././io/stat.c:212 #, c-format msgid "geom.agcount = %u\n" msgstr "geom.agcount = %u\n" #: .././io/stat.c:213 #, c-format msgid "geom.agblocks = %u\n" msgstr "geom.agblocks = %u\n" #: .././io/stat.c:214 #, c-format msgid "geom.datablocks = %llu\n" msgstr "geom.datablocks = %llu\n" #: .././io/stat.c:216 #, c-format msgid "geom.rtblocks = %llu\n" msgstr "geom.rtblocks = %llu\n" #: .././io/stat.c:218 #, c-format msgid "geom.rtextents = %llu\n" msgstr "geom.rtextents = %llu\n" #: .././io/stat.c:220 #, c-format msgid "geom.rtextsize = %u\n" msgstr "geom.rtextsize = %u\n" #: .././io/stat.c:221 #, c-format msgid "geom.sunit = %u\n" msgstr "geom.sunit = %u\n" #: .././io/stat.c:222 #, c-format msgid "geom.swidth = %u\n" msgstr "geom.swidth = %u\n" #: .././io/stat.c:227 #, c-format msgid "counts.freedata = %llu\n" msgstr "counts.freedata = %llu\n" #: .././io/stat.c:229 #, c-format msgid "counts.freertx = %llu\n" msgstr "counts.freertx = %llu\n" #: .././io/stat.c:231 #, c-format msgid "counts.freeino = %llu\n" msgstr "counts.freeino = %llu\n" #: .././io/stat.c:233 #, c-format msgid "counts.allocino = %llu\n" msgstr "counts.allocino = %llu\n" #: .././io/stat.c:259 #, c-format msgid "" "\n" " Display extended file status.\n" "\n" " Options:\n" " -v -- More verbose output\n" " -r -- Print raw statx structure fields\n" " -m mask -- Specify the field mask for the statx call\n" " (can also be 'basic' or 'all'; default STATX_ALL)\n" " -D -- Don't sync attributes with the server\n" " -F -- Force the attributes to be sync'd with the server\n" "\n" msgstr "" "\n" " WyÅ›wietlenie rozszerzonego stanu pliku.\n" "\n" " Opcje:\n" " -v - bardziej szczegółowe wyjÅ›cie\n" " -r - wypisanie surowych pól struktury statx\n" " -m maska - okreÅ›lenie maski pól dla wywoÅ‚ania statx\n" " (może być też 'basic' lub 'all'; domyÅ›lnie STATX_ALL)\n" " -D - bez synchronizacji atrybutów z serwerem\n" " -F - wymuszenie synchronizacji atrybutów z serwerem\n" "\n" #: .././io/stat.c:329 #, c-format msgid "non-numeric mask -- %s\n" msgstr "nieliczbowa maska - %s\n" #: .././io/stat.c:376 #, c-format msgid "stat.btime = %s" msgstr "stat.btime = %s" #: .././io/stat.c:396 msgid "[-v|-r]" msgstr "[-v|-r]" #: .././io/stat.c:397 msgid "statistics on the currently open file" msgstr "statystyki dla aktualnie otwartego pliku" #: .././io/stat.c:404 msgid "[-v|-r][-m basic | -m all | -m ][-FD]" msgstr "[-v|-r][-m basic | -m all | -m ][-FD]" #: .././io/stat.c:405 msgid "extended statistics on the currently open file" msgstr "rozszerzone statystyki dla aktualnie otwartego pliku" #: .././io/stat.c:412 msgid "statistics on the filesystem of the currently open file" msgstr "statystyki dla systemu plików aktualnie otwartego pliku" #: .././io/sync.c:58 msgid "calls sync(2) to flush all in-core filesystem state to disk" msgstr "" "wywoÅ‚anie sync(2) aby zrzucić caÅ‚y stan systemu plików z pamiÄ™ci na dysk" #: .././io/sync.c:67 msgid "calls syncfs(2) to flush all in-core filesystem state to disk" msgstr "" "wywoÅ‚anie syncfs(2) aby zrzucić caÅ‚y stan systemu plików z pamiÄ™ci na dysk" #: .././io/sync_file_range.c:30 #, c-format msgid "" "\n" " Trigger specific writeback commands on a range of the current file\n" "\n" " With no options, the SYNC_FILE_RANGE_WRITE is implied.\n" " -a -- wait for IO to finish after writing (SYNC_FILE_RANGE_WAIT_AFTER).\n" " -b -- wait for IO to finish before writing (SYNC_FILE_RANGE_WAIT_BEFORE).\n" " -w -- write dirty data in range (SYNC_FILE_RANGE_WRITE).\n" "\n" msgstr "" "\n" " Wyzwolenie okreÅ›lonych poleceÅ„ zapisu w tle na pewnym zakresie bieżącego " "pliku\n" "\n" " Bez opcji przyjmowana jest operacja SYNC_FILE_RANGE_WRITE.\n" " -a - oczekiwanie na zakoÅ„czenie we/wy po zapisie " "(SYNC_FILE_RANGE_WAIT_AFTER).\n" " -b - oczekiwanie na zakoÅ„czenie we/wy przedtem " "(SYNC_FILE_RANGE_WAIT_BEFORE).\n" " -w - zapis zmodyfikowanych danych z zakresu (SYNC_FILE_RANGE_WRITE).\n" "\n" #: .././io/sync_file_range.c:101 msgid "[-abw] off len" msgstr "[-abw] offset dÅ‚ugość" #: .././io/sync_file_range.c:102 msgid "Control writeback on a range of a file" msgstr "Sterowanie zapisem w tle dla zakresu pliku" #: .././io/truncate.c:37 #, c-format msgid "non-numeric truncate argument -- %s\n" msgstr "nieliczbowy argument truncate - %s\n" #: .././io/truncate.c:57 msgid "off" msgstr "offset" #: .././io/truncate.c:59 msgid "truncates the current file at the given offset" msgstr "uciÄ™cie bieżącego pliku na podanym offsecie" #: .././io/utimes.c:30 #, c-format msgid "" "\n" " Update file atime and mtime of the current file with nansecond precision.\n" "\n" " Usage: utimes atime_sec atime_nsec mtime_sec mtime_nsec.\n" " *_sec: Seconds elapsed since 1970-01-01 00:00:00 UTC.\n" " *_nsec: Nanoseconds since the corresponding *_sec.\n" "\n" msgstr "" "\n" " Uaktualnienie atime i mtime bieżącego pliku z dokÅ‚adnoÅ›ciÄ… nanosekundowÄ….\n" "\n" " SkÅ‚adnia: utimes atime_sec atime_nsec mtime_sec mtime_nsec.\n" " *_sec: Sekundy od 1970-01-01 00:00:00 UTC.\n" " *_nsec: Nanosekundy od odpowiedniego *_sec.\n" "\n" #: .././io/utimes.c:76 msgid "atime_sec atime_nsec mtime_sec mtime_nsec" msgstr "atime_sec atime_nsec mtime_sec mtime_nsec" #: .././io/utimes.c:77 msgid "Update file times of the current file" msgstr "Uaktualnienie czasów dla bieżącego pliku" #: .././libfrog/avl64.c:1032 .././repair/avl.c:1011 #, c-format msgid "avl_insert: Warning! duplicate range [%llu,%llu]\n" msgstr "avl_insert: Uwaga! powtórzony przedziaÅ‚ [%llu,%llu]\n" #: .././libfrog/avl64.c:1227 .././repair/avl.c:1206 #, c-format msgid "Command [fpdir] : " msgstr "Polecenie [fpdir] : " #: .././libfrog/avl64.c:1236 .././repair/avl.c:1215 #, c-format msgid "end of range ? " msgstr "koniec przedziaÅ‚u? " #: .././libfrog/avl64.c:1247 .././repair/avl.c:1226 #, c-format msgid "Cannot find %d\n" msgstr "Nie można odnaleźć %d\n" #: .././libfrog/avl64.c:1260 .././repair/avl.c:1239 #, c-format msgid "size of range ? " msgstr "rozmiar przedziaÅ‚u? " #: .././libfrog/avl64.c:1271 .././repair/avl.c:1250 #, c-format msgid "End of range ? " msgstr "Koniec przedziaÅ‚u? " #: .././libfrog/avl64.c:1275 .././repair/avl.c:1254 #, c-format msgid "checklen 0/1 ? " msgstr "checklen 0/1 ? " #: .././libfrog/avl64.c:1282 .././repair/avl.c:1261 #, c-format msgid "Found something\n" msgstr "Znaleziono coÅ›\n" #: .././libfrog/paths.c:336 #, c-format msgid "%s: unable to extract mount options for \"%s\"\n" msgstr "%s: nie udaÅ‚o siÄ™ wydobyć opcji montowania dla \"%s\"\n" #: .././libfrog/paths.c:422 #, c-format msgid "%s: getmntinfo() failed: %s\n" msgstr "%s: getmntinfo() nie powiodÅ‚o siÄ™: %s\n" #: .././libfrog/paths.c:491 #, c-format msgid "%s: cannot setup path for mount %s: %s\n" msgstr "%s: nie można ustawić Å›cieżki dla montowania %s: %s\n" #: .././libfrog/paths.c:513 #, c-format msgid "%s: cannot find mount point for path `%s': %s\n" msgstr "%s: nie można znaleźć punktu montowania dla Å›cieżki `%s': %s\n" #: .././libfrog/paths.c:541 #, c-format msgid "%s: cannot setup path for project %s: %s\n" msgstr "%s: nie można ustawić Å›cieżki dla projektu %s: %s\n" #: .././libfrog/paths.c:582 #, c-format msgid "%s: cannot initialise path table: %s\n" msgstr "%s: nie można zainicjować tabeli Å›cieżek: %s\n" #: .././libfrog/paths.c:602 #, c-format msgid "%s: cannot setup path for project dir %s: %s\n" msgstr "%s: nie można ustawić Å›cieżki dla katalogu projektu %s: %s\n" #: .././libfrog/topology.c:165 #, c-format msgid "%s: %s appears to contain an existing filesystem (%s).\n" msgstr "%s: %s zdaje siÄ™ zawierać istniejÄ…cy system plików (%s).\n" #: .././libfrog/topology.c:169 #, c-format msgid "%s: %s appears to contain a partition table (%s).\n" msgstr "%s: %s zdaje siÄ™ zawierać tablicÄ™ partycji (%s).\n" #: .././libfrog/topology.c:173 #, c-format msgid "%s: %s appears to contain something weird according to blkid\n" msgstr "%s: %s zdaje siÄ™ zawierać coÅ› dziwnego wg blkid\n" #: .././libfrog/topology.c:182 #, c-format msgid "%s: probe of %s failed, cannot detect existing filesystem.\n" msgstr "" "%s: test %s nie powiódÅ‚ siÄ™, nie można wykryć istniejÄ…cego systemu plików.\n" #: .././libfrog/topology.c:204 #, c-format msgid "%s: Warning: trying to probe topology of a file %s!\n" msgstr "%s: uwaga: próba sprawdzenia topologii pliku %s!\n" #: .././libfrog/topology.c:245 #, c-format msgid "warning: device is not properly aligned %s\n" msgstr "uwaga: urzÄ…dzenie nie jest wÅ‚aÅ›ciwie wyrównane: %s\n" #: .././libfrog/topology.c:250 #, c-format msgid "Use -f to force usage of a misaligned device\n" msgstr "Można użyć -f do wymuszenia użycia źle wyrównanego urzÄ…dzenia\n" #: .././libfrog/topology.c:264 #, c-format msgid "warning: unable to probe device topology for device %s\n" msgstr "uwaga: nie udaÅ‚o siÄ™ odczytać topologii urzÄ…dzenia %s\n" #: .././libxcmd/command.c:95 #, c-format msgid "bad argument count %d to %s, expected at least %d arguments\n" msgstr "" "błędna liczba argumentów %d dla %s, oczekiwano co najmniej %d argumentów\n" #: .././libxcmd/command.c:99 #, c-format msgid "bad argument count %d to %s, expected %d arguments\n" msgstr "błędna liczba argumentów %d dla %s, oczekiwano %d argumentów\n" #: .././libxcmd/command.c:103 #, c-format msgid "bad argument count %d to %s, expected between %d and %d arguments\n" msgstr "" "błędna liczba argumentów %d dla %s, oczekiwano od %d do %d argumentów\n" #: .././libxcmd/command.c:202 #, c-format msgid "command \"%s\" not found\n" msgstr "nie znaleziono polecenia \"%s\"\n" #: .././libxcmd/command.c:239 #, c-format msgid "cannot strdup command '%s': %s\n" msgstr "nie można wykonać strdup na poleceniu '%s': %s\n" #: .././libxcmd/command.c:265 #, c-format msgid "%s %lld/%lld bytes at offset %lld\n" msgstr "odczytano %s %lld/%lld bajtów od offsetu %lld\n" #: .././libxcmd/command.c:267 #, c-format msgid "%s, %d ops; %s (%s/sec and %.4f ops/sec)\n" msgstr "%s, %d operacji; %s (%s/sek i %.4f operacji/sek)\n" #: .././libxcmd/quit.c:43 msgid "exit the program" msgstr "wyjÅ›cie z programu" #: .././libxfs/darwin.c:41 #, c-format msgid "%s: error opening the device special file \"%s\": %s\n" msgstr "%s: błąd podczas otwierania pliku specjalnego urzÄ…dzenia \"%s\": %s\n" #: .././libxfs/darwin.c:48 #, c-format msgid "%s: can't tell if \"%s\" is writable: %s\n" msgstr "%s: nie można stwierdzić czy \"%s\" jest zapisywalny: %s\n" #: .././libxfs/darwin.c:76 .././libxfs/freebsd.c:116 .././libxfs/irix.c:58 #: .././libxfs/linux.c:170 #, c-format msgid "%s: cannot stat the device file \"%s\": %s\n" msgstr "%s: nie można wykonać stat na pliku urzÄ…dzenia \"%s\": %s\n" #: .././libxfs/darwin.c:86 #, c-format msgid "%s: can't determine device size: %s\n" msgstr "%s: nie można okreÅ›lić rozmiaru urzÄ…dzenia: %s\n" #: .././libxfs/darwin.c:139 .././libxfs/freebsd.c:196 .././libxfs/irix.c:106 #: .././libxfs/linux.c:260 #, c-format msgid "%s: can't determine memory size\n" msgstr "%s: nie można okreÅ›lić rozmiaru pamiÄ™ci\n" #: .././libxfs/freebsd.c:49 .././libxfs/linux.c:76 #, c-format msgid "%s: %s possibly contains a mounted filesystem\n" msgstr "%s: %s może zawierać zamontowany system plików\n" #: .././libxfs/freebsd.c:60 .././libxfs/linux.c:104 #, c-format msgid "%s: %s contains a mounted filesystem\n" msgstr "%s: %s zawiera zamontowany system plików\n" #: .././libxfs/freebsd.c:75 #, c-format msgid "%s: %s contains a possibly writable, mounted filesystem\n" msgstr "%s: %s zawiera zamontowany, być może zapisywalny system plików\n" #: .././libxfs/freebsd.c:89 .././libxfs/linux.c:100 #, c-format msgid "%s: %s contains a mounted and writable filesystem\n" msgstr "%s: %s zawiera zamontowany, zapisywalny system plików\n" #: .././libxfs/freebsd.c:129 #, c-format msgid "%s: Not a device or file: \"%s\"\n" msgstr "%s: Nie jest urzÄ…dzeniem ani plikiem: \"%s\"\n" #: .././libxfs/freebsd.c:135 #, c-format msgid "%s: DIOCGMEDIASIZE failed on \"%s\": %s\n" msgstr "%s: DIOCGMEDIASIE nie powiodÅ‚o siÄ™ dla \"%s\": %s\n" #: .././libxfs/freebsd.c:141 #, c-format msgid "%s: DIOCGSECTORSIZE failed on \"%s\": %s\n" msgstr "%s: DIOCGSECTORSIZE nie powiodÅ‚o siÄ™ dla \"%s\": %s\n" #: .././libxfs/init.c:97 .././libxfs/init.c:196 #, c-format msgid "%s: %s: device %lld is not open\n" msgstr "%s: %s: urzÄ…dzenie %lld nie jest otwarte\n" #: .././libxfs/init.c:133 #, c-format msgid "%s: cannot stat %s: %s\n" msgstr "%s: nie można wykonać stat na %s: %s\n" #: .././libxfs/init.c:158 #, c-format msgid "%s: device %lld is already open\n" msgstr "%s: urzÄ…dzenie %lld jest już otwarte\n" #: .././libxfs/init.c:171 #, c-format msgid "%s: %s: too many open devices\n" msgstr "%s: %s: zbyt dużo otwartych urzÄ…dzeÅ„\n" #: .././libxfs/init.c:214 #, c-format msgid "%s: can't find a character device matching %s\n" msgstr "%s: nie można odnaleźć urzÄ…dzenia znakowego odpowiadajÄ…cego %s\n" #: .././libxfs/init.c:220 #, c-format msgid "%s: can't find a block device matching %s\n" msgstr "%s: nie można odnaleźć urzÄ…dzenia blokowego odpowiadajÄ…cego %s\n" #: .././libxfs/init.c:334 #, c-format msgid "%s: can't get size for data subvolume\n" msgstr "%s: nie można pobrać rozmiaru podwolumenu danych\n" #: .././libxfs/init.c:339 #, c-format msgid "%s: can't get size for log subvolume\n" msgstr "%s: nie można pobrać rozmiaru podwolumenu logu\n" #: .././libxfs/init.c:344 #, c-format msgid "%s: can't get size for realtime subvolume\n" msgstr "%s: nie można pobrać rozmiaru podwolumenu realtime\n" #: .././libxfs/init.c:441 #, c-format msgid "%s: filesystem has a realtime subvolume\n" msgstr "%s: system plików ma podwolumen realtime\n" #: .././libxfs/init.c:463 #, c-format msgid "%s: realtime init - %llu != %llu\n" msgstr "%s: inicjalizacja realtime - %llu != %llu\n" #: .././libxfs/init.c:471 #, c-format msgid "%s: realtime size check failed\n" msgstr "%s: sprawdzenie rozmiaru realtime nie powiodÅ‚o siÄ™\n" #: .././libxfs/init.c:593 #, c-format msgid "%s: buftarg init failed\n" msgstr "%s: nie udaÅ‚o siÄ™ zainicjować buftarg\n" #: .././libxfs/init.c:614 #, c-format msgid "%s: bad buftarg reinit, ddev\n" msgstr "%s: błędna reinicjacja buftarg, ddev\n" #: .././libxfs/init.c:621 #, c-format msgid "%s: bad buftarg reinit, ldev mismatch\n" msgstr "%s: błędna reinicjacja buftarg, niezgodność ldev\n" #: .././libxfs/init.c:628 #, c-format msgid "%s: bad buftarg reinit, logdev\n" msgstr "%s: błędna reinicjacja buftarg, logdev\n" #: .././libxfs/init.c:635 #, c-format msgid "%s: bad buftarg reinit, rtdev\n" msgstr "%s: błędna reinicjacja buftarg, rtdev\n" #: .././libxfs/init.c:736 #, c-format msgid "%s: size check failed\n" msgstr "%s: sprawdzenie rozmiaru nie powiodÅ‚o siÄ™\n" #: .././libxfs/init.c:748 #, c-format msgid "%s: V1 inodes unsupported. Please try an older xfsprogs.\n" msgstr "" "%s: i-wÄ™zÅ‚y V1 nie sÄ… obsÅ‚ugiwane. ProszÄ™ spróbować starszÄ… wersjÄ… " "xfsprogs.\n" #: .././libxfs/init.c:757 #, c-format msgid "%s: V1 directories unsupported. Please try an older xfsprogs.\n" msgstr "" "%s: katalogi V1 nie sÄ… obsÅ‚ugiwane. ProszÄ™ spróbować starszÄ… wersjÄ… " "xfsprogs.\n" #: .././libxfs/init.c:765 #, c-format msgid "%s: Unsupported features detected. Please try a newer xfsprogs.\n" msgstr "" "%s: Wykryto nie obsÅ‚ugiwane cechy. ProszÄ™ spróbować nowszÄ… wersjÄ… xfsprogs.\n" #: .././libxfs/init.c:785 #, c-format msgid "%s: data size check failed\n" msgstr "%s: sprawdzenie rozmiaru danych nie powiodÅ‚o siÄ™\n" #: .././libxfs/init.c:799 #, c-format msgid "%s: log size checks failed\n" msgstr "%s: sprawdzenie rozmiaru logu nie powiodÅ‚o siÄ™\n" #: .././libxfs/init.c:810 #, c-format msgid "%s: realtime device init failed\n" msgstr "%s: inicjalizacja urzÄ…dzenia realtime nie powiodÅ‚a siÄ™\n" #: .././libxfs/init.c:827 #, c-format msgid "%s: read of AG %u failed\n" msgstr "%s: odczyt AG %u nie powiódÅ‚ siÄ™\n" #: .././libxfs/init.c:831 #, c-format msgid "%s: limiting reads to AG 0\n" msgstr "%s: ograniczenie odczytu do AG 0\n" #: .././libxfs/init.c:840 #, c-format msgid "%s: perag init failed\n" msgstr "%s: nie udaÅ‚o siÄ™ zainicjować perag\n" #: .././libxfs/kmem.c:15 #, c-format msgid "%s: zone init failed (%s, %d bytes): %s\n" msgstr "%s: inicjalizacja strefy nie powiodÅ‚a siÄ™ (%s, %d bajtów): %s\n" #: .././libxfs/kmem.c:32 #, c-format msgid "%s: zone alloc failed (%s, %d bytes): %s\n" msgstr "%s: przydzielenie strefy nie powiodÅ‚o siÄ™ (%s, %d bajtów): %s\n" #: .././libxfs/kmem.c:56 #, c-format msgid "%s: malloc failed (%d bytes): %s\n" msgstr "%s: malloc nie powiodÅ‚o siÄ™ (%d bajtów): %s\n" #: .././libxfs/kmem.c:77 #, c-format msgid "%s: realloc failed (%d bytes): %s\n" msgstr "%s: realloc nie powiodÅ‚o siÄ™ (%d bajtów): %s\n" #: .././libxfs/linux.c:137 #, c-format msgid "%s: %s - cannot set blocksize %d on block device %s: %s\n" msgstr "" "%s: %s - nie można ustawić rozmiaru bloku %d dla urzÄ…dzenia blokowego %s: " "%s\n" #: .././libxfs/linux.c:205 #, c-format msgid "%s: can't determine device size\n" msgstr "%s: nie można okreÅ›lić rozmiaru urzÄ…dzenia\n" #: .././libxfs/linux.c:213 #, c-format msgid "%s: warning - cannot get sector size from block device %s: %s\n" msgstr "" "%s: uwaga - nie można pobrać rozmiaru sektora urzÄ…dzenia blokowego %s: %s\n" #: .././libxfs/rdwr.c:82 #, c-format msgid "%s: %s can't memalign %d bytes: %s\n" msgstr "%s: %s nie można wykonać memalign dla %d bajtów: %s\n" #: .././libxfs/rdwr.c:92 #, c-format msgid "%s: %s seek to offset %llu failed: %s\n" msgstr "%s: %s zmiana offsetu na %llu nie powiodÅ‚a siÄ™: %s\n" #: .././libxfs/rdwr.c:102 #, c-format msgid "%s: %s write failed: %s\n" msgstr "%s: %s zapis nie powiódÅ‚ siÄ™: %s\n" #: .././libxfs/rdwr.c:106 #, c-format msgid "%s: %s not progressing?\n" msgstr "%s: %s nie postÄ™puje?\n" #: .././libxfs/rdwr.c:581 #, c-format msgid "%s: %s can't memalign %u bytes: %s\n" msgstr "%s: %s nie można wykonać memalign dla %u bajtów: %s\n" #: .././libxfs/rdwr.c:621 #, c-format msgid "%s: %s can't malloc %u bytes: %s\n" msgstr "%s: %s nie można przydzielić %u bajtów: %s\n" #: .././libxfs/rdwr.c:705 #, c-format msgid "%s: %s invalid map %p or nmaps %d\n" msgstr "%s: %s nieprawidÅ‚owa mapa %p lub nmaps %d\n" #: .././libxfs/rdwr.c:712 #, c-format msgid "%s: %s map blkno 0x%llx doesn't match key 0x%llx\n" msgstr "%s: %s map blkno 0x%llx nie pasuje do klucza 0x%llx\n" #: .././libxfs/rdwr.c:757 #, c-format msgid "Warning: recursive buffer locking at block % detected\n" msgstr "Uwaga: wykryto rekurencyjnÄ… blokadÄ™ bufora na bloku %\n" #: .././libxfs/rdwr.c:929 #, c-format msgid "%s: read failed: %s\n" msgstr "%s: odczyt nie powiódÅ‚ siÄ™: %s\n" #: .././libxfs/rdwr.c:935 #, c-format msgid "%s: error - read only %d of %d bytes\n" msgstr "%s: błąd - odczytano tylko %d z %d bajtów\n" #: .././libxfs/rdwr.c:1097 #, c-format msgid "%s: pwrite failed: %s\n" msgstr "%s: pwrite nie powiodÅ‚o siÄ™: %s\n" #: .././libxfs/rdwr.c:1103 #, c-format msgid "%s: error - pwrite only %d of %d bytes\n" msgstr "%s: błąd - wykonano pwrite tylko %d z %d bajtów\n" #: .././libxfs/rdwr.c:1138 #, c-format msgid "%s: write verifier failed on %s bno 0x%llx/0x%x\n" msgstr "%s: weryfikacja zapisu nie powiodÅ‚a siÄ™ na %s bno 0x%llx/0x%x\n" #: .././libxfs/trans.c:733 #, c-format msgid "%s: warning - imap_to_bp failed (%d)\n" msgstr "%s: uwaga - imap_to_bp nie powiodÅ‚o siÄ™ (%d)\n" #: .././libxfs/trans.c:741 #, c-format msgid "%s: warning - iflush_int failed (%d)\n" msgstr "%s: uwaga - iflush_int nie powiodÅ‚o siÄ™ (%d)\n" #: .././libxfs/trans.c:801 .././libxfs/trans.c:855 #, c-format msgid "%s: unrecognised log item type\n" msgstr "%s: nierozpoznany typ elementu logu\n" #: .././libxfs/util.c:673 #, c-format msgid "%s: cannot duplicate transaction: %s\n" msgstr "%s: nie można powielić transakcji: %s\n" #: .././libxlog/util.c:67 #, c-format msgid "%s: cannot find log head/tail (xlog_find_tail=%d)\n" msgstr "%s: nie odnaleziono poczÄ…tku/koÅ„ca logu (xlog_find_tail=%d)\n" #: .././libxlog/util.c:75 #, c-format msgid "%s: head block % tail block %\n" msgstr "%s: blok poczÄ…tku % blok koÅ„ca %\n" #: .././libxlog/util.c:97 #, c-format msgid "" "* ERROR: mismatched uuid in log\n" "* SB : %s\n" "* log: %s\n" msgstr "" "* BÅÄ„D: niepasujÄ…cy uuid w logu\n" " SB : %s\n" " log: %s\n" #: .././libxlog/util.c:110 #, c-format msgid "" "\n" "LOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n" msgstr "" "\n" "LOG REC AT LSN cykl %d blok %d (0x%x, 0x%x)\n" #: .././libxlog/util.c:118 #, c-format msgid "* ERROR: bad magic number in log header: 0x%x\n" msgstr "* BÅÄ„D: błędna liczba magiczna w nagłówku logu: 0x%x\n" #: .././libxlog/util.c:127 #, c-format msgid "* ERROR: log format incompatible (log=%d, ours=%d)\n" msgstr "* BÅÄ„D: niekompatybilny format logu (log=%d, nasz=%d)\n" #: .././libxlog/util.c:137 .././libxlog/util.c:149 msgid "Bad log" msgstr "Błędny log" #: .././logprint/log_copy.c:46 .././logprint/log_dump.c:45 #, c-format msgid "%s: read error (%lld): %s\n" msgstr "%s: błąd odczytu (%lld): %s\n" #: .././logprint/log_copy.c:51 .././logprint/log_dump.c:50 #, c-format msgid "%s: physical end of log at %lld\n" msgstr "%s: fizyczny koniec logu na %lld\n" #: .././logprint/log_copy.c:55 #, c-format msgid "%s: short read? (%lld)\n" msgstr "%s: skrócony odczyt? (%lld)\n" #: .././logprint/log_copy.c:62 #, c-format msgid "%s: write error (%lld): %s\n" msgstr "%s: błąd zapisu (%lld): %s\n" #: .././logprint/log_copy.c:67 #, c-format msgid "%s: short write? (%lld)\n" msgstr "%s: skrócony zapis? (%lld)\n" #: .././logprint/log_dump.c:58 #, c-format msgid "%6lld HEADER Cycle %d tail %d:%06d len %6d ops %d\n" msgstr "%6lld NAGÅÓWEK Cykl %d koniec %d:%06d len %6d ops %d\n" #: .././logprint/log_dump.c:69 #, c-format msgid "[%05lld - %05lld] Cycle 0x%08x New Cycle 0x%08x\n" msgstr "[%05lld - %05lld] Cykl 0x%08x Nowy cykl 0x%08x\n" #: .././logprint/log_misc.c:87 #, c-format msgid "Oper (%d): tid: %x len: %d clientid: %s " msgstr "Operacja (%d): tid: %x len: %d clientid: %s " #: .././logprint/log_misc.c:92 #, c-format msgid "flags: " msgstr "flagi: " #: .././logprint/log_misc.c:186 #, c-format msgid " Not enough data to decode further\n" msgstr " Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_misc.c:190 #, c-format msgid " tid: %x num_items: %d\n" msgstr " tid: %x num_items: %d\n" #: .././logprint/log_misc.c:235 #, c-format msgid "" "#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d flags: 0x%x\n" msgstr "" "#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d flags: 0x%x\n" #: .././logprint/log_misc.c:241 #, c-format msgid "#regs: %d Not printing rest of data\n" msgstr "#regs: %d Bez wypisywania reszty danych\n" #: .././logprint/log_misc.c:258 #, c-format msgid "SUPER BLOCK Buffer: " msgstr "Bufor SUPER BLOKU: " #: .././logprint/log_misc.c:260 .././logprint/log_misc.c:348 #: .././logprint/log_misc.c:378 #, c-format msgid "Out of space\n" msgstr "Brak miejsca na dysku\n" #: .././logprint/log_misc.c:268 #, c-format msgid "icount: %llu ifree: %llu " msgstr "icount: %llu ifree: %llu " #: .././logprint/log_misc.c:273 #, c-format msgid "fdblks: %llu frext: %llu\n" msgstr "fdblks: %llu frext: %llu\n" #: .././logprint/log_misc.c:284 #, c-format msgid "AGI Buffer: XAGI " msgstr "Bufor AGI: XAGI " #: .././logprint/log_misc.c:295 #, c-format msgid "out of space\n" msgstr "brak miejsca na dysku\n" #: .././logprint/log_misc.c:298 #, c-format msgid "ver: %d " msgstr "wersja: %d " #: .././logprint/log_misc.c:300 #, c-format msgid "seq#: %d len: %d cnt: %d root: %d\n" msgstr "seq#: %d len: %d cnt: %d root: %d\n" #: .././logprint/log_misc.c:305 #, c-format msgid "level: %d free#: 0x%x newino: 0x%x\n" msgstr "level: %d free#: 0x%x newino: 0x%x\n" #: .././logprint/log_misc.c:315 #, c-format msgid "AGI unlinked data skipped " msgstr "PominiÄ™to niedowiÄ…zane dane AGI " #: .././logprint/log_misc.c:316 #, c-format msgid "(CONTINUE set, no space)\n" msgstr "(KONTYNUACJA, brak miejsca)\n" #: .././logprint/log_misc.c:322 .././logprint/log_print_all.c:148 #, c-format msgid "bucket[%d - %d]: " msgstr "kubeÅ‚ek[%d - %d]: " #: .././logprint/log_misc.c:338 #, c-format msgid "AGF Buffer: XAGF " msgstr "Bufor AGF: XAGF " #: .././logprint/log_misc.c:351 #, c-format msgid "ver: %d seq#: %d len: %d \n" msgstr "ver: %d seq#: %d len: %d \n" #: .././logprint/log_misc.c:355 #, c-format msgid "root BNO: %d CNT: %d\n" msgstr "root BNO: %d CNT: %d\n" #: .././logprint/log_misc.c:358 #, c-format msgid "level BNO: %d CNT: %d\n" msgstr "level BNO: %d CNT: %d\n" #: .././logprint/log_misc.c:361 #, c-format msgid "1st: %d last: %d cnt: %d freeblks: %d longest: %d\n" msgstr "1st: %d last: %d cnt: %d freeblks: %d longest: %d\n" #: .././logprint/log_misc.c:375 #, c-format msgid "DQUOT Buffer: DQ " msgstr "Bufor DQUOT: DQ " #: .././logprint/log_misc.c:382 #, c-format msgid "ver: %d flags: 0x%x id: %d \n" msgstr "ver: %d flags: 0x%x id: %d \n" #: .././logprint/log_misc.c:385 #, c-format msgid "blk limits hard: %llu soft: %llu\n" msgstr "blk limits hard: %llu soft: %llu\n" #: .././logprint/log_misc.c:390 #, c-format msgid "blk count: %llu warns: %d timer: %d\n" msgstr "blk count: %llu warns: %d timer: %d\n" #: .././logprint/log_misc.c:394 #, c-format msgid "ino limits hard: %llu soft: %llu\n" msgstr "ino limits hard: %llu soft: %llu\n" #: .././logprint/log_misc.c:399 #, c-format msgid "ino count: %llu warns: %d timer: %d\n" msgstr "ino count: %llu warns: %d timer: %d\n" #: .././logprint/log_misc.c:405 #, c-format msgid "BUF DATA\n" msgstr "DANE BUFORA\n" #: .././logprint/log_misc.c:441 #, c-format msgid "QOFF: #regs: %d flags: 0x%x\n" msgstr "QOFF: #regs: %d flags: 0x%x\n" #: .././logprint/log_misc.c:444 #, c-format msgid "QOFF: Not enough data to decode further\n" msgstr "QOFF: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_misc.c:454 #, c-format msgid "INODE CORE\n" msgstr "RDZEŃ I-WĘZÅA\n" #: .././logprint/log_misc.c:455 #, c-format msgid "magic 0x%hx mode 0%ho version %d format %d\n" msgstr "magic 0x%hx mode 0%ho version %d format %d\n" #: .././logprint/log_misc.c:458 #, c-format msgid "nlink %hd uid %d gid %d\n" msgstr "nlink %hd uid %d gid %d\n" #: .././logprint/log_misc.c:460 #, c-format msgid "atime 0x%x mtime 0x%x ctime 0x%x\n" msgstr "atime 0x%x mtime 0x%x ctime 0x%x\n" #: .././logprint/log_misc.c:462 #, c-format msgid "size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n" msgstr "size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n" #: .././logprint/log_misc.c:465 #, c-format msgid "naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n" msgstr "naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n" #: .././logprint/log_misc.c:468 #, c-format msgid "flags 0x%x gen 0x%x\n" msgstr "flags 0x%x gen 0x%x\n" #: .././logprint/log_misc.c:471 #, c-format msgid "flags2 0x%llx cowextsize 0x%x\n" msgstr "flags2 0x%llx cowextsize 0x%x\n" #: .././logprint/log_misc.c:488 #, c-format msgid "SHORTFORM DIRECTORY size %d\n" msgstr "Rozmiar KATALOGU W POSTACI KRÓTKIEJ %d\n" #: .././logprint/log_misc.c:494 #, c-format msgid "SHORTFORM DIRECTORY size %d count %d\n" msgstr "KATALOG W POSTACI KRÓTKIEJ: rozmiar %d liczba %d\n" #: .././logprint/log_misc.c:497 #, c-format msgid ".. ino 0x%llx\n" msgstr ".. ino 0x%llx\n" #: .././logprint/log_misc.c:505 #, c-format msgid "%s ino 0x%llx namelen %d\n" msgstr "%s ino 0x%llx namelen %d\n" #: .././logprint/log_misc.c:545 #, c-format msgid "INODE: " msgstr "I-WĘZEÅ: " #: .././logprint/log_misc.c:546 #, c-format msgid "#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n" msgstr "#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n" #: .././logprint/log_misc.c:549 #, c-format msgid " blkno: %lld len: %d boff: %d\n" msgstr " blkno: %lld len: %d boff: %d\n" #: .././logprint/log_misc.c:554 #, c-format msgid "INODE: #regs: %d Not printing rest of data\n" msgstr "I-WĘZEÅ: #regs: %d Bez wypisywania reszty danych\n" #: .././logprint/log_misc.c:581 #, c-format msgid "DEV inode: no extra region\n" msgstr "I-wÄ™zeÅ‚ DEV: brak dodatkowego regionu\n" #: .././logprint/log_misc.c:584 #, c-format msgid "UUID inode: no extra region\n" msgstr "I-wÄ™zeÅ‚ UUID: brak dodatkowego regionu\n" #: .././logprint/log_misc.c:606 #, c-format msgid "EXTENTS inode data\n" msgstr "EKSTENTY danych i-wÄ™zÅ‚a\n" #: .././logprint/log_misc.c:609 #, c-format msgid "BTREE inode data\n" msgstr "B-DRZEWO danych i-wÄ™zÅ‚a\n" #: .././logprint/log_misc.c:612 #, c-format msgid "LOCAL inode data\n" msgstr "LOKALNE dane i-wÄ™zÅ‚a\n" #: .././logprint/log_misc.c:636 #, c-format msgid "EXTENTS attr data\n" msgstr "EKSTENTY danych atrybutów\n" #: .././logprint/log_misc.c:639 #, c-format msgid "BTREE attr data\n" msgstr "B-DRZEWO danych atrybutów\n" #: .././logprint/log_misc.c:642 #, c-format msgid "LOCAL attr data\n" msgstr "LOKALNE dane atrybutów\n" #: .././logprint/log_misc.c:683 #, c-format msgid "#regs: %d id: 0x%x" msgstr "#regs: %d id: 0x%x" #: .././logprint/log_misc.c:684 #, c-format msgid " blkno: %lld len: %d boff: %d\n" msgstr " blkno: %lld len: %d boff: %d\n" #: .././logprint/log_misc.c:688 #, c-format msgid "DQUOT: #regs: %d Not printing rest of data\n" msgstr "DQUOT: #regs: %d Bez wypisywania reszty danych\n" #: .././logprint/log_misc.c:707 #, c-format msgid "DQUOT: magic 0x%hx flags 0%ho\n" msgstr "DQUOT: magic 0x%hx flags 0%ho\n" #: .././logprint/log_misc.c:733 #, c-format msgid "ICR: split header, not printing\n" msgstr "ICR: nagłówek podzielony, bez wypisywania\n" #: .././logprint/log_misc.c:737 #, c-format msgid "" "ICR: #ag: %d agbno: 0x%x len: %d\n" " cnt: %d isize: %d gen: 0x%x\n" msgstr "" "ICR: #ag: %d agbno: 0x%x len: %d\n" " cnt: %d isize: %d gen: 0x%x\n" #: .././logprint/log_misc.c:763 #, c-format msgid "%s: lseek to %lld failed: %s\n" msgstr "%s: lseek na %lld nie powiodÅ‚o siÄ™: %s\n" #: .././logprint/log_misc.c:809 #, c-format msgid "%s: xlog_print_record: malloc failed\n" msgstr "%s: xlog_print_record: malloc nie powiodÅ‚o siÄ™\n" #: .././logprint/log_misc.c:818 #, c-format msgid "%s: xlog_print_record: read error\n" msgstr "%s: xlog_print_record: błąd odczytu\n" #: .././logprint/log_misc.c:913 .././logprint/log_misc.c:1016 #, c-format msgid "Left over region from split log item\n" msgstr "Region pozostaÅ‚y z podziaÅ‚u elementu logu\n" #: .././logprint/log_misc.c:1001 #, c-format msgid "Unmount filesystem\n" msgstr "Niezamontowany system plików\n" #: .././logprint/log_misc.c:1008 #, c-format msgid "%s: unknown log operation type (%x)\n" msgstr "%s: nieznany typ operacji w logu (%x)\n" #: .././logprint/log_misc.c:1049 #, c-format msgid "Header 0x%x wanted 0x%x\n" msgstr "Nagłówek 0x%x, pożądany 0x%x\n" #: .././logprint/log_misc.c:1063 #, c-format msgid "cycle: %d\tversion: %d\t" msgstr "cykl: %d\twersja: %d\t" #: .././logprint/log_misc.c:1069 #, c-format msgid "length of Log Record: %d\tprev offset: %d\t\tnum ops: %d\n" msgstr "dÅ‚ugość rekordu logu: %d\tpoprz.offset: %d\t\tl.oper.: %d\n" #: .././logprint/log_misc.c:1075 .././logprint/log_misc.c:1117 #, c-format msgid "cycle num overwrites: " msgstr "liczba nadpisaÅ„ cyklu: " #: .././logprint/log_misc.c:1084 #, c-format msgid "uuid: %s format: " msgstr "uuid: %s format: " #: .././logprint/log_misc.c:1087 #, c-format msgid "unknown\n" msgstr "nieznany\n" #: .././logprint/log_misc.c:1090 #, c-format msgid "little endian linux\n" msgstr "Linux little endian\n" #: .././logprint/log_misc.c:1093 #, c-format msgid "big endian linux\n" msgstr "Linux big endian\n" #: .././logprint/log_misc.c:1096 #, c-format msgid "big endian irix\n" msgstr "IRIX big endian\n" #: .././logprint/log_misc.c:1102 #, c-format msgid "h_size: %d\n" msgstr "h_size: %d\n" #: .././logprint/log_misc.c:1114 #, c-format msgid "extended-header: cycle: %d\n" msgstr "nagłówek-rozszerzony: cykl: %d\n" #: .././logprint/log_misc.c:1130 #, c-format msgid "* ERROR: found data after zeroed blocks block=%-21lld *\n" msgstr "* BÅÄ„D: znaleziono dane za wyzerowanymi blokami blok=%-21lld *\n" #: .././logprint/log_misc.c:1141 #, c-format msgid "* ERROR: header cycle=%-11d block=%-21lld *\n" msgstr "* BÅÄ„D: nagłówek cykl=%-11d blok=%-21lld *\n" #: .././logprint/log_misc.c:1152 #, c-format msgid "* ERROR: data block=%-21lld *\n" msgstr "* BÅÄ„D: blok danych=%-21lld *\n" #: .././logprint/log_misc.c:1163 #, c-format msgid "" "* ERROR: for header block=%lld\n" "* not enough hdrs for data length, required num = %d, hdr num = %d\n" msgstr "" "* BÅÄ„D: dla bloku nagłówka %lld\n" "* za maÅ‚o nagłówków dla dÅ‚ugoÅ›ci danych, wymaganych = %d, liczba = %d\n" #: .././logprint/log_misc.c:1169 msgid "Not enough headers for data length." msgstr "Za maÅ‚o nagłówków dla dÅ‚ugoÅ›ci danych." #: .././logprint/log_misc.c:1179 #, c-format msgid "%s: xlog_print: malloc failed for ext hdrs\n" msgstr "%s: xlog_print: malloc dla rozszerzonych nagłówków nie powiódÅ‚ siÄ™\n" #: .././logprint/log_misc.c:1227 .././logprint/log_misc.c:1303 #: .././logprint/log_misc.c:1374 .././logprint/log_misc.c:1411 #, c-format msgid "%s: physical end of log\n" msgstr "%s: fizyczny koniec logu\n" #: .././logprint/log_misc.c:1233 .././logprint/log_misc.c:1308 #: .././logprint/log_misc.c:1426 #, c-format msgid "BLKNO: %lld\n" msgstr "BLKNO: %lld\n" #: .././logprint/log_misc.c:1291 #, c-format msgid "%s: problem finding oldest LR\n" msgstr "%s: problem ze znalezieniem najstarszego rekordu logu\n" #: .././logprint/log_misc.c:1317 #, c-format msgid "%s: after %d zeroed blocks\n" msgstr "%s: po %d wyzerowanych blokach\n" #: .././logprint/log_misc.c:1386 msgid "illegal value" msgstr "niedozwolona wartość" #: .././logprint/log_misc.c:1392 #, c-format msgid "%s: skipped %d cleared blocks in range: %lld - %lld\n" msgstr "%s: pominiÄ™to %d wyzerowanych bloków w przedziale: %lld - %lld\n" #: .././logprint/log_misc.c:1397 #, c-format msgid "%s: totally cleared log\n" msgstr "%s: caÅ‚kowicie wyczyszczony log\n" #: .././logprint/log_misc.c:1402 #, c-format msgid "%s: skipped %d zeroed blocks in range: %lld - %lld\n" msgstr "%s: pominiÄ™to %d wyzerowanych bloków w przedziale %lld - %lld\n" #: .././logprint/log_misc.c:1407 #, c-format msgid "%s: totally zeroed log\n" msgstr "%s: caÅ‚kowicie wyzerowany log\n" #: .././logprint/log_misc.c:1423 msgid "xlog_find_head: bad read" msgstr "xlog_find_head: błędny odczyt" #: .././logprint/log_misc.c:1475 #, c-format msgid "%s: logical end of log\n" msgstr "%s: logiczny koniec logu\n" #: .././logprint/log_print_all.c:96 #, c-format msgid "" "BUF: #regs:%d start blkno:0x%llx len:%d bmap size:%d flags:0x%x\n" msgstr "" "BUF: #regs:%d blok pocz.:0x%llx dÅ‚ug.:%d rozm.bmapy:%d flagi:0x%x\n" #: .././logprint/log_print_all.c:106 #, c-format msgid "\tSUPER Block Buffer:\n" msgstr "\tBufor SUPER bloku:\n" #: .././logprint/log_print_all.c:109 #, c-format msgid " icount:%llu ifree:%llu " msgstr " icount:%llu ifree:%llu " #: .././logprint/log_print_all.c:114 #, c-format msgid "fdblks:%llu frext:%llu\n" msgstr "fdblks:%llu frext:%llu\n" #: .././logprint/log_print_all.c:119 #, c-format msgid "\t\tsunit:%u swidth:%u\n" msgstr "\t\tsunit:%u swidth:%u\n" #: .././logprint/log_print_all.c:125 #, c-format msgid "\tAGI Buffer: (XAGI)\n" msgstr "\tBufor AGI: (XAGI)\n" #: .././logprint/log_print_all.c:128 #, c-format msgid "\t\tver:%d " msgstr "\t\twersja:%d " #: .././logprint/log_print_all.c:130 #, c-format msgid "seq#:%d len:%d cnt:%d root:%d\n" msgstr "seq#:%d len:%d cnt:%d root:%d\n" #: .././logprint/log_print_all.c:135 #, c-format msgid "\t\tlevel:%d free#:0x%x newino:0x%x\n" msgstr "\t\tlevel:%d free#:0x%x newino:0x%x\n" #: .././logprint/log_print_all.c:159 #, c-format msgid "\tAGF Buffer: (XAGF)\n" msgstr "\tBufor AGI: (XAGF)\n" #: .././logprint/log_print_all.c:162 #, c-format msgid "\t\tver:%d seq#:%d len:%d \n" msgstr "\t\tver:%d seq#:%d len:%d \n" #: .././logprint/log_print_all.c:166 #, c-format msgid "\t\troot BNO:%d CNT:%d\n" msgstr "\t\troot BNO:%d CNT:%d\n" #: .././logprint/log_print_all.c:169 #, c-format msgid "\t\tlevel BNO:%d CNT:%d\n" msgstr "\t\tlevel BNO:%d CNT:%d\n" #: .././logprint/log_print_all.c:172 #, c-format msgid "\t\t1st:%d last:%d cnt:%d freeblks:%d longest:%d\n" msgstr "\t\t1st:%d last:%d cnt:%d freeblks:%d longest:%d\n" #: .././logprint/log_print_all.c:181 #, c-format msgid "\tDQUOT Buffer:\n" msgstr "\tBufor DQUOT:\n" #: .././logprint/log_print_all.c:184 #, c-format msgid "\t\tUIDs 0x%lx-0x%lx\n" msgstr "\t\tUIDs 0x%lx-0x%lx\n" #: .././logprint/log_print_all.c:189 #, c-format msgid "\tBUF DATA\n" msgstr "\tDANE BUF\n" #: .././logprint/log_print_all.c:211 #, c-format msgid "\tQUOTAOFF: #regs:%d type:%s\n" msgstr "\tQUOTAOFF: #regs:%d type:%s\n" #: .././logprint/log_print_all.c:226 #, c-format msgid "\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n" msgstr "\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n" #: .././logprint/log_print_all.c:230 #, c-format msgid "\t\tmagic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n" msgstr "\t\tmagic 0x%x\twersja 0x%x\tID 0x%x (%d)\t\n" #: .././logprint/log_print_all.c:235 #, c-format msgid "\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x\tino_soft 0x%x\n" msgstr "\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x\tino_soft 0x%x\n" #: .././logprint/log_print_all.c:241 #, c-format msgid "\t\tbcount 0x%x (%d) icount 0x%x (%d)\n" msgstr "\t\tbcount 0x%x (%d) icount 0x%x (%d)\n" #: .././logprint/log_print_all.c:246 #, c-format msgid "\t\tbtimer 0x%x itimer 0x%x \n" msgstr "\t\tbtimer 0x%x itimer 0x%x \n" #: .././logprint/log_print_all.c:255 #, c-format msgid "\tCORE inode:\n" msgstr "\tGÅÓWNY i-wÄ™zeÅ‚:\n" #: .././logprint/log_print_all.c:258 #, c-format msgid "\t\tmagic:%c%c mode:0x%x ver:%d format:%d\n" msgstr "\t\tmagic:%c%c mode:0x%x ver:%d format:%d\n" #: .././logprint/log_print_all.c:261 #, c-format msgid "\t\tuid:%d gid:%d nlink:%d projid:0x%04x%04x\n" msgstr "\t\tuid:%d gid:%d nlink:%d projid:0x%04x%04x\n" #: .././logprint/log_print_all.c:264 #, c-format msgid "\t\tatime:%d mtime:%d ctime:%d\n" msgstr "\t\tatime:%d mtime:%d ctime:%d\n" #: .././logprint/log_print_all.c:266 #, c-format msgid "\t\tflushiter:%d\n" msgstr "\t\tflushiter:%d\n" #: .././logprint/log_print_all.c:267 #, c-format msgid "\t\tsize:0x%llx nblks:0x%llx exsize:%d nextents:%d anextents:%d\n" msgstr "\t\tsize:0x%llx nblks:0x%llx exsize:%d nextents:%d anextents:%d\n" #: .././logprint/log_print_all.c:271 #, c-format msgid "\t\tforkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x gen:%u\n" msgstr "\t\tforkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x gen:%u\n" #: .././logprint/log_print_all.c:276 #, c-format msgid "\t\tflags2 0x%llx cowextsize 0x%x\n" msgstr "\t\tflags2 0x%llx cowextsize 0x%x\n" #: .././logprint/log_print_all.c:295 #, c-format msgid "\tINODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n" msgstr "\tINODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n" #: .././logprint/log_print_all.c:311 #, c-format msgid "\t\tDATA FORK EXTENTS inode data:\n" msgstr "\t\tDane EKSTENTÓW GAÅĘZI DANYCH i-wÄ™zÅ‚a:\n" #: .././logprint/log_print_all.c:318 #, c-format msgid "\t\tDATA FORK BTREE inode data:\n" msgstr "\t\tDane B-DRZEWA GAÅĘZI DANYCH i-wÄ™zÅ‚a:\n" #: .././logprint/log_print_all.c:325 #, c-format msgid "\t\tDATA FORK LOCAL inode data:\n" msgstr "\t\tDane LOKALNE GAÅĘZI DANYCH i-wÄ™zÅ‚a:\n" #: .././logprint/log_print_all.c:332 #, c-format msgid "\t\tDEV inode: no extra region\n" msgstr "\t\tI-wÄ™zeÅ‚ DEV: brak dodatkowego regionu\n" #: .././logprint/log_print_all.c:336 #, c-format msgid "\t\tUUID inode: no extra region\n" msgstr "\t\tI-wÄ™zeÅ‚ UUID: brak dodatkowego regionu\n" #: .././logprint/log_print_all.c:351 #, c-format msgid "\t\tATTR FORK EXTENTS inode data:\n" msgstr "\t\tDane EKSTENTÓW GAÅĘZI ATRYBUTÓW i-wÄ™zÅ‚a:\n" #: .././logprint/log_print_all.c:359 #, c-format msgid "\t\tATTR FORK BTREE inode data:\n" msgstr "\t\tDane B-DRZEWA GAÅĘZI ATRYBUTÓW i-wÄ™zÅ‚a:\n" #: .././logprint/log_print_all.c:367 #, c-format msgid "\t\tATTR FORK LOCAL inode data:\n" msgstr "\t\tDane LOKALNE GAÅĘZI ATRYBUTÓW i-wÄ™zÅ‚a:\n" #: .././logprint/log_print_all.c:388 #, c-format msgid "" "\tICR: #ag: %d agbno: 0x%x len: %d\n" "\t cnt: %d isize: %d gen: 0x%x\n" msgstr "" "\tICR: #ag: %d agbno: 0x%x len: %d\n" "\t cnt: %d isize: %d gen: 0x%x\n" #: .././logprint/log_print_all.c:440 #, c-format msgid "xlog_recover_print_logitem: illegal type\n" msgstr "xlog_recover_print_logitem: niedozwolony typ\n" #: .././logprint/log_print_all.c:492 #, c-format msgid "%s: illegal type" msgstr "%s: niedozwolony typ" #: .././logprint/log_print_all.c:500 #, c-format msgid ": cnt:%d total:%d " msgstr ": cnt:%d total:%d " #: .././logprint/log_print_all.c:502 #, c-format msgid "a:0x%lx len:%d " msgstr "a:0x%lx len:%d " #: .././logprint/log_print_trans.c:27 #, c-format msgid "TRANS: tid:0x%x #items:%d trans:0x%x q:0x%lx\n" msgstr "TRANS: tid:0x%x #items:%d trans:0x%0x q:0x%lx\n" #: .././logprint/log_print_trans.c:53 #, c-format msgid "%s: failed to find head and tail, error: %d\n" msgstr "%s: nie udaÅ‚o siÄ™ odnaleźć poczÄ…tku ani koÅ„ca, błąd: %d\n" #: .././logprint/log_print_trans.c:58 #, c-format msgid " log tail: %lld head: %lld state: %s\n" msgstr " koniec logu: %lld poczÄ…tek: %lld stan: %s\n" #: .././logprint/log_print_trans.c:64 #, c-format msgid " override tail: %d\n" msgstr " koniec override: %d\n" #: .././logprint/log_print_trans.c:84 #, c-format msgid "" "Superblock has unknown incompatible log features (0x%x) enabled.\n" "Output may be incomplete or inaccurate. It is recommended that you\n" "upgrade your xfsprogs installation to match the filesystem features.\n" msgstr "" "Superblok ma włączone nieznane, niezgodne opcje logu (0x%x).\n" "WyjÅ›cie może być niekompletne lub niedokÅ‚adne. Zalecana jest\n" "aktualizacja zainstalowanej wersji xfsprogs, aby zgadzaÅ‚a siÄ™ z opcjami\n" "systemu plików.\n" #: .././logprint/log_print_trans.c:92 #, c-format msgid "%s: failed in xfs_do_recovery_pass, error: %d\n" msgstr "%s: xfs_do_recovery_pass nie powiodÅ‚o siÄ™, błąd: %d\n" #: .././logprint/log_redo.c:71 #, c-format msgid "%s: bad size of efi format: %u; expected %u or %u; nextents = %u\n" msgstr "" "%s: błędny rozmiar formatu efi: %u; oczekiwano %u lub %u; nextents = %u\n" #: .././logprint/log_redo.c:94 .././logprint/log_redo.c:110 #, c-format msgid "%s: xlog_print_trans_efi: malloc failed\n" msgstr "%s: xlog_print_trans_efi: malloc nie powiodÅ‚o siÄ™\n" #: .././logprint/log_redo.c:104 #, c-format msgid "EFI: Not enough data to decode further\n" msgstr "EFI: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:118 #, c-format msgid "EFI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "EFI: #regs: %d\tnum_extents: %d id: 0x%llx\n" #: .././logprint/log_redo.c:122 #, c-format msgid "EFI free extent data skipped (CONTINUE set, no space)\n" msgstr "PominiÄ™to dane wolnego ekstentu EFI (KONTYNUACJA, brak miejsca)\n" #: .././logprint/log_redo.c:161 #, c-format msgid "%s: xlog_recover_print_efi: malloc failed\n" msgstr "%s: xlog_recover_print_efi: malloc nie powiodÅ‚o siÄ™\n" #: .././logprint/log_redo.c:170 #, c-format msgid "\tEFI: #regs:%d\tnum_extents:%d id:0x%llx\n" msgstr "\tEFI: #regs:%d\tnum_extents:%d id:0x%llx\n" #: .././logprint/log_redo.c:202 #, c-format msgid "EFD: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "EFD: #regs: %d\tnum_extents: %d id: 0x%llx\n" #: .././logprint/log_redo.c:210 #, c-format msgid "EFD: Not enough data to decode further\n" msgstr "EFD: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:228 #, c-format msgid "\tEFD: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "\tEFD: #regs: %d\tnum_extents: %d id: 0x%llx\n" #: .././logprint/log_redo.c:249 #, c-format msgid "%s: bad size of RUI format: %u; expected %u; nextents = %u\n" msgstr "%s: błędny rozmiar formatu RUI: %u; oczekiwano %u; nextents = %u\n" #: .././logprint/log_redo.c:276 .././logprint/log_redo.c:295 #: .././logprint/log_redo.c:424 .././logprint/log_redo.c:443 #: .././logprint/log_redo.c:567 .././logprint/log_redo.c:586 #, c-format msgid "%s: %s: malloc failed\n" msgstr "%s: %s: malloc nie powiodÅ‚o siÄ™\n" #: .././logprint/log_redo.c:288 #, c-format msgid "RUI: Not enough data to decode further\n" msgstr "RUI: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:304 #, c-format msgid "RUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "RUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" #: .././logprint/log_redo.c:308 #, c-format msgid "RUI extent data skipped (CONTINUE set, no space)\n" msgstr "PominiÄ™to dane ekstentu RUI (ustawiona KONTYNUACJA, brak miejsca)\n" #: .././logprint/log_redo.c:359 #, c-format msgid "RUD: #regs: %d\t id: 0x%llx\n" msgstr "RUD: #regs: %d\t id: 0x%llx\n" #: .././logprint/log_redo.c:367 #, c-format msgid "RUD: Not enough data to decode further\n" msgstr "RUD: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:401 #, c-format msgid "%s: bad size of CUI format: %u; expected %u; nextents = %u\n" msgstr "%s: błędny rozmiar formatu CUI: %u; oczekiwano %u; nextents = %u\n" #: .././logprint/log_redo.c:436 #, c-format msgid "CUI: Not enough data to decode further\n" msgstr "CUI: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:452 #, c-format msgid "CUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "CUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" #: .././logprint/log_redo.c:456 #, c-format msgid "CUI extent data skipped (CONTINUE set, no space)\n" msgstr "PominiÄ™to dane ekstentu CUI (ustawiona KONTYNUACJA, brak miejsca)\n" #: .././logprint/log_redo.c:502 #, c-format msgid "CUD: #regs: %d\t id: 0x%llx\n" msgstr "CUD: #regs: %d\t id: 0x%llx\n" #: .././logprint/log_redo.c:510 #, c-format msgid "CUD: Not enough data to decode further\n" msgstr "CUD: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:544 #, c-format msgid "%s: bad size of BUI format: %u; expected %u; nextents = %u\n" msgstr "%s: błędny rozmiar formatu BUI: %u; oczekiwano %u; nextents = %u\n" #: .././logprint/log_redo.c:579 #, c-format msgid "BUI: Not enough data to decode further\n" msgstr "BUI: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/log_redo.c:595 #, c-format msgid "BUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "BUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" #: .././logprint/log_redo.c:599 #, c-format msgid "BUI extent data skipped (CONTINUE set, no space)\n" msgstr "PominiÄ™to dane ekstentu BUI (ustawiona KONTYNUACJA, brak miejsca)\n" #: .././logprint/log_redo.c:646 #, c-format msgid "BUD: #regs: %d\t id: 0x%llx\n" msgstr "BUD: #regs: %d\t id: 0x%llx\n" #: .././logprint/log_redo.c:654 #, c-format msgid "BUD: Not enough data to decode further\n" msgstr "BUD: Za maÅ‚o danych do dalszego dekodowania\n" #: .././logprint/logprint.c:45 #, c-format msgid "" "Usage: %s [options...] \n" "\n" "Options:\n" " -c\t try to continue if error found in log\n" " -C copy the log from the filesystem to filename\n" " -d\t dump the log in log-record format\n" " -e\t exit when an error is found in the log\n" " -f\t specified device is actually a file\n" " -l filename of external log\n" " -n\t don't try and interpret log data\n" " -o\t print buffer data in hex\n" " -s block # to start printing\n" " -v print \"overwrite\" data\n" " -t\t print out transactional view\n" "\t-b in transactional view, extract buffer info\n" "\t-i in transactional view, extract inode info\n" "\t-q in transactional view, extract quota info\n" " -D print only data; no decoding\n" " -V print version information\n" msgstr "" "SkÅ‚adnia: %s [opcje...] \n" "\n" "Opcje:\n" " -c próba kontynuacji w przypadku błędu w logu\n" " -C skopiowanie logu z systemu plików do pliku o podanej " "nazwie\n" " -d zrzut logu w formacie jego rekordów\n" " -e zakoÅ„czenie po napotkaniu błędu w logu\n" " -f podane urzÄ…dzenie jest plikiem\n" " -l nazwa pliku z logiem zewnÄ™trznym\n" " -n bez prób interpretacji danych logu\n" " -o wypisanie danych bufora szesnastkowo\n" " -s numer pierwszego bloku do wypisania\n" " -v wypisanie danych \"overwrite\"\n" " -t wypisywanie w widoku transakcyjnym\n" " -b w wid.transakcyjnym: wypisywanie informacji o buforze\n" " -i w wid.transakcyjnym: wypisywanie informacji o i-wÄ™zÅ‚ach\n" " -q w wid.transakcyjnym: wypisywanie informacji o limitach\n" " -D wypisywanie tylko danych, bez dekodowania\n" " -V wypisanie informacji o wersji\n" #: .././logprint/logprint.c:79 #, c-format msgid " Can't open device %s: %s\n" msgstr " Nie można otworzyć urzÄ…dzenia %s: %s\n" #: .././logprint/logprint.c:85 #, c-format msgid " read of XFS superblock failed\n" msgstr " odczyt superbloku XFS-a nie powiódÅ‚ siÄ™\n" #: .././logprint/logprint.c:105 #, c-format msgid "" " external log device not specified\n" "\n" msgstr "" " Nie podano urzÄ…dzenia zewnÄ™trznego loga\n" "\n" #: .././logprint/logprint.c:121 #, c-format msgid "Can't open file %s: %s\n" msgstr "Nie można otworzyć pliku %s: %s\n" #: .././logprint/logprint.c:222 #, c-format msgid "xfs_logprint:\n" msgstr "xfs_logprint:\n" #: .././logprint/logprint.c:231 #, c-format msgid " data device: 0x%llx\n" msgstr " urzÄ…dzenie danych: 0x%llx\n" #: .././logprint/logprint.c:234 #, c-format msgid " log file: \"%s\" " msgstr " plik logu: \"%s\" " #: .././logprint/logprint.c:236 #, c-format msgid " log device: 0x%llx " msgstr " urzÄ…dzenie logu: 0x%llx " #: .././logprint/logprint.c:239 #, c-format msgid "" "daddr: %lld length: %lld\n" "\n" msgstr "" "daddr: %lld dÅ‚ugość: %lld\n" "\n" #: .././mkfs/proto.c:79 #, c-format msgid "%s: failed to open %s: %s\n" msgstr "%s: nie udaÅ‚o siÄ™ otworzyć %s: %s\n" #: .././mkfs/proto.c:86 .././mkfs/proto.c:309 #, c-format msgid "%s: read failed on %s: %s\n" msgstr "%s: odczyt nie powiódÅ‚ siÄ™ dla %s: %s\n" #: .././mkfs/proto.c:91 #, c-format msgid "%s: proto file %s premature EOF\n" msgstr "%s: plik prototypu %s skoÅ„czyÅ‚ siÄ™ przedwczeÅ›nie\n" #: .././mkfs/proto.c:125 msgid "cannot reserve space" msgstr "nie można zarezerwować miejsca" #: .././mkfs/proto.c:180 #, c-format msgid "%s: premature EOF in prototype file\n" msgstr "%s: przedwczesny EOF w pliku prototypu\n" #: .././mkfs/proto.c:200 msgid "error reserving space for a file" msgstr "błąd podczas rezerwowania miejsca na plik" #: .././mkfs/proto.c:267 msgid "error allocating space for a file" msgstr "błąd podczas przydzielania miejsca na plik" #: .././mkfs/proto.c:271 #, c-format msgid "%s: cannot allocate space for file\n" msgstr "%s: nie można przydzielić miejsca na plik\n" #: .././mkfs/proto.c:336 msgid "directory createname error" msgstr "błąd tworzenia nazwy katalogu" #: .././mkfs/proto.c:350 msgid "directory create error" msgstr "błąd tworzenia katalogu" #: .././mkfs/proto.c:415 .././mkfs/proto.c:427 .././mkfs/proto.c:438 #: .././mkfs/proto.c:445 #, c-format msgid "%s: bad format string %s\n" msgstr "%s: błędny Å‚aÅ„cuch formatujÄ…cy %s\n" #: .././mkfs/proto.c:466 .././mkfs/proto.c:514 .././mkfs/proto.c:529 #: .././mkfs/proto.c:541 .././mkfs/proto.c:553 .././mkfs/proto.c:564 msgid "Inode allocation failed" msgstr "Przydzielanie i-wÄ™zÅ‚a nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:481 #, c-format msgid "%s: Bad value %s for proto file %s\n" msgstr "%s: błędna wartość %s dla pliku proto %s\n" #: .././mkfs/proto.c:490 msgid "Inode pre-allocation failed" msgstr "Wczesne przydzielanie i-wÄ™zÅ‚a nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:501 msgid "Pre-allocated file creation failed" msgstr "Tworzenie wczeÅ›nie przydzielonego pliku nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:584 msgid "Directory creation failed" msgstr "Tworzenie katalogu nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:605 msgid "Unknown format" msgstr "Nieznany format" #: .././mkfs/proto.c:611 msgid "Error encountered creating file from prototype file" msgstr "WystÄ…piÅ‚ błąd podczas tworzenia pliku z pliku prototypu" #: .././mkfs/proto.c:663 msgid "Realtime bitmap inode allocation failed" msgstr "Przydzielanie i-wÄ™zÅ‚a bitmapy realtime nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:680 msgid "Realtime summary inode allocation failed" msgstr "Tworzenie i-wÄ™zÅ‚a opisu realtime nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:707 msgid "Allocation of the realtime bitmap failed" msgstr "Przydzielenie bitmapy realtime nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:721 msgid "Completion of the realtime bitmap failed" msgstr "UzupeÅ‚nienie bitmapy realtime nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:744 msgid "Allocation of the realtime summary failed" msgstr "Przydzielenie opisu realtime nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:757 msgid "Completion of the realtime summary failed" msgstr "UzupeÅ‚nienie opisu realtime nie powiodÅ‚o siÄ™" #: .././mkfs/proto.c:775 msgid "Error initializing the realtime space" msgstr "Błąd podczas inicjalizacji przestrzeni realtime" #: .././mkfs/proto.c:781 msgid "Error completing the realtime space" msgstr "Błąd podczas uzupeÅ‚niania przestrzeni realtime" #: .././mkfs/xfs_mkfs.c:866 #, c-format msgid "" "Usage: %s\n" "/* blocksize */\t\t[-b size=num]\n" "/* metadata */\t\t[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n" "/* data subvol */\t[-d agcount=n,agsize=n,file,name=xxx,size=num,\n" "\t\t\t (sunit=value,swidth=value|su=num,sw=num|noalign),\n" "\t\t\t sectsize=num\n" "/* force overwrite */\t[-f]\n" "/* inode size */\t[-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2,\n" "\t\t\t projid32bit=0|1,sparse=0|1]\n" "/* no discard */\t[-K]\n" "/* log subvol */\t[-l agnum=n,internal,size=num,logdev=xxx,version=n\n" "\t\t\t sunit=value|su=num,sectsize=num,lazy-count=0|1]\n" "/* label */\t\t[-L label (maximum 12 characters)]\n" "/* naming */\t\t[-n size=num,version=2|ci,ftype=0|1]\n" "/* no-op info only */\t[-N]\n" "/* prototype file */\t[-p fname]\n" "/* quiet */\t\t[-q]\n" "/* realtime subvol */\t[-r extsize=num,size=num,rtdev=xxx]\n" "/* sectorsize */\t[-s size=num]\n" "/* version */\t\t[-V]\n" "\t\t\tdevicename\n" " is required unless -d name=xxx is given.\n" " is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n" " xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n" " is xxx (512 byte blocks).\n" msgstr "" "SkÅ‚adnia: %s\n" "/* rozmiar bloku */ [-b size=ile]\n" "/* metadane */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|" "1]\n" "/* podwolumen danych */ [-d agcount=n,agsize=n,file,name=xxx,size=ile,\n" " (sunit=wartość,swidth=wartość|su=ile,sw=ile|" "noalign),\n" " sectsize=ile]\n" "/* wym. nadpisania */ [-f]\n" "/* rozmiar i-wÄ™zÅ‚a */ [-i log=n|perblock=n|size=ile,maxpct=n,attr=0|1|2,\n" " projid32bit=0|1,sparse=0|1]\n" "/* bez porzucania */ [-K]\n" "/* podwolumen logu */ [-l agnum=n,internal,size=ile,logdev=xxx,version=n\n" " sunit=wartość|su=ile,sectsize=ile,lazy-count=0|" "1]\n" "/* etykieta */ [-L etykieta (maksymalnie 12 znaków)]\n" "/* nazwy */ [-n size=ile,version=2|ci,ftype=0|1]\n" "/* tylko info no-op */ [-N]\n" "/* plik prototypu */ [-p nazwa_pliku]\n" "/* cisza */ [-q]\n" "/* podwolumen rt */ [-r extsize=ile,size=ile,rtdev=xxx]\n" "/* rozmiar sektora */ [-s size=ile]\n" "/* wersja */ [-V]\n" " nazwa_urzÄ…dzenia\n" " jest wymagana, chyba że podano -d name=xxx.\n" " to xxx (bajtów), xxxs (sektorów), xxxb (bloków systemu plików),\n" " xxxk (xxx KiB), xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB),\n" " xxxp (xxx PiB).\n" " to xxx (512-bajtowych bloków).\n" #: .././mkfs/xfs_mkfs.c:902 #, c-format msgid "Cannot specify both -%c %s and -%c %s\n" msgstr "Nie można podać jednoczeÅ›nie -%c %s i %c %s\n" #: .././mkfs/xfs_mkfs.c:914 #, c-format msgid "Invalid value %s for -%s option\n" msgstr "Błędna wartość %s dla opcji -%s\n" #: .././mkfs/xfs_mkfs.c:931 #, c-format msgid "-%c %s option requires a value\n" msgstr "Opcja -%c %s wymaga wartoÅ›ci\n" #: .././mkfs/xfs_mkfs.c:944 .././repair/xfs_repair.c:170 #, c-format msgid "option respecified\n" msgstr "ponownie podana opcja\n" #: .././mkfs/xfs_mkfs.c:953 .././repair/xfs_repair.c:177 #, c-format msgid "unknown option -%c %s\n" msgstr "nieznana opcja -%c %s\n" #: .././mkfs/xfs_mkfs.c:979 #, c-format msgid "Blocksize must be provided prior to using 'b' suffix.\n" msgstr "Rozmiar bloku musi być przekazany przed użyciem przyrostka 'b'.\n" #: .././mkfs/xfs_mkfs.c:988 #, c-format msgid "Sectorsize must be specified prior to using 's' suffix.\n" msgstr "Rozmiar sektora musi być przekazany przed użyciem przyrostka 's'.\n" #: .././mkfs/xfs_mkfs.c:1034 #, c-format msgid "if -%s file then -%s name and -%s size are required\n" msgstr "jeÅ›li podano -%s file, to -%s name i -%s size sÄ… wymagane\n" #: .././mkfs/xfs_mkfs.c:1040 #, c-format msgid "No device name specified\n" msgstr "Nie podano nazwy urzÄ…dzenia\n" #: .././mkfs/xfs_mkfs.c:1052 #, c-format msgid "Error accessing specified device %s: %s\n" msgstr "Błąd podczas dostÄ™pu do podanego urzÄ…dzenia %s: %s\n" #: .././mkfs/xfs_mkfs.c:1060 #, c-format msgid "%s: Use the -f option to force overwrite.\n" msgstr "%s: Można użyć opcji -f do wymuszenia nadpisania.\n" #: .././mkfs/xfs_mkfs.c:1081 #, c-format msgid "specified \"-%s file\" on a block device %s\n" msgstr "podano \"-%s plik\" dla urzÄ…dzenia blokowego %s\n" #: .././mkfs/xfs_mkfs.c:1089 #, c-format msgid "specified device %s not a file or block device\n" msgstr "podane urzÄ…dzenie %s nie jest plikiem ani urzÄ…dzeniem blokowym\n" #: .././mkfs/xfs_mkfs.c:1103 #, c-format msgid "agsize (%lld blocks) too small, need at least %lld blocks\n" msgstr "agsize (%lld bloków) zbyt maÅ‚e, potrzeba co najmniej %lld bloków\n" #: .././mkfs/xfs_mkfs.c:1111 #, c-format msgid "agsize (%lld blocks) too big, maximum is %lld blocks\n" msgstr "agsize (%lld bloków) zbyt duże, maksimum to %lld bloków\n" #: .././mkfs/xfs_mkfs.c:1119 #, c-format msgid "agsize (%lld blocks) too big, data area is %lld blocks\n" msgstr "agsize (%lld bloków) zbyt duże, obszar danych to %lld bloków\n" #: .././mkfs/xfs_mkfs.c:1126 #, c-format msgid "too many allocation groups for size = %lld\n" msgstr "zbyt dużo grup alokacji dla rozmiaru = %lld\n" #: .././mkfs/xfs_mkfs.c:1128 #, c-format msgid "need at most %lld allocation groups\n" msgstr "potrzeba najwyżej %lld grup alokacji\n" #: .././mkfs/xfs_mkfs.c:1136 #, c-format msgid "too few allocation groups for size = %lld\n" msgstr "zbyt maÅ‚o grup alokacji dla rozmiaru = %lld\n" #: .././mkfs/xfs_mkfs.c:1138 #, c-format msgid "need at least %lld allocation groups\n" msgstr "potrzeba co najmniej %lld grup alokacji\n" #: .././mkfs/xfs_mkfs.c:1151 #, c-format msgid "last AG size %lld blocks too small, minimum size is %lld blocks\n" msgstr "" "rozmiar ostatniej AG %lld bloków zbyt maÅ‚y, minimalny rozmiar to %lld " "bloków\n" #: .././mkfs/xfs_mkfs.c:1162 #, c-format msgid "%lld allocation groups is too many, maximum is %lld\n" msgstr "%lld grup alokacji to zbyt dużo, maksimum to %lld\n" #: .././mkfs/xfs_mkfs.c:1192 #, c-format msgid "error reading existing superblock -- failed to memalign buffer\n" msgstr "" "błąd podczas odczytu istniejÄ…cego superbloku - nie udaÅ‚o siÄ™ wykonać " "memalign dla bufora\n" #: .././mkfs/xfs_mkfs.c:1207 #, c-format msgid "error reading existing superblock: %s\n" msgstr "błąd podczas odczytu istniejÄ…cego superbloku: %s\n" #: .././mkfs/xfs_mkfs.c:1270 #, c-format msgid "Invalid value %s for -%c %s option. %s\n" msgstr "Błędna wartość %s dla opcji -%c %s. %s\n" #: .././mkfs/xfs_mkfs.c:1290 #, c-format msgid "Developer screwed up option parsing (%d/%d)! Please report!\n" msgstr "Programista schrzaniÅ‚ analizÄ™ opcji (%d/%d)! ProszÄ™ zgÅ‚osić!\n" #: .././mkfs/xfs_mkfs.c:1344 #, c-format msgid "" "Option -%c %s has undefined minval/maxval.Can't verify value range. This is " "a bug.\n" msgstr "" "Opcja -%c %s nie ma okreÅ›lonych wartoÅ›ci minimalnej/maksymalnej. Nie można " "sprawdzić zakresu - to błąd.\n" #: .././mkfs/xfs_mkfs.c:1364 msgid "Value not recognized as number." msgstr "Wartość nie rozpoznana jako liczba." #: .././mkfs/xfs_mkfs.c:1367 msgid "Unit suffixes are not allowed." msgstr "Przyrostki jednostek nie sÄ… dozwolone." #: .././mkfs/xfs_mkfs.c:1372 msgid "Value is too small." msgstr "Wartość zbyt maÅ‚a." #: .././mkfs/xfs_mkfs.c:1374 msgid "Value is too large." msgstr "Wartość zbyt duża." #: .././mkfs/xfs_mkfs.c:1376 msgid "Value must be a power of 2." msgstr "Wartość musi być potÄ™gÄ… liczby 2." #: .././mkfs/xfs_mkfs.c:1793 #, c-format msgid "" "specified blocksize %d is less than device physical sector size %d\n" "switching to logical sector size %d\n" msgstr "" "podany rozmiar bloku %d jest mniejszy niż rozmiar fizycznego sektora " "urzÄ…dzenia %d\n" "przełączanie na rozmiar sektora logicznego %d\n" #: .././mkfs/xfs_mkfs.c:1806 #, c-format msgid "illegal sector size %d\n" msgstr "niedozwolony rozmiar sektora %d\n" #: .././mkfs/xfs_mkfs.c:1812 #, c-format msgid "block size %d cannot be smaller than sector size %d\n" msgstr "rozmiar bloku %d nie może być mniejszy niż rozmiar sektora %d\n" #: .././mkfs/xfs_mkfs.c:1818 #, c-format msgid "illegal sector size %d; hw sector is %d\n" msgstr "niedozwolony rozmiar sektora %d; sektor sprzÄ™towy ma %d\n" #: .././mkfs/xfs_mkfs.c:1844 #, c-format msgid "illegal block size %d\n" msgstr "niedozwolony rozmiar bloku %d\n" #: .././mkfs/xfs_mkfs.c:1851 #, c-format msgid "Minimum block size for CRC enabled filesystems is %d bytes.\n" msgstr "Minimalny rozmiar bloku systemów plików z CRC to %d bajtów.\n" #: .././mkfs/xfs_mkfs.c:1874 #, c-format msgid "Can't change sector size on internal log!\n" msgstr "Nie można zmienić rozmiaru sektora logu wewnÄ™trznego!\n" #: .././mkfs/xfs_mkfs.c:1889 #, c-format msgid "illegal log sector size %d\n" msgstr "niedozwolony rozmiar sektora logu %d\n" #: .././mkfs/xfs_mkfs.c:1897 #, c-format msgid "Version 1 logs do not support sector size %d\n" msgstr "Wersja logów 1 nie obsÅ‚uguje rozmiaru sektora %d\n" #: .././mkfs/xfs_mkfs.c:1907 #, c-format msgid "log stripe unit specified, using v2 logs\n" msgstr "podano jednostkÄ™ pasa logu, użyto logów v2\n" #: .././mkfs/xfs_mkfs.c:1934 .././mkfs/xfs_mkfs.c:2100 #, c-format msgid "Minimum inode size for CRCs is %d bytes\n" msgstr "Minimalny rozmiar i-wÄ™zÅ‚a dla CRC to %d bajtów\n" #: .././mkfs/xfs_mkfs.c:1942 #, c-format msgid "Inodes always aligned for CRC enabled filesystems\n" msgstr "I-wÄ™zÅ‚y sÄ… zawsze wyrównane dla systemów plików z CRC\n" #: .././mkfs/xfs_mkfs.c:1949 #, c-format msgid "Lazy superblock counters always enabled for CRC enabled filesystems\n" msgstr "" "Leniwe liczenie syperbloków jest zawsze włączone dla systemów plików z CRC\n" #: .././mkfs/xfs_mkfs.c:1956 #, c-format msgid "V2 logs always enabled for CRC enabled filesystems\n" msgstr "Logi V2 sÄ… zawsze włączone dla systemów plików z CRC\n" #: .././mkfs/xfs_mkfs.c:1963 #, c-format msgid "V2 attribute format always enabled on CRC enabled filesystems\n" msgstr "Format atrybutów V2 jest zawsze włączony dla systemów plików z CRC\n" #: .././mkfs/xfs_mkfs.c:1971 #, c-format msgid "32 bit Project IDs always enabled on CRC enabled filesystems\n" msgstr "32-bitowe ID projektów sÄ… zawsze włączone dla systemów plików z CRC\n" #: .././mkfs/xfs_mkfs.c:1978 #, c-format msgid "Directory ftype field always enabled on CRC enabled filesystems\n" msgstr "Pole ftype katalogu jest zawsze włączone dla systemów plików z CRC\n" #: .././mkfs/xfs_mkfs.c:1994 #, c-format msgid "finobt not supported without CRC support\n" msgstr "finobt nie jest obsÅ‚ugiwane bez obsÅ‚ugi CRC\n" #: .././mkfs/xfs_mkfs.c:2001 #, c-format msgid "sparse inodes not supported without CRC support\n" msgstr "i-wÄ™zÅ‚y rzadkie nie sÄ… obsÅ‚ugiwane bez obsÅ‚ugi CRC\n" #: .././mkfs/xfs_mkfs.c:2008 #, c-format msgid "rmapbt not supported without CRC support\n" msgstr "rmapbt nie jest obsÅ‚ugiwane bez obsÅ‚ugi CRC\n" #: .././mkfs/xfs_mkfs.c:2015 #, c-format msgid "reflink not supported without CRC support\n" msgstr "reflink nie jest obsÅ‚ugiwane bez obsÅ‚ugi CRC\n" #: .././mkfs/xfs_mkfs.c:2024 #, c-format msgid "cowextsize not supported without reflink support\n" msgstr "cowextsize nie jest obsÅ‚ugiwane bez obsÅ‚ugi reflink\n" #: .././mkfs/xfs_mkfs.c:2030 #, c-format msgid "reflink not supported with realtime devices\n" msgstr "reflink nie jest obsÅ‚ugiwane dla urzÄ…dzeÅ„ realtime\n" #: .././mkfs/xfs_mkfs.c:2037 #, c-format msgid "rmapbt not supported with realtime devices\n" msgstr "rmapbt nie jest obsÅ‚ugiwane dla urzÄ…dzeÅ„ realtime\n" #: .././mkfs/xfs_mkfs.c:2062 #, c-format msgid "illegal directory block size %d\n" msgstr "niedozwolony rozmiar bloku katalogu %d\n" #: .././mkfs/xfs_mkfs.c:2111 #, c-format msgid "illegal inode size %d\n" msgstr "niedozwolony rozmiar i-wÄ™zÅ‚a %d\n" #: .././mkfs/xfs_mkfs.c:2116 #, c-format msgid "allowable inode size with %d byte blocks is %d\n" msgstr "dozwolony rozmiar i-wÄ™zÅ‚a przy blokach %d-bajtowych to %d\n" #: .././mkfs/xfs_mkfs.c:2120 #, c-format msgid "allowable inode size with %d byte blocks is between %d and %d\n" msgstr "dozwolone rozmiary i-wÄ™zÅ‚a przy blokach %d-bajtowych sÄ… od %d do %d\n" #: .././mkfs/xfs_mkfs.c:2143 #, c-format msgid "illegal %s length %lld, not a multiple of %d\n" msgstr "niedozwolona dÅ‚ugość %s %lld, nie jest wielokrotnoÅ›ciÄ… %d\n" #: .././mkfs/xfs_mkfs.c:2150 #, c-format msgid "warning: %s length %lld not a multiple of %d, truncated to %lld\n" msgstr "uwaga: dÅ‚ugość %s %lld nie jest wielokrotnoÅ›ciÄ… %d, uciÄ™to do %lld\n" #: .././mkfs/xfs_mkfs.c:2173 #, c-format msgid "illegal rt extent size %lld, not a multiple of %d\n" msgstr "niedozwolony rozmiar ekstentu rt %lld, nie jest wielokrotnoÅ›ciÄ… %d\n" #: .././mkfs/xfs_mkfs.c:2245 #, c-format msgid "both data sunit and data swidth options must be specified\n" msgstr "trzeba podać obie opcje sunit i swidth dla danych\n" #: .././mkfs/xfs_mkfs.c:2253 #, c-format msgid "both data su and data sw options must be specified\n" msgstr "trzeba podać obie opcje su i sw dla danych\n" #: .././mkfs/xfs_mkfs.c:2259 #, c-format msgid "data su must be a multiple of the sector size (%d)\n" msgstr "su danych musi być wielokrotnoÅ›ciÄ… rozmiaru sektora (%d)\n" #: .././mkfs/xfs_mkfs.c:2267 #, c-format msgid "" "data stripe width (%lld) is too large of a multiple of the data stripe unit " "(%d)\n" msgstr "" "szerokość pasa danych (%lld) jest zbyt dużą wielokrotnoÅ›ciÄ… jednostki pasa " "danych (%d)\n" #: .././mkfs/xfs_mkfs.c:2276 #, c-format msgid "" "data stripe width (%d) must be a multiple of the data stripe unit (%d)\n" msgstr "" "szerokość pasa danych (%d) musi być wielokrotnoÅ›ciÄ… jednostki pasa danych " "(%d)\n" #: .././mkfs/xfs_mkfs.c:2302 #, c-format msgid "" "%s: Specified data stripe unit %d is not the same as the volume stripe unit " "%d\n" msgstr "" "%s: Podana jednostka pasa danych %d nie jest taka sama jak jednostka pasa " "wolumenu %d\n" #: .././mkfs/xfs_mkfs.c:2307 #, c-format msgid "" "%s: Specified data stripe width %d is not the same as the volume stripe " "width %d\n" msgstr "" "%s: Podana szerokość pasa danych %d nie jest taka sama jak szerokość pasa " "wolumenu %d\n" #: .././mkfs/xfs_mkfs.c:2324 #, c-format msgid "" "%s: Stripe unit(%d) or stripe width(%d) is not a multiple of the block " "size(%d)\n" msgstr "" "%s: Jednostka pasa (%d) lub szerokość pasa (%d) nie jest wielokrotnoÅ›ciÄ… " "rozmiaru bloku (%d)\n" #: .././mkfs/xfs_mkfs.c:2351 .././mkfs/xfs_mkfs.c:2359 #, c-format msgid "log stripe unit (%d) must be a multiple of the block size (%d)\n" msgstr "" "jednostka pasa logu (%d) musi być wielokrotnoÅ›ciÄ… rozmiaru bloku (%d)\n" #: .././mkfs/xfs_mkfs.c:2381 #, c-format msgid "" "log stripe unit (%d bytes) is too large (maximum is 256KiB)\n" "log stripe unit adjusted to 32KiB\n" msgstr "" "jednostka pasa logu (%d bajtów) jest zbyt duża (maksimum to 256KiB)\n" "jednostkÄ™ pasa logu zmieniono na 32KiB\n" #: .././mkfs/xfs_mkfs.c:2406 #, c-format msgid "no device name given in argument list\n" msgstr "nie podano nazwy urzÄ…dzenia w liÅ›cie argumentów\n" #: .././mkfs/xfs_mkfs.c:2451 #, c-format msgid "can't get size of data subvolume\n" msgstr "nie można pobrać rozmiaru podwolumenu danych\n" #: .././mkfs/xfs_mkfs.c:2459 #, c-format msgid "" "size %s specified for data subvolume is too large, maximum is %lld blocks\n" msgstr "" "rozmiar %s podany dla podwolumenu danych jest zbyt duży, maksimum to %lld " "bloków\n" #: .././mkfs/xfs_mkfs.c:2471 #, c-format msgid "size %lld of data subvolume is too small, minimum %d blocks\n" msgstr "" "rozmiar %lld dla podwolumenu danych jest zbyt maÅ‚y, minimum to %d bloków\n" #: .././mkfs/xfs_mkfs.c:2478 #, c-format msgid "" "Warning: the data subvolume sector size %u is less than the sector size \n" "reported by the device (%u).\n" msgstr "" "Uwaga: rozmiar sektora podwolumenu danych %u jest mniejszy od rozmiaru\n" "sektora zgÅ‚aszanego przez urzÄ…dzenie (%u).\n" #: .././mkfs/xfs_mkfs.c:2501 msgid "volume log" msgstr "log na wolumenie" #: .././mkfs/xfs_mkfs.c:2510 #, c-format msgid "can't have both external and internal logs\n" msgstr "nie można mieć jednoczeÅ›nie zewnÄ™trznego i wewnÄ™trznego logu\n" #: .././mkfs/xfs_mkfs.c:2526 #, c-format msgid "data and log sector sizes must be equal for internal logs\n" msgstr "" "rozmiary sektora danych i logu muszÄ… być równe dla logów wewnÄ™trznych\n" #: .././mkfs/xfs_mkfs.c:2531 #, c-format msgid "log size %lld too large for internal log\n" msgstr "rozmiar logu %lld jest zbyt duży dla logu wewnÄ™trznego\n" #: .././mkfs/xfs_mkfs.c:2535 msgid "internal log" msgstr "log wewnÄ™trzny" #: .././mkfs/xfs_mkfs.c:2543 #, c-format msgid "no log subvolume or external log.\n" msgstr "brak podwolumenu logu ani logu zewnÄ™trznego.\n" #: .././mkfs/xfs_mkfs.c:2550 #, c-format msgid "unable to get size of the log subvolume.\n" msgstr "nie można pobrać rozmiaru podwolumenu logu.\n" #: .././mkfs/xfs_mkfs.c:2556 #, c-format msgid "" "size %s specified for log subvolume is too large, maximum is %lld blocks\n" msgstr "" "rozmiar %s podany dla podwolumenu logu jest zbyt duży, maksimum to %lld " "bloków\n" #: .././mkfs/xfs_mkfs.c:2564 #, c-format msgid "" "Warning: the log subvolume sector size %u is less than the sector size\n" "reported by the device (%u).\n" msgstr "" "Uwaga: rozmiar sektora podwolumenu logu %u jest mniejszy od rozmiaru\n" "sektora zgÅ‚aszanego przez urzÄ…dzenie (%u).\n" #: .././mkfs/xfs_mkfs.c:2583 #, c-format msgid "size specified for non-existent rt subvolume\n" msgstr "podano rozmiar dla nie istniejÄ…cego podwolumenu rt\n" #: .././mkfs/xfs_mkfs.c:2594 #, c-format msgid "Invalid zero length rt subvolume found\n" msgstr "Znaleziono błędnÄ… zerowÄ… dÅ‚ugość podwolumenu rt\n" #: .././mkfs/xfs_mkfs.c:2600 msgid "volume rt" msgstr "wolumen rt" #: .././mkfs/xfs_mkfs.c:2607 #, c-format msgid "" "size %s specified for rt subvolume is too large, maxi->um is %lld blocks\n" msgstr "" "rozmiar %s podany dla podwolumenu rt jest zbyt duży, maksimum to %lld " "bloków\n" #: .././mkfs/xfs_mkfs.c:2614 #, c-format msgid "" "Warning: the realtime subvolume sector size %u is less than the sector size\n" "reported by the device (%u).\n" msgstr "" "Uwaga: rozmiar sektora podwolumenu realtime %u jest mniejszy od rozmiaru\n" "sektora zgÅ‚aszanego przez urzÄ…dzenie (%u).\n" #: .././mkfs/xfs_mkfs.c:2641 #, c-format msgid "agsize (%s) not a multiple of fs blk size (%d)\n" msgstr "" "agsize (%s) nie jest wielokrotnoÅ›ciÄ… rozmiaru bloku systemu plików (%d)\n" #: .././mkfs/xfs_mkfs.c:2723 #, c-format msgid "agsize rounded to %lld, sunit = %d\n" msgstr "agsize zaokrÄ…glone do %lld, sunit = %d\n" #: .././mkfs/xfs_mkfs.c:2734 #, c-format msgid "" "Warning: AG size is a multiple of stripe width. This can cause performance\n" "problems by aligning all AGs on the same disk. To avoid this, run mkfs " "with\n" "an AG size that is one stripe unit smaller or larger, for example %llu.\n" msgstr "" "Uwaga: rozmiar AG jest wielokrotnoÅ›ciÄ… szerokoÅ›ci pasa. Może to spowodować\n" "problemy z wydajnoÅ›ciÄ… poprzez wyrównanie wszystkich AG na tym samym dysku.\n" "Aby temu zapobiec, należy uruchomić mkfs z rozmiarem AG o jednÄ… jednostkÄ™\n" "pasa mniejszym, na przykÅ‚ad %llu.\n" #: .././mkfs/xfs_mkfs.c:2924 #, c-format msgid "log size %lld is not a multiple of the log stripe unit %d\n" msgstr "rozmiar logu %lld nie jest wielokrotnoÅ›ciÄ… jednostki pasa logu %d\n" #: .././mkfs/xfs_mkfs.c:2959 #, c-format msgid "" "Due to stripe alignment, the internal log size (%lld) is too large.\n" "Must fit within an allocation group.\n" msgstr "" "Ze wzglÄ™du na wyrównanie do rozmiaru pasa rozmiar wewnÄ™trznego logu (%lld) " "jest zbyt duży. Musi sie mieÅ›cić w grupie alokacji.\n" #: .././mkfs/xfs_mkfs.c:2971 #, c-format msgid "log size %lld blocks too small, minimum size is %d blocks\n" msgstr "" "rozmiar logu %lld bloków jest zbyt maÅ‚y, minimalny rozmiar to %d bloków\n" #: .././mkfs/xfs_mkfs.c:2977 #, c-format msgid "log size %lld blocks too large, maximum size is %lld blocks\n" msgstr "" "rozmiar logu %lld bloków jest zbyt duży, maksymalny rozmiar to %lld bloków\n" #: .././mkfs/xfs_mkfs.c:2983 #, c-format msgid "log size %lld bytes too large, maximum size is %lld bytes\n" msgstr "" "rozmiar logu %lld bajtów jest zbyt duży, maksymalny rozmiar to %lld bajtów\n" #: .././mkfs/xfs_mkfs.c:3022 #, c-format msgid "external log device %lld too small, must be at least %lld blocks\n" msgstr "" "urzÄ…dzenie logu zewnÄ™trznego %lld zbyt maÅ‚e, potrzeba co najmniej %lld " "bloków\n" #: .././mkfs/xfs_mkfs.c:3087 #, c-format msgid "internal log size %lld too large, must fit in allocation group\n" msgstr "" "rozmiar wewnÄ™trznego logu %lld zbyt duży, musi siÄ™ zmieÅ›cić w grupie " "alokacji\n" #: .././mkfs/xfs_mkfs.c:3095 #, c-format msgid "log ag number %lld too large, must be less than %lld\n" msgstr "liczba ag logu %lld zbyt duża, musi być mniejsza niż %lld\n" #: .././mkfs/xfs_mkfs.c:3185 #, c-format msgid "" "meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u, reflink=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n" "log =%-22s bsize=%-6d blocks=%lld, version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n" msgstr "" "metadane=%-22s isize=%-6d agcount=%lld, agsize=%lld bloków\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u, reflink=%u\n" "dane =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u bloków\n" "nazwy =wersja %-14u bsize=%-6u ascii-ci=%d ftype=%d\n" "log =%-22s bsize=%-6d blocks=%lld, wersja=%d\n" " =%-22s sectsz=%-5u sunit=%d bloków, lazy-count=%d\n" "realtime=%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n" #: .././mkfs/xfs_mkfs.c:3286 #, c-format msgid "%s: Growing the data section failed\n" msgstr "%s: PowiÄ™kszenie sekcji danych nie powiodÅ‚o siÄ™\n" #: .././mkfs/xfs_mkfs.c:3800 msgid "package build definitions" msgstr "definicje przy budowaniu pakietu" #: .././mkfs/xfs_mkfs.c:3890 #, c-format msgid "extra arguments\n" msgstr "nadmiarowe argumenty\n" #: .././mkfs/xfs_mkfs.c:3990 #, c-format msgid "%s: filesystem failed to initialize\n" msgstr "%s: nie udaÅ‚o siÄ™ zainicjować systemu plików\n" #: .././mkfs/xfs_mkfs.c:4017 #, c-format msgid "%s: root inode created in AG %u, not AG 0\n" msgstr "%s: główny i-wÄ™zeÅ‚ utworzony w AG %u, nie AG 0\n" #: .././quota/edit.c:36 #, c-format msgid "" "\n" " modify quota limits for the specified user\n" "\n" " Example:\n" " 'limit bsoft=100m bhard=110m tanya\n" "\n" " Changes the soft and/or hard block limits, inode limits and/or realtime\n" " block limits that are currently being used for the specified user, group,\n" " or project. The filesystem identified by the current path is modified.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota limits\n" " -p -- modify project quota limits\n" " -u -- modify user quota limits\n" " The block limit values can be specified with a units suffix - accepted\n" " units are: k (kilobytes), m (megabytes), g (gigabytes), and t (terabytes).\n" " The user/group/project can be specified either by name or by number.\n" "\n" msgstr "" "\n" " zmiana limitów quot dla podanego użytkownika\n" "\n" "PrzykÅ‚ad:\n" " 'limit bsoft=100m bhard=110m tanya'\n" "\n" " limit zmienia miÄ™kki i/lub twardy limit bloków, limity i-wÄ™złów i/lub " "limity\n" " bloków realtime aktualnie używane dla podanego użytkownika, grupy lub " "projektu.\n" " System plików okreÅ›lony bieżącÄ… Å›cieżkÄ… jest modyfikowany.\n" " -d - ustawienie wartoÅ›ci domyÅ›lnych, użytych pierwszy raz przy tworzeniu " "pliku\n" " -g - zmiana limitów quot grupy\n" " -p - zmiana limitów quot projektu\n" " -u - zmiana limitów quot użytkownika\n" " WartoÅ›ci limitów bloków mogÄ… być podane z koÅ„cówkÄ… jednostki - przyjmowane\n" " jednostki to: k (kilobajty), m (megabajty), g (gigabajty) i t (terabajty).\n" " Użytkownik/grupa/projekt może być podany za pomocÄ… nazwy lub numeru.\n" "\n" #: .././quota/edit.c:59 #, c-format msgid "" "\n" " modify quota enforcement timeout for the current filesystem\n" "\n" " Example:\n" " 'timer -i 3days'\n" " (soft inode limit timer is changed to 3 days)\n" "\n" " Changes the timeout value associated with the block limits, inode limits\n" " and/or realtime block limits for all users, groups, or projects on the\n" " current filesystem.\n" " As soon as a user consumes the amount of space or number of inodes set as\n" " the soft limit, a timer is started. If the timer expires and the user is\n" " still over the soft limit, the soft limit is enforced as the hard limit.\n" " The default timeout is 7 days.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota timer\n" " -p -- modify project quota timer\n" " -u -- modify user quota timer\n" " -b -- modify the blocks-used timer\n" " -i -- modify the inodes-used timer\n" " -r -- modify the blocks-used timer for the (optional) realtime subvolume\n" " The timeout value is specified as a number of seconds, by default.\n" " However, a suffix may be used to alternatively specify minutes (m),\n" " hours (h), days (d), or weeks (w) - either the full word or the first\n" " letter of the word can be used.\n" "\n" msgstr "" "\n" " zmiana czasu wymuszenia limitów dla bieżącego systemu plików\n" "\n" " PrzykÅ‚ad:\n" " 'timer -i 3days'\n" " (zmiana czasu wymuszenia miÄ™kkiego limitu i-wÄ™złów na 3 dni)\n" "\n" " timer zmienia wartość ograniczenia czasu zwiÄ…zanego z limitami bloków,\n" " limitami i-wÄ™złów i/lub limitami bloków realtime dla wszystkich " "użytkowników,\n" " grup lub projektów na bieżącym systemie plików.\n" " Po tym jak użytkownik wykorzysta ilość miejsca lub liczbÄ™ i-wÄ™złów " "ustawionÄ…\n" " jako miÄ™kki limit, zaczyna dziaÅ‚ać zegar. Kiedy czas minie, a użytkownik " "nadal\n" " przekracza miÄ™kki limit, miÄ™kki limit staje siÄ™ twardym.\n" " DomyÅ›lne ograniczenie czasowe to 7 dni.\n" " -d - ustawienie wartoÅ›ci domyÅ›lnych, użytych pierwszy raz przy tworzeniu " "pliku\n" " -g - zmiana czasu dla limitów quot grup\n" " -p - zmiana czasu dla limitów quot projektów\n" " -u - zmiana czasu dla limitów quot użytkowników\n" " -b - zmiana czasu dla użytych bloków\n" " -i - zmiana czasu dla użytych i-wÄ™złów\n" " -r - zmiana czasu dla użytych bloków na (opcjonalnym) podwolumenie " "realtime\n" " Wartość ograniczenia czasu jest podawana domyÅ›lnie jako liczba sekund.\n" " Jednak można dodać koÅ„cówkÄ™, aby podać czas w minutach (m), godzinach (h),\n" " dniach (d) lub tygodniach (w) - można użyć peÅ‚nego sÅ‚owa lub pierwsze " "litery.\n" "\n" #: .././quota/edit.c:91 #, c-format msgid "" "\n" " modify the number of quota warnings sent to the specified user\n" "\n" " Example:\n" " 'warn 2 jimmy'\n" " (tell the quota system that two warnings have been sent to user jimmy)\n" "\n" " Changes the warning count associated with the block limits, inode limits\n" " and/or realtime block limits for the specified user, group, or project.\n" " When a user has been warned the maximum number of times allowed, the soft\n" " limit is enforced as the hard limit. It is intended as an alternative to\n" " the timeout system, where the system administrator updates a count of the\n" " number of warnings issued to people, and they are penalised if the " "warnings\n" " are ignored.\n" " -d -- set maximum warning count, which triggers soft limit enforcement\n" " -g -- set group quota warning count\n" " -p -- set project quota warning count\n" " -u -- set user quota warning count\n" " -b -- set the blocks-used warning count\n" " -i -- set the inodes-used warning count\n" " -r -- set the blocks-used warn count for the (optional) realtime subvolume\n" " The user/group/project can be specified either by name or by number.\n" "\n" msgstr "" "\n" " zmiana liczby ostrzeżeÅ„ quot wysyÅ‚anych do podanego użytkownika\n" "\n" " PrzykÅ‚ad:\n" " 'warn 2 jimmy'\n" " (przekazanie systemowi quota, że wysÅ‚ano 2 ostrzeżenia do użytkownika " "jimmy)\n" "\n" " warn zmienia liczbÄ™ ostrzeżeÅ„ zwiÄ…zanych z limitami bloków, limitami i-" "wÄ™złów\n" " i/lub limitami bloków realtime dla podanego użytkownika, grupy lub " "projektu.\n" " Kiedy użytkownik zostaÅ‚ ostrzeżony maksymalnÄ… dozwolonÄ… liczbÄ™ razy, " "miÄ™kki\n" " limit staje siÄ™ twardym. Jest to pomyÅ›lane jako alternatywa dla systemu\n" " ograniczeÅ„ czasowych, gdzie administrator uaktualnia licznik ostrzeżeÅ„\n" " wysÅ‚anych do ludzi i karze użytkowników ignorujÄ…cych ostrzeżenia.\n" " -d - ustawienie maksymalnej liczby ostrzeżeÅ„, po której wymuszane sÄ… " "limity\n" " -g - ustawienie liczby ostrzeżeÅ„ dla grupy\n" " -p - ustawienie liczby ostrzeżeÅ„ dla projektu\n" " -u - ustawienie liczby ostrzeżeÅ„ dla grupy\n" " -b - ustawienie liczby ostrzeżeÅ„ dla użytych bloków\n" " -i - ustawienie liczby ostrzeżeÅ„ dla użytych i-wÄ™złów\n" " -r - ustawienie liczby ostrzeżeÅ„ dla użytych bloków na podwolumenie " "realtime\n" " Użytkownik/grupa/projekt może być podany za pomocÄ… nazwy lub numeru.\n" "\n" #: .././quota/edit.c:145 #, c-format msgid "%s: cannot set limits: %s\n" msgstr "%s: nie można ustawić limitów: %s\n" #: .././quota/edit.c:166 .././quota/edit.c:584 #, c-format msgid "%s: invalid user name: %s\n" msgstr "%s: nieprawidÅ‚owa nazwa użytkownika: %s\n" #: .././quota/edit.c:189 .././quota/edit.c:601 #, c-format msgid "%s: invalid group name: %s\n" msgstr "%s: nieprawidÅ‚owa nazwa grupy: %s\n" #: .././quota/edit.c:212 .././quota/edit.c:618 #, c-format msgid "%s: invalid project name: %s\n" msgstr "%s: nieprawidÅ‚owa nazwa projektu: %s\n" #: .././quota/edit.c:237 #, c-format msgid "%s: Error: could not parse size %s.\n" msgstr "%s: Błąd: nie udaÅ‚o siÄ™ przeanalizować rozmiaru %s.\n" #: .././quota/edit.c:243 #, c-format msgid "%s: Warning: `%s' in quota blocks is 0 (unlimited).\n" msgstr "%s: Uwaga: `%s' w blokach limitów wynosi 0 (bez ograniczeÅ„).\n" #: .././quota/edit.c:332 #, c-format msgid "%s: unrecognised argument %s\n" msgstr "%s: nierozpoznany argument %s\n" #: .././quota/edit.c:339 #, c-format msgid "%s: cannot find any valid arguments\n" msgstr "%s: nie można znaleźć żadnych poprawnych argumentów\n" #: .././quota/edit.c:457 #, c-format msgid "%s: fopen on %s failed: %s\n" msgstr "%s: fopen na %s nie powiodÅ‚o siÄ™: %s\n" #: .././quota/edit.c:489 #, c-format msgid "%s: cannot set timer: %s\n" msgstr "%s: nie można ustawić czasu: %s\n" #: .././quota/edit.c:568 #, c-format msgid "%s: cannot set warnings: %s\n" msgstr "%s: nie można ustawić ostrzeżeÅ„: %s\n" #: .././quota/edit.c:709 msgid "[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name" msgstr "[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|nazwa" #: .././quota/edit.c:710 msgid "modify quota limits" msgstr "zmiana limitów quot" #: .././quota/edit.c:718 .././quota/report.c:33 .././quota/report.c:768 msgid "[-g|-p|-u] [-f file]" msgstr "[-g|-p|-u] [-f plik]" #: .././quota/edit.c:719 msgid "restore quota limits from a backup file" msgstr "odtworzenie limitów quot z pliku kopii zapasowej" #: .././quota/edit.c:726 msgid "[-bir] [-g|-p|-u] value" msgstr "[-bir] [-g|-p|-u] wartość" #: .././quota/edit.c:727 msgid "set quota enforcement timeouts" msgstr "ustawienie czasu wymuszenia quot" #: .././quota/edit.c:735 msgid "[-bir] [-g|-p|-u] value -d|id|name" msgstr "[-bir] [-g|-p|-u] wartość -d|id|nazwa" #: .././quota/edit.c:736 msgid "get/set enforcement warning counter" msgstr "pobranie/ustawienie licznika ostrzeżeÅ„" #: .././quota/free.c:30 #, c-format msgid "" "\n" " reports the number of free disk blocks and inodes\n" "\n" " This command reports the number of total, used, and available disk blocks.\n" " It can optionally report the same set of numbers for inodes and realtime\n" " disk blocks, and will report on all known XFS filesystem mount points and\n" " project quota paths by default (see 'print' command for a list).\n" " -b -- report the block count values\n" " -i -- report the inode count values\n" " -r -- report the realtime block count values\n" " -h -- report in a human-readable format\n" " -N -- suppress the header from the output\n" "\n" msgstr "" "\n" " informacje o liczbie wolnych bloków i i-wÄ™złów dysku\n" "\n" " To polecenie informuje o liczbie wszystkich, używanych i dostÄ™pnych bloków\n" " dysku. Opcjonalnie informuje o tym samym zestawie liczb dla i-wÄ™złów i " "bloków\n" " realtime oraz domyÅ›lnie zgÅ‚asza wszystkie znane punkty montowania systemu\n" " plików XFS i Å›cieżki quot projektów (patrz lista w poleceniu 'print').\n" " -b - informacje o liczbach bloków\n" " -i - informacje o liczbach i-wÄ™złów\n" " -r - informacje o liczbach bloków realtime\n" " -h - informacje w postaci czytelnej dla czÅ‚owieka\n" " -N - pominiÄ™cie nagłówka z wyjÅ›cia\n" "\n" #: .././quota/free.c:171 #, c-format msgid "%s: project quota flag not set on %s\n" msgstr "%s: flaga quot projektu nie ustawiona dla %s\n" #: .././quota/free.c:180 #, c-format msgid "%s: project ID %u (%s) doesn't match ID %u (%s)\n" msgstr "%s: ID projektu %u (%s) nie zgadza siÄ™ z ID %u (%s)\n" #: .././quota/free.c:247 #, c-format msgid "Filesystem " msgstr "System plików " #: .././quota/free.c:247 #, c-format msgid "Filesystem " msgstr "System plików " #: .././quota/free.c:250 #, c-format msgid " Size Used Avail Use%%" msgstr " Rozmiar Użyto Dost. %%uż." #: .././quota/free.c:251 #, c-format msgid " 1K-blocks Used Available Use%%" msgstr " Bloki 1K Użyto DostÄ™pnych %%uż." #: .././quota/free.c:254 #, c-format msgid " Inodes Used Free Use%%" msgstr " I-wÄ™zÅ‚y Użyto Wolne %%uż." #: .././quota/free.c:255 #, c-format msgid " Inodes IUsed IFree IUse%%" msgstr " I-wÄ™zÅ‚y UżytoI WolneI %%użI" #: .././quota/free.c:256 #, c-format msgid " Pathname\n" msgstr " Åšcieżka\n" #: .././quota/free.c:388 msgid "[-bir] [-hN] [-f file]" msgstr "[-bir] [-hN] [-f plik]" #: .././quota/free.c:389 msgid "show free and used counts for blocks and inodes" msgstr "pokazanie liczby wolnych i zajÄ™tych bloków i i-wÄ™złów" #: .././quota/init.c:49 #, c-format msgid "Usage: %s [-V] [-x] [-f] [-p prog] [-c cmd]... [-d project]... [path]\n" msgstr "" "SkÅ‚adnia: %s [-V] [-x] [-f] [-p program] [-c polecenie]... [-d projekt]... " "[Å›cieżka]\n" #: .././quota/init.c:131 #, c-format msgid "%s: command is for XFS filesystems only\n" msgstr "%s: polecenie jest tylko dla systemów plików XFS\n" #: .././quota/init.c:138 #, c-format msgid "%s: foreign filesystem. Invoke xfs_quota with -f to enable.\n" msgstr "" "%s: obcy system plików; zby włączyć, należy uruchomić xfs_quota z opcjÄ… -f.\n" #: .././quota/path.c:39 #, c-format msgid "%s%sFilesystem Pathname\n" msgstr "%s%sSystem plików Åšcieżka\n" #: .././quota/path.c:40 msgid " " msgstr " " #: .././quota/path.c:41 msgid " " msgstr " " #: .././quota/path.c:44 #, c-format msgid "%c%03d%c " msgstr "%c%03d%c " #: .././quota/path.c:47 #, c-format msgid "%-19s %s" msgstr "%-19s %s" #: .././quota/path.c:50 #, c-format msgid " (project %u" msgstr " (projekt %u" #: .././quota/path.c:52 #, c-format msgid ", %s" msgstr ", %s" #: .././quota/path.c:117 #, c-format msgid "No paths are available\n" msgstr "Brak Å›cieżek\n" #: .././quota/path.c:145 msgid "set current path, or show the list of paths" msgstr "ustawienie bieżącej Å›cieżki lub pokazanie listy Å›cieżek" #: .././quota/path.c:153 msgid "list known mount points and projects" msgstr "wypisanie znanych punktów montowaÅ„ i projektów" #: .././quota/project.c:45 #, c-format msgid "" "\n" " list projects or setup a project tree for tree quota management\n" "\n" " Example:\n" " 'project -c logfiles'\n" " (match project 'logfiles' to a directory, and setup the directory tree)\n" "\n" " Without arguments, report all projects found in the /etc/projects file.\n" " The project quota mechanism in XFS can be used to implement a form of\n" " directory tree quota, where a specified directory and all of the files\n" " and subdirectories below it (i.e. a tree) can be restricted to using a\n" " subset of the available space in the filesystem.\n" "\n" " A managed tree must be setup initially using the -c option with a project.\n" " The specified project name or identifier is matched to one or more trees\n" " defined in /etc/projects, and these trees are then recursively descended\n" " to mark the affected inodes as being part of that tree - which sets inode\n" " flags and the project identifier on every file.\n" " Once this has been done, new files created in the tree will automatically\n" " be accounted to the tree based on their project identifier. An attempt to\n" " create a hard link to a file in the tree will only succeed if the project\n" " identifier matches the project identifier for the tree. The xfs_io " "utility\n" " can be used to set the project ID for an arbitrary file, but this can only\n" " be done by a privileged user.\n" "\n" " A previously setup tree can be cleared from project quota control through\n" " use of the -C option, which will recursively descend the tree, clearing\n" " the affected inodes from project quota control.\n" "\n" " The -c option can be used to check whether a tree is setup, it reports\n" " nothing if the tree is correct, otherwise it reports the paths of inodes\n" " which do not have the project ID of the rest of the tree, or if the inode\n" " flag is not set.\n" "\n" " The -p option can be used to manually specify project path without\n" " need to create /etc/projects file. This option can be used multiple times\n" " to specify multiple paths. When using this option only one projid/name can\n" " be specified at command line. Note that /etc/projects is also used if " "exists.\n" "\n" " The -d option allows to descend at most levels of " "directories\n" " below the command line arguments. -d 0 means only apply the actions\n" " to the top level of the projects. -d -1 means no recursion limit " "(default).\n" "\n" " The /etc/projid and /etc/projects file formats are simple, and described\n" " on the xfs_quota man page.\n" "\n" msgstr "" "\n" " wypisanie projektów lub ustanowienie drzewa projektu do zarzÄ…dzania " "limitami\n" "\n" " PrzykÅ‚ad:\n" " 'project -c logfiles'\n" " (dopasowanie projektu 'logfiles' do katalogu i ustanowienie drzewa " "katalogów)\n" "\n" " Bez argumentów project wypisuje wszystkie projekty znalezione w pliku\n" " /etc/projects. Mechanizm quota dla projektów w XFS-ie może być używany do\n" " zaimplementowania formy limitów dla drzewa katalogów, gdzie podany katalog\n" " i wszystkie pliki i podkatalogi poniżej niego (czyli drzewo) mogÄ… być\n" " ograniczone do używania podzbioru miejsca dostÄ™pnego w systemie plików.\n" "\n" " ZarzÄ…dzane drzewo musi być ustanowione poczÄ…tkowo przy użyciu opcji project " "-c.\n" " Podana nazwa lub identyfikator projektu jest dopasowywany do jednego lub\n" " wiÄ™kszej liczby drzew zdefiniowanych w /etc/projects, a nastÄ™pnie te drzewa " "sÄ…\n" " rekurencyjnie przechodzone w celu oznaczenia i-wÄ™złów jako bÄ™dÄ…cych " "częściÄ…\n" " tego drzewa - co ustawia flagi i-wÄ™złów i identyfikator projektu dla " "każdego\n" " pliku.\n" " Po zrobieniu tego nowe pliki tworzone w drzewie bÄ™dÄ… automatycznie liczone " "jako\n" " część drzewa o ich identyfikatorze projektu. Próba utworzenia dowiÄ…zania\n" " zwykÅ‚ego do pliku w drzewie powiedzie siÄ™ tylko jeÅ›li identyfikator " "projektu\n" " pasuje do identyfikatora projektu drzewa. Można użyć narzÄ™dzia xfs_io do\n" " ustawienia ID projektu dla dowolnego pliku, ale może tego dokonać tylko\n" " uprzywilejowany użytkownik.\n" "\n" " Poprzednio ustanowione drzewa można usunąć z kontroli limitów projektu " "poprzez\n" " użycie opcji -C, która rekurencyjnie przejdzie drzewo, usuwajÄ…c i-wÄ™zÅ‚y " "spod\n" " kontroli limitów projektu.\n" "\n" " Opcji -c można użyć do sprawdzenia czy drzewo zostaÅ‚o ustanowione - nie\n" " informuje o niczym jeÅ›li drzewo jest poprawne, a w przeciwnym wypadku " "zgÅ‚asza\n" " Å›cieżki i-wÄ™złów nie majÄ…ce ID projektu takiego jak reszta drzewa lub nie\n" " majÄ…ce ustawionej flagi.\n" "\n" " Opcja -p <Å›cieżka> umożliwia podanie Å›cieżki projektu w linii poleceÅ„\n" " bez potrzeby tworzenia pliku /etc/projects. Ta opcja może być używana\n" " wielokrotnie w celu przekazanie wielu Å›cieżek projektu. Tylko jeden\n" " identyfikator projektu może być podawy w linii poleceÅ„ w momencie\n" " używania opcji -p. JeÅ›li plik /etc/projects istnieje to także jest używany\n" " oprócz Å›cieżek w linii poleceÅ„.\n" "\n" " Opcja -d pozwala na ograniczanie zagłębiania siÄ™ w podkatalogach\n" " projektu do granicy . -d 0 oznacza najwyższy poziom. -d 1 oznacza\n" " brak limitu zagłębiania (domyÅ›lny).\n" "\n" " Format plików /etc/projid i /etc/projects jest prosty i opisany na stronie\n" " manuala xfs_quota.\n" "\n" #: .././quota/project.c:108 .././quota/project.c:153 .././quota/project.c:200 #, c-format msgid "%s: cannot stat file %s\n" msgstr "%s: nie można wykonać stat na pliku %s\n" #: .././quota/project.c:112 .././quota/project.c:157 .././quota/project.c:204 #, c-format msgid "%s: skipping special file %s\n" msgstr "%s: pominiÄ™to plik specjalny %s\n" #: .././quota/project.c:126 #, c-format msgid "%s - project identifier is not set (inode=%u, tree=%u)\n" msgstr "%s - identyfikator projektu nie ustawiony (i-wÄ™zeÅ‚=%u, drzewo=%u)\n" #: .././quota/project.c:130 #, c-format msgid "%s - project inheritance flag is not set\n" msgstr "%s - flaga dziedziczenia projektu nie ustawiona\n" #: .././quota/project.c:178 #, c-format msgid "%s: cannot clear project on %s: %s\n" msgstr "%s: nie można usunąć projektu z %s: %s\n" #: .././quota/project.c:225 #, c-format msgid "%s: cannot set project on %s: %s\n" msgstr "%s: nie można ustawić projektu na %s: %s\n" #: .././quota/project.c:240 #, c-format msgid "Checking project %s (path %s)...\n" msgstr "Sprawdzanie projektu %s (Å›cieżka %s)...\n" #: .././quota/project.c:244 #, c-format msgid "Setting up project %s (path %s)...\n" msgstr "Ustanawianie projektu %s (Å›cieżka %s)...\n" #: .././quota/project.c:248 #, c-format msgid "Clearing project %s (path %s)...\n" msgstr "Usuwanie projektu %s (Å›cieżka %s)...\n" #: .././quota/project.c:271 #, c-format msgid "" "Processed %d (%s and cmdline) paths for project %s with recursion depth %s " "(%d).\n" msgstr "" "Przetworzono %d (z %s oraz z linii poleceÅ„) Å›cieżek dla projektu %s\n" "z ograniczeniem %s (%d)\n" #: .././quota/project.c:274 msgid "infinite" msgstr "nieaktywnym" #: .././quota/project.c:274 msgid "limited" msgstr "aktywnym" #: .././quota/project.c:319 #, c-format msgid "projects file \"%s\" doesn't exist\n" msgstr "plik projektów \"%s\" nie istnieje\n" #: .././quota/project.c:326 #, c-format msgid "" "%s: only one projid/name can be specified when using -p , %d found.\n" msgstr "" "%s: tylko jeden id projektu/nazwa może być podana kiedy opcja -p <Å›cieżka> " "jest w użyciu. Znaleziono %d.\n" #: .././quota/project.c:336 #, c-format msgid "%s - no such project in %s or invalid project number\n" msgstr "%s - nie ma takiego projektu w %s lub błędny numer projektu\n" #: .././quota/project.c:353 msgid "[-c|-s|-C|-d |-p ] project ..." msgstr "[-c|-s|-C| -d |-p <Å›cieżka>] projekt ..." #: .././quota/project.c:356 msgid "check, setup or clear project quota trees" msgstr "sprawdzenie, ustanowienie lub usuniÄ™cie drzew projektów" #: .././quota/quot.c:56 #, c-format msgid "" "\n" " display a summary of filesystem ownership\n" "\n" " -a -- summarise for all local XFS filesystem mount points\n" " -c -- display three columns giving file size in kilobytes, number of files\n" " of that size, and cumulative total of kilobytes in that size or\n" " smaller file. The last row is used as an overflow bucket and is the\n" " total of all files greater than 500 kilobytes.\n" " -v -- display three columns containing the number of kilobytes not\n" " accessed in the last 30, 60, and 90 days.\n" " -g -- display group summary\n" " -p -- display project summary\n" " -u -- display user summary\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n" msgstr "" "\n" " wyÅ›wietlenie podsumowania wÅ‚asnoÅ›ci systemu plików\n" "\n" " -a - podsumowanie dla wszystkich punktów montowania systemów plików XFS\n" " -c - wyÅ›wietlenie trzech kolumn z rozmiarem plików w kilobajtach, liczbÄ…\n" " plików tego rozmiaru i sumÄ… kilobajtów w plikach o tym lub mniejszym\n" " rozmiarze. Ostatni wiersz podsumowuje pliki wiÄ™ksze niż 500 " "kilobajtów.\n" " -v - wyÅ›wietlenie trzech kolumn zawierajÄ…cych liczbÄ™ kilobajtów, do " "których\n" " nie byÅ‚o odwoÅ‚aÅ„ przez ostatnie 30, 60 i 90 dni.\n" " -g - wyÅ›wietlenie podsumowania dla grup\n" " -p - wyÅ›wietlenie podsumowania dla projektów\n" " -u - wyÅ›wietlenie podsumowania dla użytkowników\n" " -b - wyÅ›wietlenie liczby wykorzystanych bloków\n" " -i - wyÅ›wietlenie liczby wykorzystanych i-wÄ™złów\n" " -r - wyÅ›wietlenie liczby wykorzystanych blików realtime\n" " -n - pominiÄ™cie tÅ‚umaczenia identyfikatorów na nazwy, wypisywanie ID\n" " -N - pominiÄ™cie poczÄ…tkowego nagłówka\n" " -f - zapisanie wyjÅ›cia do pliku\n" " (opcjonalny) użytkownik/grupa/projekt może być podany za pomocÄ… nazwy lub\n" " numeru (tzn. uid/gid/projid).\n" #: .././quota/quot.c:221 #, c-format msgid "%s (%s) %s:\n" msgstr "%s (%s) %s:\n" #: .././quota/quot.c:297 #, c-format msgid "%s (%s):\n" msgstr "%s (%s):\n" #: .././quota/quot.c:302 .././quota/quot.c:306 #, c-format msgid "%d\t%llu\t%llu\n" msgstr "%d\t%llu\t%llu\n" #: .././quota/quot.c:425 msgid "[-bir] [-g|-p|-u] [-acv] [-f file]" msgstr "[-bir] [-g|-p|-u] [-acv] [-f plik]" #: .././quota/quot.c:426 msgid "summarize filesystem ownership" msgstr "podsumowanie wÅ‚asnoÅ›ci systemu plików" #: .././quota/quota.c:33 #, c-format msgid "" "\n" " display usage and quota information\n" "\n" " -g -- display group quota information\n" " -p -- display project quota information\n" " -u -- display user quota information\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -v -- increase verbosity in reporting (also dumps zero values)\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n" msgstr "" "\n" " wyÅ›wietlenie informacji o wykorzystaniu miejsca i limitach\n" "\n" " -g - wyÅ›wietlenie informacji o limitach grup\n" " -p - wyÅ›wietlenie informacji o limitach projektów\n" " -u - wyÅ›wietlenie informacji o limitach użytkowników\n" " -b - wyÅ›wietlenie liczby wykorzystanych bloków\n" " -i - wyÅ›wietlenie liczby wykorzystanych i-wÄ™złów\n" " -r - wyÅ›wietlenie liczby wykorzystanych bloków realtime\n" " -h - użycie formatu czytelnego dla czÅ‚owieka\n" " -n - pominiÄ™cie tÅ‚umaczenia identyfikatorów na nazwy, wypisywanie ID\n" " -N - pominiÄ™cie poczÄ…tkowego nagłówka\n" " -v - zwiÄ™kszenie szczegółowoÅ›ci (wypisywanie także wartoÅ›ci zerowych)\n" " -f - zapisanie wyjÅ›cia do pliku\n" " (opcjonalny) użytkownik/grupa/projekt może być podany za pomocÄ… nazwy lub\n" " numeru (tzn. uid/gid/projid).\n" #: .././quota/quota.c:86 #, c-format msgid "" "Disk quotas for %s %s (%u)\n" "Filesystem%s" msgstr "" "Limity dyskowe (quota) dla %s %s (%u)\n" "System plików%s" #: .././quota/quota.c:91 #, c-format msgid " Blocks Quota Limit Warn/Time " msgstr " Bloki Quota Limit Czas ostrz. " #: .././quota/quota.c:92 #, c-format msgid " Blocks Quota Limit Warn/Time " msgstr " Bloki Quota Limit Czas ostrz. " #: .././quota/quota.c:95 #, c-format msgid " Files Quota Limit Warn/Time " msgstr " Pliki Quota Limit Czas ostrz. " #: .././quota/quota.c:96 #, c-format msgid " Files Quota Limit Warn/Time " msgstr " Pliki Quota Limit Czas ostrz. " #: .././quota/quota.c:99 #, c-format msgid "Realtime Quota Limit Warn/Time " msgstr "Realtime Quota Limit Czas ostrz. " #: .././quota/quota.c:100 #, c-format msgid " Realtime Quota Limit Warn/Time " msgstr " Realtime Quota Limit Czas ostrz. " #: .././quota/quota.c:236 #, c-format msgid "%s: cannot find user %s\n" msgstr "%s: nie można odnaleźć użytkownika %s\n" #: .././quota/quota.c:286 #, c-format msgid "%s: cannot find group %s\n" msgstr "%s: nie można odnaleźć grupy %s\n" #: .././quota/quota.c:347 #, c-format msgid "%s: must specify a project name/ID\n" msgstr "%s: należy podać nazwÄ™/ID projektu\n" #: .././quota/quota.c:360 #, c-format msgid "%s: cannot find project %s\n" msgstr "%s: nie można odnaleźć projektu %s\n" #: .././quota/quota.c:470 msgid "[-bir] [-g|-p|-u] [-hnNv] [-f file] [id|name]..." msgstr "[-bir] [-g|-p|-u] [-hnNv] [-f plik] [id|nazwa]..." #: .././quota/quota.c:471 msgid "show usage and limits" msgstr "pokazanie wykorzystania i limitów" #: .././quota/report.c:34 .././quota/report.c:769 msgid "dump quota information for backup utilities" msgstr "zrzucenie informacji o limitach (quota) dla narzÄ™dzi backupowych" #: .././quota/report.c:36 #, c-format msgid "" "\n" " create a backup file which contains quota limits information\n" " -g -- dump out group quota limits\n" " -p -- dump out project quota limits\n" " -u -- dump out user quota limits (default)\n" " -f -- write the dump out to the specified file\n" "\n" msgstr "" "\n" " utworzenie pliku kopii zapasowej zawierajÄ…cego informacje o limitach " "(quota)\n" " -g - zrzucenie limitów dla grup\n" " -p - zrzucenie limitów dla projektów\n" " -u - zrzucenie limitów dla użytkowników (domyÅ›lne)\n" " -f - zapisanie zrzutu do podanego pliku\n" "\n" #: .././quota/report.c:48 msgid "[-bir] [-gpu] [-ahntlLNU] [-f file]" msgstr "[-bir] [-gpu] [-ahntlLNU] [-f plik]" #: .././quota/report.c:49 .././quota/report.c:779 msgid "report filesystem quota information" msgstr "raportowanie informacji o limitach (quota) w systemie plików" #: .././quota/report.c:51 #, c-format msgid "" "\n" " report used space and inodes, and quota limits, for a filesystem\n" " Example:\n" " 'report -igh'\n" " (reports inode usage for all groups, in an easy-to-read format)\n" " This command is the equivalent of the traditional repquota command, which\n" " prints a summary of the disk usage and quotas for the current filesystem,\n" " or all filesystems.\n" " -a -- report for all mounted filesystems with quota enabled\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the header from the output\n" " -t -- terse output format, hides rows which are all zero\n" " -L -- lower ID bound to report on\n" " -U -- upper ID bound to report on\n" " -l -- look up names for IDs in lower-upper range\n" " -g -- report group usage and quota information\n" " -p -- report project usage and quota information\n" " -u -- report user usage and quota information\n" " -b -- report blocks-used information only\n" " -i -- report inodes-used information only\n" " -r -- report realtime-blocks-used information only\n" "\n" msgstr "" "\n" " informacje o wykorzystanym miejscu i i-wÄ™zÅ‚ach oraz limitach quota dla " "systemu\n" " plików\n" "\n" " PrzykÅ‚ad:\n" " 'report -igh'\n" " (raport o wykorzystaniu i-wÄ™złów dla wszystkich grup w czytelnym formacie)\n" "\n" " To polecenie jest odpowiednikiem tradycyjnego polecenia repquota, " "wypisujÄ…cego\n" " podsumowanie wykorzystania dysku i limitów dla bieżącego systemu plików " "lub\n" " wszystkich systemów plików.\n" " -a - informacje o wszystkich zamontowanych systemach plików z limitami\n" " -h - informacje w formacie czytelnym dla czÅ‚owieka\n" " -n - pominiÄ™cie tÅ‚umaczenia identyfikatorów na nazwy, wypisywanie ID\n" " -N - pominiÄ™cie poczÄ…tkowego nagłówka\n" " -t - zwiÄ™zÅ‚y format, ukrycie wierszy zerowych\n" " -L - dolna granica ID dla wypisywanych informacji\n" " -U - górna granica ID dla wypisywanych informacji\n" " -l - wyszukiwanie nazw dla identyfikatorów w przedziale dolny-górny\n" " -g - informacje o wykorzystanym miejscu i limitach dla grup\n" " -p - informacje o wykorzystanym miejscu i limitach dla projektów\n" " -u - informacje o wykorzystanym miejscu i limitach dla użytkowników\n" " -b - tylko informacje o wykorzystanych blokach\n" " -i - tylko informacje o wykorzystanych i-wÄ™zÅ‚ach\n" " -r - tylko informacje o wykorzystanych blokach realtime\n" "\n" #: .././quota/report.c:273 #, c-format msgid "%s quota on %s (%s)\n" msgstr "limit %s na %s (%s)\n" #: .././quota/report.c:298 .././quota/report.c:306 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr " Użyto MiÄ™kki Twardy Ostrzeżenie " #: .././quota/report.c:299 .././quota/report.c:307 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr " Użyto MiÄ™kki Twardy Ostrzeżenie " #: .././quota/report.c:302 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr " Użyto MiÄ™kki Twardy Ostrzeżenie" #: .././quota/report.c:303 #, c-format msgid " Used Soft Hard Warn/ Grace " msgstr " Użyto MiÄ™kki Twardy Ostrzeżenie " #: .././quota/report.c:778 msgid "[-bir] [-gpu] [-ahnt] [-f file]" msgstr "[-bir] [-gpu] [-ahnt] [-f plik]" #: .././quota/state.c:33 #, c-format msgid "" "\n" " turn filesystem quota off, both accounting and enforcement\n" "\n" " Example:\n" " 'off -uv' (switch off user quota on the current filesystem)\n" " This command is the equivalent of the traditional quotaoff command,\n" " which disables quota completely on a mounted filesystem.\n" " Note that there is no 'on' command - for XFS filesystems (with the\n" " exception of the root filesystem on IRIX) quota can only be enabled\n" " at mount time, through the use of one of the quota mount options.\n" "\n" " The state command is useful for displaying the current state. Using\n" " the -v (verbose) option with the 'off' command will display the quota\n" " state for the affected filesystem once the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " wyłączenie podsystemu quota (zarówno rozliczania jak i wymuszania)\n" "\n" " PrzykÅ‚ad:\n" " 'off -uv' (wyłączenie limitów użytkownika w bieżącym systemie plików)\n" "\n" " To polecenie jest odpowiednikiem tradycyjnego polecenia quotaoff,\n" " wyłączajÄ…cego caÅ‚kowicie limity na zamontowanym systemie plików.\n" " Należy zauważyć, że nie ma polecenia 'on' - dla systemów plików XFS\n" " (z wyjÄ…tkiem głównego systemu plików pod systemem IRIX) limity można\n" " włączyć wyłącznie na etapie montowania, poprzez użycie jednej z opcji\n" " quota programu mount.\n" "\n" " Polecenie state jest przydatne do wyÅ›wietlania aktualnego stanu. Użycie\n" " opcji -v (szczegółowość) dla polecenia 'off' wyÅ›wietli stan quoty dla\n" " danego systemu plików po zakoÅ„czeniu operacji.\n" " Rodzaj limitu którego dotyczy polecenie można wybrać opcjÄ… -g (grupy),\n" " -p (projekty) lub -u (użytkownicy); domyÅ›lnie polecenie dotyczy limitów\n" " użytkowników (można podać wiele rodzajów).\n" "\n" #: .././quota/state.c:56 #, c-format msgid "" "\n" " query the state of quota on the current filesystem\n" "\n" " This is a verbose status command, reporting whether or not accounting\n" " and/or enforcement are enabled for a filesystem, which inodes are in\n" " use as the quota state inodes, and how many extents and blocks are\n" " presently being used to hold that information.\n" " The quota type is specified via -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " odczytanie stanu podsystemu quota w bieżącym systemie plików\n" "\n" " Jest to polecenie szczegółowo informujÄ…ce o stanie, opisujÄ…ce czy włączone\n" " jest rozliczanie i/lub wymuszanie limitów w systemie plików, które i-wÄ™zÅ‚y\n" " sÄ… wykorzystywane jako i-wÄ™zÅ‚y stanu quot oraz ile ekstentów i bloków jest\n" " aktualnie używana do przechowywania tych informacji.\n" " Rodzaj limitów podaje siÄ™ opcjÄ… -g (grupy), -p (projekty) lub -u " "(użytkownicy);\n" " domyÅ›lnie polecenie dotyczy limitów użytkowników (można podać wiele " "rodzajów).\n" "\n" #: .././quota/state.c:72 #, c-format msgid "" "\n" " enable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and has quota accounting enabled, but not\n" " quota enforcement, enforcement can be enabled with this command.\n" " With the -v (verbose) option, the status of the filesystem will be\n" " reported after the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " włączenie wymuszania limitów w systemie plików\n" "\n" " JeÅ›li system plików jest zamontowany i ma włączone rozliczanie limitów,\n" " ale nie ma wymuszania limitów, można włączyć wymuszanie tym poleceniem.\n" " Z opcjÄ… -v (szczegółowość) po zakoÅ„czeniu operacji zostanie zraportowany\n" " stan systemu plików.\n" " Rodzaj limitów podaje siÄ™ opcjÄ… -g (grupy), -p (projekty) lub -u " "(użytkownicy);\n" " domyÅ›lnie polecenie dotyczy limitów użytkowników (można podać wiele " "rodzajów).\n" "\n" #: .././quota/state.c:88 #, c-format msgid "" "\n" " disable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and is currently enforcing quota, this\n" " provides a mechanism to switch off the enforcement, but continue to\n" " perform used space (and used inodes) accounting.\n" " The affected quota type is -g (groups), -p (projects) or -u (users).\n" "\n" msgstr "" "\n" " wyłączenie wymuszania limitów w systemie plików\n" "\n" " JeÅ›li system plików jest zamontowany i aktualnie wymusza przestrzeganie\n" " limitów, tym poleceniem można wyłączyć wymuszanie, ale nadal pozostawić\n" " rozliczanie wykorzystanego miejsca (oraz i-wÄ™złów).\n" " Rodzaj limitów podaje siÄ™ opcjÄ… -g (grupy), -p (projekty) lub -u " "(użytkownicy).\n" "\n" #: .././quota/state.c:102 #, c-format msgid "" "\n" " remove any space being used by the quota subsystem\n" "\n" " Once quota has been switched 'off' on a filesystem, the space that\n" " was allocated to holding quota metadata can be freed via this command.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" "\n" " zwolnienie miejsca zajmowanego przez podsystem quota\n" "\n" " Po wyłączeniu limitów dla systemu plików można tym poleceniem zwolnić " "miejsce\n" " przydzielone na przechowywanie metadanych quot.\n" " Rodzaj limitów podaje siÄ™ opcjÄ… -g (grupy), -p (projekty) lub -u " "(użytkownicy);\n" " domyÅ›lnie polecenie dotyczy limitów użytkowników (można podać wiele " "rodzajów).\n" "\n" #: .././quota/state.c:121 #, c-format msgid "%s quota state on %s (%s)\n" msgstr "stan limitów %s na %s (%s)\n" #: .././quota/state.c:123 #, c-format msgid " Accounting: %s\n" msgstr " Rozliczanie: %s\n" #: .././quota/state.c:123 .././quota/state.c:124 msgid "ON" msgstr "WÅÄ„CZONE" #: .././quota/state.c:123 .././quota/state.c:124 msgid "OFF" msgstr "WYÅÄ„CZONE" #: .././quota/state.c:124 #, c-format msgid " Enforcement: %s\n" msgstr " Wymuszanie: %s\n" #: .././quota/state.c:126 #, c-format msgid " Inode: #%llu (%llu blocks, %lu extents)\n" msgstr " I-wÄ™zeÅ‚: #%llu (%llu bloków, %lu ekstentów)\n" #: .././quota/state.c:131 #, c-format msgid " Inode: N/A\n" msgstr " I-wÄ™zeÅ‚: N/A\n" #: .././quota/state.c:140 #, c-format msgid "%s grace time: %s\n" msgstr "czas pobÅ‚ażliwoÅ›ci %s: %s\n" #: .././quota/state.c:212 #, c-format msgid "%s quota are not enabled on %s\n" msgstr "Limity %s nie sÄ… włączone na %s\n" #: .././quota/state.c:584 .././quota/state.c:601 .././quota/state.c:609 #: .././quota/state.c:617 msgid "[-gpu] [-v]" msgstr "[-gpu] [-v]" #: .././quota/state.c:585 msgid "permanently switch quota off for a path" msgstr "wyłączenie limitów na staÅ‚e dla Å›cieżki" #: .././quota/state.c:592 msgid "[-gpu] [-a] [-v] [-f file]" msgstr "[-gpu] [-a] [-v] [-f plik]" #: .././quota/state.c:593 msgid "get overall quota state information" msgstr "uzyskanie ogólnych informacji o stanie quot" #: .././quota/state.c:602 msgid "enable quota enforcement" msgstr "włączenie wymuszania limitów" #: .././quota/state.c:610 msgid "disable quota enforcement" msgstr "wyłączenie wymuszania limitów" #: .././quota/state.c:618 msgid "remove quota extents from a filesystem" msgstr "usuniÄ™cie ekstentów zwiÄ…zanych z limitami z systemu plików" #: .././quota/util.c:70 #, c-format msgid "[-none-]" msgstr "[-brak-]" #: .././quota/util.c:70 #, c-format msgid "[--none--]" msgstr "[--brak--]" #: .././quota/util.c:73 #, c-format msgid "[------]" msgstr "[------]" #: .././quota/util.c:73 #, c-format msgid "[--------]" msgstr "[--------]" # XXX: ngettext() #: .././quota/util.c:77 .././quota/util.c:80 msgid "day" msgstr "dzieÅ„" #: .././quota/util.c:77 .././quota/util.c:80 msgid "days" msgstr "dni" #: .././quota/util.c:205 msgid "Blocks" msgstr "Bloki" #: .././quota/util.c:205 msgid "Inodes" msgstr "I-wÄ™zÅ‚y" #: .././quota/util.c:205 msgid "Realtime Blocks" msgstr "Bloki realtime" #: .././quota/util.c:220 msgid "User" msgstr "użytkowników" #: .././quota/util.c:220 msgid "Group" msgstr "grup" #: .././quota/util.c:220 msgid "Project" msgstr "projektów" #: .././quota/util.c:428 #, c-format msgid "%s: open on %s failed: %s\n" msgstr "%s: open dla %s nie powiodÅ‚o siÄ™: %s\n" #: .././quota/util.c:434 #, c-format msgid "%s: fdopen on %s failed: %s\n" msgstr "%s: fdopen dla %s nie powiodÅ‚o siÄ™: %s\n" #: .././repair/agheader.c:40 #, c-format msgid "bad magic # 0x%x for agf %d\n" msgstr "błędna liczba magiczna 0x%x dla agf %d\n" #: .././repair/agheader.c:49 #, c-format msgid "bad version # %d for agf %d\n" msgstr "błędny numer wersji %d dla agf %d\n" #: .././repair/agheader.c:58 #, c-format msgid "bad sequence # %d for agf %d\n" msgstr "błędny numer sekwencji %d dla agf %d\n" #: .././repair/agheader.c:68 #, c-format msgid "bad length %d for agf %d, should be %d\n" msgstr "błędna dÅ‚ugość %d dla agf %d, powinno być %d\n" #: .././repair/agheader.c:81 #, c-format msgid "bad length %d for agf %d, should be %\n" msgstr "błędna dÅ‚ugość %d dla agf %d, powinno być %\n" #: .././repair/agheader.c:95 #, c-format msgid "flfirst %d in agf %d too large (max = %zu)\n" msgstr "flfirst %d w agf %d zbyt duże (maksimum = %zu)\n" #: .././repair/agheader.c:103 #, c-format msgid "fllast %d in agf %d too large (max = %zu)\n" msgstr "fllast %d w agf %d zbyt duże (maksimum = %zu)\n" #: .././repair/agheader.c:120 #, c-format msgid "bad uuid %s for agf %d\n" msgstr "błędny uuid %s dla agf %d\n" #: .././repair/agheader.c:139 #, c-format msgid "bad magic # 0x%x for agi %d\n" msgstr "błędna liczba magiczna 0x%x dla agi %d\n" #: .././repair/agheader.c:148 #, c-format msgid "bad version # %d for agi %d\n" msgstr "błędny numer wersji %d dla agi %d\n" #: .././repair/agheader.c:157 #, c-format msgid "bad sequence # %d for agi %d\n" msgstr "błędny numer sekwencji %d dla agi %d\n" #: .././repair/agheader.c:167 #, c-format msgid "bad length # %d for agi %d, should be %d\n" msgstr "błędna dÅ‚ugość %d dla agi %d, powinno być %d\n" #: .././repair/agheader.c:180 #, c-format msgid "bad length # %d for agi %d, should be %\n" msgstr "błędna dÅ‚ugość %d dla agi %d, powinno być %\n" #: .././repair/agheader.c:199 #, c-format msgid "bad uuid %s for agi %d\n" msgstr "błędny uuid %s dla agi %d\n" #: .././repair/agheader.c:305 #, c-format msgid "zeroing unused portion of %s superblock (AG #%u)\n" msgstr "zerowanie nieużywanej części superbloku %s (AG #%u)\n" #: .././repair/agheader.c:306 .././repair/agheader.c:324 msgid "primary" msgstr "głównego" #: .././repair/agheader.c:306 .././repair/agheader.c:324 msgid "secondary" msgstr "zapasowego" #: .././repair/agheader.c:323 #, c-format msgid "would zero unused portion of %s superblock (AG #%u)\n" msgstr "nieużywana część superbloku %s (AG #%u) zostaÅ‚aby wyzerowana\n" #: .././repair/agheader.c:341 #, c-format msgid "bad flags field in superblock %d\n" msgstr "błędne pole flag w superbloku %d\n" #: .././repair/agheader.c:364 #, c-format msgid "non-null user quota inode field in superblock %d\n" msgstr "niezerowe pole i-wÄ™zÅ‚a limitów użytkowników w superbloku %d\n" #: .././repair/agheader.c:379 #, c-format msgid "non-null group quota inode field in superblock %d\n" msgstr "niezerowe pole i-wÄ™zÅ‚a limitów grup w superbloku %d\n" #: .././repair/agheader.c:400 #, c-format msgid "non-null project quota inode field in superblock %d\n" msgstr "niezerowe pole i-wÄ™zÅ‚a limitów projektu w superbloku %d\n" #: .././repair/agheader.c:412 #, c-format msgid "non-null quota flags in superblock %d\n" msgstr "niezerowe flagi limitów w superbloku %d\n" #: .././repair/agheader.c:430 #, c-format msgid "bad inode alignment field in superblock %d\n" msgstr "błędne pole wyrównania i-wÄ™złów w superbloku %d\n" #: .././repair/agheader.c:443 #, c-format msgid "bad stripe unit/width fields in superblock %d\n" msgstr "błędne pola jednostki/szerokoÅ›ci pasa w superbloku %d\n" #: .././repair/agheader.c:461 #, c-format msgid "bad log/data device sector size fields in superblock %d\n" msgstr "błędne pola rozmiaru sektora urzÄ…dzenia logu/danych w superbloku %d\n" #: .././repair/agheader.c:492 #, c-format msgid "bad on-disk superblock %d - %s\n" msgstr "błędny superblok %d na dysku - %s\n" #: .././repair/agheader.c:499 #, c-format msgid "primary/secondary superblock %d conflict - %s\n" msgstr "konflikt głównego/zapasowego superbloku %d - %s\n" #: .././repair/attr_repair.c:70 #, c-format msgid "bad range claimed [%d, %d) in da block\n" msgstr "błędny przedziaÅ‚ [%d, %d) przypisany w bloku da\n" #: .././repair/attr_repair.c:77 #, c-format msgid "byte range end [%d %d) in da block larger than blocksize %d\n" msgstr "" "koniec przedziaÅ‚u bajtów [%d %d) w bloku da wiÄ™kszy niż rozmiar bloku %d\n" #: .././repair/attr_repair.c:84 #, c-format msgid "multiply claimed byte %d in da block\n" msgstr "wielokrotnie użyty bajt %d w bloku da\n" #: .././repair/attr_repair.c:164 msgid "No memory for ACL check!\n" msgstr "Brak pamiÄ™ci na sprawdzenie ACL!\n" #: .././repair/attr_repair.c:172 msgid "" "entry contains illegal value in attribute named SGI_ACL_FILE or " "SGI_ACL_DEFAULT\n" msgstr "" "wpis zawiera niedozwolonÄ… wartość w atrybucie SGI_ACL_FILE lub " "SGI_ACL_DEFAULT\n" #: .././repair/attr_repair.c:198 msgid "entry contains illegal value in attribute named SGI_MAC_LABEL\n" msgstr "wpis zawiera niedozwolonÄ… wartość w atrybucie SGI_MAC_LABEL\n" #: .././repair/attr_repair.c:204 msgid "entry contains illegal value in attribute named SGI_CAP_FILE\n" msgstr "wpis zawiera niedozwolonÄ… wartość w atrybucie SGI_CAP_FILE\n" #: .././repair/attr_repair.c:244 #, c-format msgid "there are no attributes in the fork for inode %\n" msgstr "nie ma atrybutów w gałęzi dla i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:252 #, c-format msgid "would junk the attribute fork since count is 0 for inode %\n" msgstr "" "gałąź atrybutów zostaÅ‚aby usuniÄ™ta ponieważ licznik wynosi 0 dla i-wÄ™zÅ‚a " "%\n" #: .././repair/attr_repair.c:272 msgid "zero length name entry in attribute fork," msgstr "wpis nazwy zerowej dÅ‚ugoÅ›ci w gałęzi atrybutów," #: .././repair/attr_repair.c:275 .././repair/attr_repair.c:295 #, c-format msgid " truncating attributes for inode % to %d\n" msgstr " uciÄ™to atrybuty dla i-wÄ™zÅ‚a % do %d\n" #: .././repair/attr_repair.c:280 .././repair/attr_repair.c:301 #, c-format msgid " would truncate attributes for inode % to %d\n" msgstr " atrybuty dla i-wÄ™zÅ‚a % zostaÅ‚yby uciÄ™te do %d\n" #: .././repair/attr_repair.c:292 msgid "name or value attribute lengths are too large,\n" msgstr "dÅ‚ugoÅ›ci nazwy lub wartoÅ›ci atrybutów sÄ… zbyt duże,\n" #: .././repair/attr_repair.c:314 msgid "entry contains illegal character in shortform attribute name\n" msgstr "wpis zawiera niedozwolony znak w nazwie atrybutu krótkiego\n" #: .././repair/attr_repair.c:320 msgid "entry has INCOMPLETE flag on in shortform attribute\n" msgstr "wpis ma flagÄ™ NIEPEÅNY w atrybucie krótkim\n" #: .././repair/attr_repair.c:338 #, c-format msgid "removing attribute entry %d for inode %\n" msgstr "usuniÄ™to wpis atrybutu %d dla i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:350 #, c-format msgid "would remove attribute entry %d for inode %\n" msgstr "wpis atrybutu %d dla i-wÄ™zÅ‚a % zostaÅ‚by usuniÄ™ty\n" #: .././repair/attr_repair.c:365 #, c-format msgid "" "would have corrected attribute entry count in inode % from %d to %d\n" msgstr "" "liczba wpisów atrybutów w i-węźle % zostaÅ‚aby poprawiona z %d na %d\n" #: .././repair/attr_repair.c:369 #, c-format msgid "corrected attribute entry count in inode %, was %d, now %d\n" msgstr "" "poprawiono liczbÄ™ wpisów atrybutów w i-węźle % - byÅ‚o %d, jest %d\n" #: .././repair/attr_repair.c:380 #, c-format msgid "" "would have corrected attribute totsize in inode % from %d to %d\n" msgstr "totsize atrybutów w i-węźle % zostaÅ‚by poprawiony z %d na %d\n" #: .././repair/attr_repair.c:385 #, c-format msgid "corrected attribute entry totsize in inode %, was %d, now %d\n" msgstr "" "poprawiono totsize wpisu atrybutów w i-węźle % - byÅ‚o %d, jest %d\n" #: .././repair/attr_repair.c:419 #, c-format msgid "remote block for attributes of inode % is missing\n" msgstr "brak odlegÅ‚ego bloku dla atrybutów i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:428 #, c-format msgid "can't read remote block for attributes of inode %\n" msgstr "nie można odczytać odlegÅ‚ego bloku dla atrybutów i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:435 #, c-format msgid "Corrupt remote block for attributes of inode %\n" msgstr "Uszkodzony odlegÅ‚y blok dla atrybutów i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:476 #, c-format msgid "" "attribute entry %d in attr block %u, inode % has bad name (namelen = " "%d)\n" msgstr "" "wpis atrybutu %d w bloku atrybutów %u, i-węźle % ma błędnÄ… nazwÄ™ " "(namelen = %d)\n" #: .././repair/attr_repair.c:493 #, c-format msgid "" "bad hashvalue for attribute entry %d in attr block %u, inode %\n" msgstr "" "błędna wartość hasza dla wpisu atrybutu %d w bloku atrybutów %u, i-węźle " "%\n" #: .././repair/attr_repair.c:503 #, c-format msgid "" "bad security value for attribute entry %d in attr block %u, inode %\n" msgstr "" "błędna wartość bezpieczeÅ„stwa dla wpisu atrybutu %d w bloku atrybutów %u, i-" "węźle %\n" #: .././repair/attr_repair.c:536 #, c-format msgid "" "inconsistent remote attribute entry %d in attr block %u, ino %\n" msgstr "" "niespójny wpis odlegÅ‚ego atrybutu %d w bloku atrybutów %u, i-węźle " "%\n" #: .././repair/attr_repair.c:546 #, c-format msgid "cannot malloc enough for remotevalue attribute for inode %\n" msgstr "" "nie można przydzielić wystarczajÄ…co dużo dla atrybutu remotevalue dla i-" "wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:548 msgid "SKIPPING this remote attribute\n" msgstr "POMINIĘTO ten atrybut odlegÅ‚y\n" #: .././repair/attr_repair.c:554 #, c-format msgid "remote attribute get failed for entry %d, inode %\n" msgstr "" "pobranie odlegÅ‚ego atrybutu nie powiodÅ‚o siÄ™ dla wpisu %d, i-wÄ™zÅ‚a " "%\n" #: .././repair/attr_repair.c:561 #, c-format msgid "remote attribute value check failed for entry %d, inode %\n" msgstr "" "sprawdzenie wartoÅ›ci odlegÅ‚ego atrybutu nie powiodÅ‚o siÄ™ dla wpisu %d, i-" "wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:600 #, c-format msgid "bad attribute count %d in attr block %u, inode %\n" msgstr "błędna liczba atrybutów %d w bloku atrybutów %u, i-węźle %\n" #: .././repair/attr_repair.c:615 #, c-format msgid "bad attribute nameidx %d in attr block %u, inode %\n" msgstr "błędny nameidx atrybutu %d w bloku atrybutów %u, i-węźle %\n" #: .././repair/attr_repair.c:624 #, c-format msgid "attribute entry #%d in attr block %u, inode % is INCOMPLETE\n" msgstr "" "wpis atrybutu #%d w bloku atrybutów %u, i-węźle % jest NIEPEÅNY\n" #: .././repair/attr_repair.c:635 #, c-format msgid "" "attribute entry %d in attr block %u, inode % claims already used " "space\n" msgstr "" "wpis atrybutu %d w bloku atrybutów %u, i-węźle % odwoÅ‚uje siÄ™ do już " "użytego miejsca\n" #: .././repair/attr_repair.c:658 #, c-format msgid "" "attribute entry %d in attr block %u, inode % claims used space\n" msgstr "" "wpis atrybutu %d w bloku atrybutów %u, i-węźle % odwoÅ‚uje siÄ™ do " "używanego miejsca\n" #: .././repair/attr_repair.c:682 #, c-format msgid "" "- resetting first used heap value from %d to %d in block %u of attribute " "fork of inode %\n" msgstr "" "- przestawiono pierwszÄ… używanÄ… wartość sterty z %d na %d w bloku %u gałęzi " "atrybutów i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:690 #, c-format msgid "" "- would reset first used value from %d to %d in block %u of attribute fork " "of inode %\n" msgstr "" "- pierwsza używana wartość zostaÅ‚aby przestawiona z %d na %d w bloku %u " "gałęzi atrybutów i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:700 #, c-format msgid "" "- resetting usedbytes cnt from %d to %d in block %u of attribute fork of " "inode %\n" msgstr "" "- przestawiono liczbÄ™ użytych bajtów z %d na %d w bloku %u gałęzi atrybutów " "i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:708 #, c-format msgid "" "- would reset usedbytes cnt from %d to %d in block %u of attribute fork of " "%\n" msgstr "" "- liczba użytych bajtów zostaÅ‚aby przestawiona z %d na %d w bloku %u gałęzi " "atrybutów i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:763 #, c-format msgid "btree cycle detected in attribute fork for inode %\n" msgstr "wykryto cykl b-drzewa w gałęzi atrybutów dla i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:775 #, c-format msgid "can't map block %u for attribute fork for inode %\n" msgstr "" "nie można odwzorować bloku %u dla gałęzi atrybutów dla i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:785 #, c-format msgid "" "can't read file block %u (fsbno %) for attribute fork of inode " "%\n" msgstr "" "nie można odczytać bloku pliku %u (fsbno %) dla gałęzi atrybutów i-" "wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:797 #, c-format msgid "bad attribute leaf magic %#x for inode %\n" msgstr "błędna liczba magiczna liÅ›cia atrybutu %#x dla i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:828 #, c-format msgid "" "bad sibling back pointer for block %u in attribute fork for inode %\n" msgstr "" "błędny wskaźnik wsteczny dla bloku %u w gałęzi atrybutów dla i-wÄ™zÅ‚a " "%\n" #: .././repair/attr_repair.c:863 #, c-format msgid "bad hash path in attribute fork for inode %\n" msgstr "błędna Å›cieżka hasza w gałęzi atrybutów dla i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:945 #, c-format msgid "expected owner inode %, got %llu, attr block %\n" msgstr "" "oczekiwano i-wÄ™zÅ‚a wÅ‚aÅ›ciciela %, napotkano %llu, blok attr " "%\n" #: .././repair/attr_repair.c:953 #, c-format msgid "expected block %, got %llu, inode %attr block\n" msgstr "" "oczekiwano bloku %, napotkano %llu, blok attr i-wÄ™zÅ‚a %\n" #: .././repair/attr_repair.c:961 #, c-format msgid "wrong FS UUID, inode % attr block %\n" msgstr "błędny UUID systemu plików, i-wÄ™zeÅ‚ % blok attr %\n" #: .././repair/attr_repair.c:1003 #, c-format msgid "block 0 of inode % attribute fork is missing\n" msgstr "brak bloku 0 i-wÄ™zÅ‚a % gałęzi atrybutów\n" #: .././repair/attr_repair.c:1010 #, c-format msgid "agno of attribute fork of inode % out of regular partition\n" msgstr "agno gałęzi atrybutów i-wÄ™zÅ‚a % spoza zwykÅ‚ej partycji\n" #: .././repair/attr_repair.c:1018 #, c-format msgid "can't read block 0 of inode % attribute fork\n" msgstr "nie można odczytać bloku 0 i-wÄ™zÅ‚a % gałęzi atrybutów\n" #: .././repair/attr_repair.c:1042 #, c-format msgid "" "clearing forw/back pointers in block 0 for attributes in inode %\n" msgstr "" "wyczyszczono wskaźniki forw/back w bloku 0 dla atrybutów w i-węźle " "%\n" #: .././repair/attr_repair.c:1051 #, c-format msgid "" "would clear forw/back pointers in block 0 for attributes in inode %\n" msgstr "" "wskaźniki forw/back w bloku 0 dla atrybutów w i-węźle % zostaÅ‚yby " "wyczyszczone\n" #: .././repair/attr_repair.c:1087 #, c-format msgid "bad attribute leaf magic # %#x for dir ino %\n" msgstr "" "błędna liczba magiczna liÅ›cia atrybutu %#x dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/attr_repair.c:1117 #, c-format msgid "Too many ACL entries, count %d\n" msgstr "Za dużo wpisów ACL, liczba %d\n" #: .././repair/attr_repair.c:1126 msgid "cannot malloc enough for ACL attribute\n" msgstr "nie można wykonać wystarczajÄ…cego malloc dla atrybutu ACL\n" #: .././repair/attr_repair.c:1127 msgid "SKIPPING this ACL\n" msgstr "POMINIĘTO ten ACL\n" #: .././repair/attr_repair.c:1177 .././repair/dinode.c:2077 #, c-format msgid "illegal attribute format %d, ino %\n" msgstr "niedozwolony format atrybutu %d, i-wÄ™zeÅ‚ %\n" #: .././repair/bmap.c:53 #, c-format msgid "" "Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n" "If this is not a corruption, then you will need a 64 bit system\n" "to repair this filesystem.\n" msgstr "" "Liczba ekstentów żądanych w blkmap_alloc (%d) przepeÅ‚nia 32 bity.\n" "JeÅ›li nie jest to efekt uszkodzenia, do naprawy tego systemu plików\n" "niezbÄ™dny jest system 64-bitowy.\n" #: .././repair/bmap.c:66 #, c-format msgid "malloc failed in blkmap_alloc (%zu bytes)\n" msgstr "malloc nie powiodÅ‚o siÄ™ w blkmap_alloc (%zu bajtów)\n" #: .././repair/bmap.c:189 #, c-format msgid "blkmap_getn malloc failed (% bytes)\n" msgstr "malloc w blkmap_getn nie powiodÅ‚o siÄ™ (% bajtów)\n" #: .././repair/bmap.c:296 #, c-format msgid "" "Number of extents requested in blkmap_grow (%d) overflows 32 bits.\n" "You need a 64 bit system to repair this filesystem.\n" msgstr "" "Liczba ekstentów żądanych w blkmap_grow (%d) przepeÅ‚nia 32 bity.\n" "Do naprawy tego systemu plików niezbÄ™dny jest system 64-bitowy.\n" #: .././repair/bmap.c:304 #, c-format msgid "" "Number of extents requested in blkmap_grow (%d) overflowed the\n" "maximum number of supported extents (%d).\n" msgstr "" "Liczba ekstentów żądanych w blkmap_grow (%d) przepeÅ‚niÅ‚a maksymalnÄ…\n" "liczbÄ™ obsÅ‚ugiwanych ekstentów (%d).\n" #: .././repair/bmap.c:312 msgid "realloc failed in blkmap_grow\n" msgstr "realloc nie powiodÅ‚o siÄ™ w blkmap_grow\n" #: .././repair/da_util.c:88 .././repair/prefetch.c:238 msgid "couldn't malloc dir2 buffer list\n" msgstr "nie można przydzielić listy bufora dir2\n" #: .././repair/da_util.c:105 msgid "attribute" msgstr "atrybut" #: .././repair/da_util.c:164 .././repair/da_util.c:585 #, c-format msgid "can't read %s block %u for inode %\n" msgstr "nie można odczytać bloku %su %u dla i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:177 #, c-format msgid "found non-root LEAFN node in inode % bno = %u\n" msgstr "znaleziono niegłówny wÄ™zeÅ‚ LEAFN w i-węźle % bno = %u\n" #: .././repair/da_util.c:188 #, c-format msgid "bad %s magic number 0x%x in inode % bno = %u\n" msgstr "błędna liczba magiczna %su 0x%x w i-węźle % bno = %u\n" #: .././repair/da_util.c:199 #, c-format msgid "corrupt %s tree block %u for inode %\n" msgstr "uszkodzony blok drzewa %su %u w i-węźle %\n" #: .././repair/da_util.c:207 #, c-format msgid "bad %s record count in inode %, count = %d, max = %d\n" msgstr "" "błędna liczba rekordów %su w i-węźle %, liczba = %d, maksimum = %d\n" #: .././repair/da_util.c:221 #, c-format msgid "bad header depth for directory inode %\n" msgstr "błędna głębokość nagłówka dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/da_util.c:232 #, c-format msgid "bad %s btree for inode %\n" msgstr "błędne b-drzewo %su dla i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:282 #, c-format msgid "release_da_cursor_int got unexpected non-null bp, dabno = %u\n" msgstr "" "release_da_cursor_int otrzymaÅ‚o nieoczekiwany niepusty bp, dabno = %u\n" #: .././repair/da_util.c:360 #, c-format msgid "%s block used/count inconsistency - %d/%hu\n" msgstr "niespójność wartoÅ›ci used/count bloku %su - %d / %hu\n" #: .././repair/da_util.c:370 #, c-format msgid "%s block hashvalue inconsistency, expected > %u / saw %u\n" msgstr "niespójność wartoÅ›ci hasza bloku %su - oczekiwano > %u, napotkano %u\n" #: .././repair/da_util.c:378 #, c-format msgid "bad %s forward block pointer, expected 0, saw %u\n" msgstr "błędny wskaźnik bloku w przód %su - oczekiwano 0, napotkano %u\n" #: .././repair/da_util.c:383 #, c-format msgid "bad %s block in inode %\n" msgstr "błędny blok %su w i-węźle %\n" #: .././repair/da_util.c:413 #, c-format msgid "" "correcting bad hashval in non-leaf %s block\n" "\tin (level %d) in inode %.\n" msgstr "" "poprawiono błędne hashval w bloku %su nie bÄ™dÄ…cego liÅ›ciem\n" "\tw i-węźle (poziomu %d) %.\n" #: .././repair/da_util.c:421 #, c-format msgid "" "would correct bad hashval in non-leaf %s block\n" "\tin (level %d) in inode %.\n" msgstr "" "błędne hashval w bloku %su nie bÄ™dÄ…cego liÅ›ciem zostaÅ‚oby poprawione\n" "\tw i-węźle (poziomu %d) %.\n" #: .././repair/da_util.c:574 #, c-format msgid "can't get map info for %s block %u of inode %\n" msgstr "" "nie można uzyskać informacji o mapie dla bloku %su %u i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:602 #, c-format msgid "bad magic number %x in %s block %u for inode %\n" msgstr "błędna liczba magiczna %x w bloku %su %u dla i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:609 #, c-format msgid "bad back pointer in %s block %u for inode %\n" msgstr "błędny wskaźnik wstecz w bloku %su %u dla i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:615 #, c-format msgid "entry count %d too large in %s block %u for inode %\n" msgstr "liczba wpisów %d zbyt duża w bloku %su %u dla i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:622 #, c-format msgid "bad level %d in %s block %u for inode %\n" msgstr "błędny poziom %d w bloku %su %u dla i-wÄ™zÅ‚a %\n" #: .././repair/da_util.c:686 #, c-format msgid "" "correcting bad hashval in interior %s block\n" "\tin (level %d) in inode %.\n" msgstr "" "poprawiono błędne hashval w wewnÄ™trznym bloku %su\n" "\tw i-węźle (poziomu %d) %.\n" #: .././repair/da_util.c:694 #, c-format msgid "" "would correct bad hashval in interior %s block\n" "\tin (level %d) in inode %.\n" msgstr "" "błędne hashval w wewnÄ™trznym bloku %su zostaÅ‚oby poprawione\n" "\tw i-węźle (poziomu %d) %.\n" #: .././repair/dino_chunks.c:57 #, c-format msgid "cannot read agbno (%u/%u), disk block %\n" msgstr "nie można odczytać agbno (%u/%u), blok dysku %\n" #: .././repair/dino_chunks.c:150 #, c-format msgid "uncertain inode block %d/%d already known\n" msgstr "niepewny blok i-wÄ™zÅ‚a %d/%d już znany\n" #: .././repair/dino_chunks.c:166 .././repair/dino_chunks.c:438 #: .././repair/dino_chunks.c:497 #, c-format msgid "inode block %d/%d multiply claimed, (state %d)\n" msgstr "blok i-wÄ™zÅ‚a %d/%d już przypisany (stan %d)\n" #: .././repair/dino_chunks.c:173 .././repair/dino_chunks.c:502 #, c-format msgid "inode block %d/%d bad state, (state %d)\n" msgstr "blok i-wÄ™zÅ‚a (%d/%d) w błędnym stanie (stan %d)\n" #: .././repair/dino_chunks.c:445 #, c-format msgid "uncertain inode block overlap, agbno = %d, ino = %\n" msgstr "niepewny blok i-wÄ™zÅ‚a pokrywa siÄ™, agbno = %d, i-wÄ™zeÅ‚ %\n" #: .././repair/dino_chunks.c:484 #, c-format msgid "uncertain inode block % already known\n" msgstr "niepewny blok i-wÄ™zÅ‚a % już znany\n" #: .././repair/dino_chunks.c:578 #, c-format msgid "bad state in block map %d\n" msgstr "błędny stan w mapie bloku %d\n" #: .././repair/dino_chunks.c:583 #, c-format msgid "inode block % multiply claimed, state was %d\n" msgstr "blok i-wÄ™zÅ‚a % wielokrotnie przydzielony, stan byÅ‚ %d\n" #: .././repair/dino_chunks.c:654 #, c-format msgid "failed to allocate %zd bytes of memory\n" msgstr "nie udaÅ‚o siÄ™ przydzielić %zd bajtów pamiÄ™ci\n" #: .././repair/dino_chunks.c:678 #, c-format msgid "cannot read inode %, disk block %, cnt %d\n" msgstr "nie można odczytać i-wÄ™zÅ‚a %, blok dysku %, cnt %d\n" #: .././repair/dino_chunks.c:832 #, c-format msgid "imap claims in-use inode % is free, " msgstr "imap twierdzi, że używany i-wÄ™zeÅ‚ % jest wolny, " #: .././repair/dino_chunks.c:837 msgid "correcting imap\n" msgstr "poprawiono imap\n" #: .././repair/dino_chunks.c:839 msgid "would correct imap\n" msgstr "imap zostaÅ‚oby poprawione\n" #: .././repair/dino_chunks.c:892 #, c-format msgid "cleared root inode %\n" msgstr "wyczyszczono główny i-wÄ™zeÅ‚ %\n" #: .././repair/dino_chunks.c:896 #, c-format msgid "would clear root inode %\n" msgstr "główny wÄ™zeÅ‚ % zostaÅ‚by wyczyszczony\n" #: .././repair/dino_chunks.c:904 #, c-format msgid "cleared realtime bitmap inode %\n" msgstr "wyczyszczono i-wÄ™zeÅ‚ bitmapy realtime %\n" #: .././repair/dino_chunks.c:908 #, c-format msgid "would clear realtime bitmap inode %\n" msgstr "i-wÄ™zeÅ‚ bitmapy realtime % zostaÅ‚by wyczyszczony\n" #: .././repair/dino_chunks.c:916 #, c-format msgid "cleared realtime summary inode %\n" msgstr "wyczyszczono i-wÄ™zeÅ‚ opisu realtime %\n" #: .././repair/dino_chunks.c:920 #, c-format msgid "would clear realtime summary inode %\n" msgstr "i-wÄ™zeÅ‚ opisu realtime % zostaÅ‚by wyczyszczony\n" #: .././repair/dino_chunks.c:924 #, c-format msgid "cleared inode %\n" msgstr "wyczyszczono i-wÄ™zeÅ‚ %\n" #: .././repair/dino_chunks.c:927 #, c-format msgid "would have cleared inode %\n" msgstr "i-wÄ™zeÅ‚ % zostaÅ‚by wyczyszczony\n" #: .././repair/dino_chunks.c:1118 .././repair/dino_chunks.c:1153 #: .././repair/dino_chunks.c:1267 msgid "found inodes not in the inode allocation tree\n" msgstr "znaleziono i-wÄ™zÅ‚y nieobecne w drzewie alokacji i-wÄ™złów\n" #: .././repair/dinode.c:54 msgid "real-time" msgstr "realtime" #: .././repair/dinode.c:55 msgid "regular" msgstr "zwykÅ‚ym" #: .././repair/dinode.c:78 #, c-format msgid "clearing inode % attributes\n" msgstr "wyczyszczono atrybuty i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:81 #, c-format msgid "would have cleared inode % attributes\n" msgstr "atrybuty i-wÄ™zÅ‚a % zostaÅ‚yby wyczyszczone\n" #: .././repair/dinode.c:444 #, c-format msgid "" "inode % - bad rt extent start block number %, offset " "%\n" msgstr "" "i-wÄ™zeÅ‚ % - błędny numer bloku poczÄ…tkowego ekstentu rt %, " "offset %\n" #: .././repair/dinode.c:452 #, c-format msgid "" "inode % - bad rt extent last block number %, offset " "%\n" msgstr "" "i-wÄ™zeÅ‚ % - błędny numer bloku koÅ„cowego ekstentu rt %, " "offset %\n" #: .././repair/dinode.c:460 #, c-format msgid "" "inode % - bad rt extent overflows - start %, end %, " "offset %\n" msgstr "" "i-wÄ™zeÅ‚ % - błędne przepeÅ‚nienie ekstentu rt - poczÄ…tek %, " "koniec %, offset %\n" #: .././repair/dinode.c:477 #, c-format msgid "malformed rt inode extent [% %] (fs rtext size = %u)\n" msgstr "" "znieksztaÅ‚cony ekstent i-wÄ™zÅ‚a rt [% %] (rozmiar fs rtext = " "%u)\n" #: .././repair/dinode.c:498 #, c-format msgid "" "data fork in rt ino % claims dup rt extent,off - %, start - " "%, count %\n" msgstr "" "gałąź danych w i-węźle rt % odwoÅ‚uje siÄ™ do powtórzonego ekstentu " "rt, offset %, poczÄ…tek %, liczba %\n" #: .././repair/dinode.c:517 #, c-format msgid "bad state in rt block map %\n" msgstr "błędny stan w mapie bloku rt %\n" #: .././repair/dinode.c:523 #, c-format msgid "" "data fork in rt inode % found metadata block % in rt bmap\n" msgstr "" "gałąź danych w i-węźle rt % - znaleziono blok metadanych % w " "bmapie rt\n" #: .././repair/dinode.c:531 #, c-format msgid "data fork in rt inode % claims used rt block %\n" msgstr "" "gałąź danych w i-węźle rt % odwoÅ‚uje siÄ™ do używanego bloku rt " "%\n" #: .././repair/dinode.c:537 #, c-format msgid "illegal state %d in rt block map %\n" msgstr "niedozwolony stan %d w mapie bloku rt %\n" #: .././repair/dinode.c:600 #, c-format msgid "" "bmap rec out of order, inode % entry %d [o s c] [% % " "%], %d [% % %]\n" msgstr "" "rekord bmap uszkodzony, i-wÄ™zeÅ‚ % wpis %d [o s c] [% " "% %], %d [% % %]\n" #: .././repair/dinode.c:616 #, c-format msgid "" "zero length extent (off = %, fsbno = %) in ino %\n" msgstr "" "ekstent zerowej dÅ‚ugoÅ›ci (off = %, fsbno = %) w i-węźle " "%\n" #: .././repair/dinode.c:647 #, c-format msgid "" "inode % - bad extent starting block number %, offset " "%\n" msgstr "" "i-wÄ™zeÅ‚ % - błędny numer bloku poczÄ…tkowego ekstentu %, " "offset %\n" #: .././repair/dinode.c:655 #, c-format msgid "" "inode % - bad extent last block number %, offset %\n" msgstr "" "i-wÄ™zeÅ‚ % - błędny numer bloku koÅ„cowego ekstentu %, offset " "%\n" #: .././repair/dinode.c:663 #, c-format msgid "" "inode % - bad extent overflows - start %, end %, " "offset %\n" msgstr "" "i-wÄ™zeÅ‚ % - błędne przepeÅ‚nienie ekstentu - poczÄ…tek %, " "koniec %, offset %\n" #: .././repair/dinode.c:675 #, c-format msgid "" "inode % - extent exceeds max offset - start %, count " "%, physical block %\n" msgstr "" "i-wÄ™zeÅ‚ % - ekstent przekracza maksymalny offset - poczÄ…tek " "%, liczba %, blok fizyczny %\n" #: .././repair/dinode.c:696 #, c-format msgid "" "Fatal error: inode % - blkmap_set_ext(): %s\n" "\t%s fork, off - %, start - %, cnt %\n" msgstr "" "Błąd krytyczny: i-wÄ™zeÅ‚ % - blkmap_set_ext(): %s\n" "\tgałąź %s, offset %, poczÄ…tek %, liczba %\n" #: .././repair/dinode.c:729 #, c-format msgid "" "%s fork in ino % claims dup extent, off - %, start - " "%, cnt %\n" msgstr "" "gałąź %s w i-węźle % odwoÅ‚uje siÄ™ do powtórzonego ekstentu, offset " "%, poczÄ…tek %, liczba %\n" #: .././repair/dinode.c:748 #, c-format msgid "%s fork in ino % claims free block %\n" msgstr "gałąź %s w i-węźle % odwoÅ‚uje siÄ™ do wolnego bloku %\n" #: .././repair/dinode.c:757 #, c-format msgid "bad state in block map %\n" msgstr "błędny stan w mapie bloku %\n" #: .././repair/dinode.c:762 msgid "rmap claims metadata use!\n" msgstr "rmap ma przypisane użycie metadanych!\n" #: .././repair/dinode.c:769 #, c-format msgid "%s fork in inode % claims metadata block %\n" msgstr "" "gałąź %s w i-węźle % odwoÅ‚uje siÄ™ do bloku metadanych %\n" #: .././repair/dinode.c:780 #, c-format msgid "%s fork in %s inode % claims used block %\n" msgstr "" "gałąź %s w i-węźle %s % odwoÅ‚uje siÄ™ do używanego bloku %\n" #: .././repair/dinode.c:786 #, c-format msgid "%s fork in %s inode % claims CoW block %\n" msgstr "gałąź %s w i-węźle %s % odwoÅ‚uje siÄ™ do bloku CoW %\n" #: .././repair/dinode.c:792 #, c-format msgid "illegal state %d in block map %\n" msgstr "niedozwolony stan %d w mapie bloku %\n" #: .././repair/dinode.c:800 msgid "couldn't add reverse mapping\n" msgstr "nie udaÅ‚o siÄ™ dodać odwzorowania odwrotnego\n" #: .././repair/dinode.c:812 #, c-format msgid "correcting nextents for inode %\n" msgstr "poprawiono nextents dla i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:904 #, c-format msgid "cannot read inode (%u/%u), disk block %\n" msgstr "nie można odczytać i-wÄ™zÅ‚a (%u/%u), blok dysku %\n" #: .././repair/dinode.c:972 #, c-format msgid "bad level %d in inode % bmap btree root block\n" msgstr "błędny poziom %d w bloku głównym bmap btree i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:978 #, c-format msgid "bad numrecs 0 in inode % bmap btree root block\n" msgstr "błędne numrecs 0 w bloku głównym bmap btree i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:987 #, c-format msgid "" "indicated size of %s btree root (%d bytes) greater than space in inode " "% %s fork\n" msgstr "" "oznaczony rozmiar korzenia b-drzewa %s (%d bajtów) wiÄ™kszy niż miejsce w i-" "węźle % gałęzi %s\n" #: .././repair/dinode.c:1008 #, c-format msgid "bad bmap btree ptr 0x% in ino %\n" msgstr "błędny wskaźnik bmap btree 0x% w i-węźle %\n" #: .././repair/dinode.c:1028 #, c-format msgid "" "correcting key in bmbt root (was %, now %) in inode " "% %s fork\n" msgstr "" "poprawiono klucz w korzeniu bmbt (byÅ‚ %, jest %) w i-węźle " "% gałęzi %s\n" #: .././repair/dinode.c:1040 #, c-format msgid "" "bad key in bmbt root (is %, would reset to %) in inode " "% %s fork\n" msgstr "" "błędny klucz w korzeniu bmbt (jest %, zostaÅ‚by przestawiony na " "%) w i-węźle % gałęzi %s\n" #: .././repair/dinode.c:1056 #, c-format msgid "out of order bmbt root key % in inode % %s fork\n" msgstr "" "niepoprawny klucz korzenia bmbt % w i-węźle % gałęzi %s\n" #: .././repair/dinode.c:1073 #, c-format msgid "" "extent count for ino % %s fork too low (%) for file format\n" msgstr "" "i-wÄ™zeÅ‚ %: liczba ekstentów dla gałęzi %s zbyt maÅ‚a (%) dla " "formatu pliku\n" #: .././repair/dinode.c:1084 #, c-format msgid "bad fwd (right) sibling pointer (saw % should be NULLFSBLOCK)\n" msgstr "" "błędny wskaźnik fwd (prawy) (napotkano %, powinno być NULLFSBLOCK)\n" #: .././repair/dinode.c:1087 #, c-format msgid "\tin inode % (%s fork) bmap btree block %\n" msgstr "\tw i-węźle % (gałęzi %s) bloku bmap btree %\n" #: .././repair/dinode.c:1169 #, c-format msgid "local inode % data fork is too large (size = %lld, max = %d)\n" msgstr "" "gałąź danych lokalnego i-wÄ™zÅ‚a % zbyt duża (rozmiar = %lld, maksimum " "= %d)\n" #: .././repair/dinode.c:1177 #, c-format msgid "local inode % attr fork too large (size %d, max = %d)\n" msgstr "" "gałąź atrybutów lokalnego i-wÄ™zÅ‚a % zbyt duża (rozmiar %d, maksimum " "= %d)\n" #: .././repair/dinode.c:1184 #, c-format msgid "local inode % attr too small (size = %d, min size = %zd)\n" msgstr "" "gałąź atrybutów lokalnego i-wÄ™zÅ‚a % zbyt maÅ‚a (rozmiar = %d, minimum " "= %zd)\n" #: .././repair/dinode.c:1208 #, c-format msgid "" "mismatch between format (%d) and size (%) in symlink ino %\n" msgstr "" "niezgodność miÄ™dzy formatem (%d) a rozmiarem (%) w i-węźle " "dowiÄ…zania symbolicznego %\n" #: .././repair/dinode.c:1215 #, c-format msgid "" "mismatch between format (%d) and size (%) in symlink inode " "%\n" msgstr "" "niezgodność miÄ™dzy formatem (%d) a rozmiarem (%) w i-węźle " "dowiÄ…zania symbolicznego %\n" #: .././repair/dinode.c:1230 #, c-format msgid "bad number of extents (%d) in symlink % data fork\n" msgstr "" "błędna liczba ekstentów (%d) w gałęzi danych dowiÄ…zania symbolicznego " "%\n" #: .././repair/dinode.c:1242 #, c-format msgid "bad extent #%d offset (%) in symlink % data fork\n" msgstr "" "błędny offset ekstentu %d (%) w gałęzi danych dowiÄ…zania " "symbolicznego %\n" #: .././repair/dinode.c:1248 #, c-format msgid "bad extent #%d count (%) in symlink % data fork\n" msgstr "" "błędna liczba ekstentów #%d (%) w gałęzi danych dowiÄ…zania " "symbolicznego %\n" #: .././repair/dinode.c:1306 #, c-format msgid "cannot read inode %, file block %d, NULL disk block\n" msgstr "" "nie można odczytać i-wÄ™zÅ‚a %, blok pliku %d, zerowy blok dysku\n" #: .././repair/dinode.c:1328 #, c-format msgid "cannot read inode %, file block %d, disk block %\n" msgstr "" "nie można odczytać i-wÄ™zÅ‚a %, blok pliku %d, blok dysku %\n" #: .././repair/dinode.c:1334 #, c-format msgid "" "Bad symlink buffer CRC, block %, inode %.\n" "Correcting CRC, but symlink may be bad.\n" msgstr "" "Błędna suma kontrolna bufora dowiÄ…zania symbolicznego, blok %, i-" "wÄ™zeÅ‚ %.\n" "Poprawianie CRC, ale dowiÄ…zanie symboliczne może być błędne.\n" #: .././repair/dinode.c:1347 #, c-format msgid "bad symlink header ino %, file block %d, disk block %\n" msgstr "" "błędny i-wÄ™zeÅ‚ nagłówka dowiÄ…zania symbolicznego %, blok pliku %d, " "blok dysku %\n" #: .././repair/dinode.c:1390 #, c-format msgid "symlink in inode % too long (%llu chars)\n" msgstr "dowiÄ…zanie symboliczne w i-węźle % zbyt dÅ‚ugie (%llu znaków)\n" #: .././repair/dinode.c:1396 #, c-format msgid "zero size symlink in inode %\n" msgstr "dowiÄ…zanie symboliczne o zerowym rozmiarze w i-węźle %\n" #: .././repair/dinode.c:1427 #, c-format msgid "found illegal null character in symlink inode %\n" msgstr "" "znaleziono niedozwolony znak null w i-węźle dowiÄ…zania symbolicznego " "%\n" #: .././repair/dinode.c:1452 #, c-format msgid "inode % has bad inode type (IFMNT)\n" msgstr "i-wÄ™zeÅ‚ % ma błędny typ i-wÄ™zÅ‚a (IFMNT)\n" #: .././repair/dinode.c:1463 #, c-format msgid "size of character device inode % != 0 (% bytes)\n" msgstr "" "rozmiar i-wÄ™zÅ‚a urzÄ…dzenia znakowego % != 0 (% bajtów)\n" #: .././repair/dinode.c:1468 #, c-format msgid "size of block device inode % != 0 (% bytes)\n" msgstr "" "rozmiar i-wÄ™zÅ‚a urzÄ…dzenia blokowego % != 0 (% bajtów)\n" #: .././repair/dinode.c:1473 #, c-format msgid "size of socket inode % != 0 (% bytes)\n" msgstr "rozmiar i-wÄ™zÅ‚a gniazda % != 0 (% bajtów)\n" #: .././repair/dinode.c:1478 #, c-format msgid "size of fifo inode % != 0 (% bytes)\n" msgstr "rozmiar i-wÄ™zÅ‚a potoku % != 0 (% bajtów)\n" #: .././repair/dinode.c:1482 #, c-format msgid "Internal error - process_misc_ino_types, illegal type %d\n" msgstr "Błąd wewnÄ™trzny - process_misc_ino_types, niedozwolony typ %d\n" #: .././repair/dinode.c:1509 #, c-format msgid "size of character device inode % != 0 (% blocks)\n" msgstr "" "rozmiar i-wÄ™zÅ‚a urzÄ…dzenia znakowego % != 0 (% bloków)\n" #: .././repair/dinode.c:1514 #, c-format msgid "size of block device inode % != 0 (% blocks)\n" msgstr "" "rozmiar i-wÄ™zÅ‚a urzÄ…dzenia blokowego % != 0 (% bloków)\n" #: .././repair/dinode.c:1519 #, c-format msgid "size of socket inode % != 0 (% blocks)\n" msgstr "rozmiar i-wÄ™zÅ‚a gniazda % != 0 (% bloków)\n" #: .././repair/dinode.c:1524 #, c-format msgid "size of fifo inode % != 0 (% blocks)\n" msgstr "rozmiar i-wÄ™zÅ‚a potoku % != 0 (% bloków)\n" #: .././repair/dinode.c:1602 #, c-format msgid "root inode % has bad type 0x%x\n" msgstr "i-wÄ™zeÅ‚ główny % ma błędny typ 0x%x\n" #: .././repair/dinode.c:1606 msgid "resetting to directory\n" msgstr "przestawiono na katalog\n" #: .././repair/dinode.c:1610 msgid "would reset to directory\n" msgstr "zostaÅ‚by przestawiony na katalog\n" #: .././repair/dinode.c:1616 #, c-format msgid "user quota inode % has bad type 0x%x\n" msgstr "i-wÄ™zeÅ‚ limitu użytkownika % ma błędny typ 0x%x\n" #: .././repair/dinode.c:1625 #, c-format msgid "group quota inode % has bad type 0x%x\n" msgstr "i-wÄ™zeÅ‚ limitu grupy % ma błędny typ 0x%x\n" #: .././repair/dinode.c:1634 #, c-format msgid "project quota inode % has bad type 0x%x\n" msgstr "i-wÄ™zeÅ‚ limitu projektu % ma błędny typ 0x%x\n" #: .././repair/dinode.c:1644 #, c-format msgid "realtime summary inode % has bad type 0x%x, " msgstr "i-wÄ™zeÅ‚ opisu realtime % ma błędny typ 0x%x, " #: .././repair/dinode.c:1647 .././repair/dinode.c:1668 msgid "resetting to regular file\n" msgstr "przestawiono na zwykÅ‚y plik\n" #: .././repair/dinode.c:1651 .././repair/dinode.c:1672 msgid "would reset to regular file\n" msgstr "zostaÅ‚by przestawiony na zwykÅ‚y plik\n" #: .././repair/dinode.c:1656 #, c-format msgid "bad # of extents (%u) for realtime summary inode %\n" msgstr "błędna liczba ekstentów (%u) dla i-wÄ™zÅ‚a opisu realtime %\n" #: .././repair/dinode.c:1665 #, c-format msgid "realtime bitmap inode % has bad type 0x%x, " msgstr "i-wÄ™zeÅ‚ bitmapy realtime % ma błędny typ 0x%x, " #: .././repair/dinode.c:1677 #, c-format msgid "bad # of extents (%u) for realtime bitmap inode %\n" msgstr "błędna liczba ekstentów (%u) dla i-wÄ™zÅ‚a bitmapy realtime %\n" #: .././repair/dinode.c:1712 #, c-format msgid "" "mismatch between format (%d) and size (%) in directory ino " "%\n" msgstr "" "niezgodność miÄ™dzy formatem (%d) a rozmiarem (%) w i-węźle katalogu " "%\n" #: .././repair/dinode.c:1718 #, c-format msgid "directory inode % has bad size %\n" msgstr "i-wÄ™zeÅ‚ katalogu % ma błędny rozmiar %\n" #: .././repair/dinode.c:1726 #, c-format msgid "bad data fork in symlink %\n" msgstr "błędna gałąź danych w dowiÄ…zaniu symbolicznym %\n" #: .././repair/dinode.c:1747 #, c-format msgid "found inode % claiming to be a real-time file\n" msgstr "znaleziono i-wÄ™zeÅ‚ % twierdzÄ…cy, że należy do pliku realtime\n" #: .././repair/dinode.c:1756 #, c-format msgid "" "realtime bitmap inode % has bad size % (should be " "%)\n" msgstr "" "i-wÄ™zeÅ‚ bitmapy realtime % ma błędny rozmiar % (powinien być " "%)\n" #: .././repair/dinode.c:1767 #, c-format msgid "" "realtime summary inode % has bad size % (should be %d)\n" msgstr "" "i-wÄ™zeÅ‚ opisu realtime % ma błędny rozmiar % (powinien być " "%d)\n" #: .././repair/dinode.c:1795 #, c-format msgid "bad attr fork offset %d in dev inode %, should be %d\n" msgstr "" "błędny offset gałęzi atrybutów %d w i-węźle urzÄ…dzenia %, powinien " "być %d\n" #: .././repair/dinode.c:1807 #, c-format msgid "bad attr fork offset %d in inode %, max=%d\n" msgstr "błędny offset gałęzi atrybutów %d w i-węźle %, maksimum=%d\n" #: .././repair/dinode.c:1814 #, c-format msgid "unexpected inode format %d\n" msgstr "nieoczekiwany format i-wÄ™zÅ‚a %d\n" #: .././repair/dinode.c:1835 #, c-format msgid "correcting nblocks for inode %, was %llu - counted %\n" msgstr "" "poprawiono nblocks dla i-wÄ™zÅ‚a % - byÅ‚o %llu, naliczono %\n" #: .././repair/dinode.c:1842 #, c-format msgid "bad nblocks %llu for inode %, would reset to %\n" msgstr "" "błędne nblocks %llu dla i-wÄ™zÅ‚a %, zostaÅ‚oby przestawione na " "%\n" #: .././repair/dinode.c:1850 #, c-format msgid "too many data fork extents (%) in inode %\n" msgstr "zbyt dużo ekstentów gałęzi danych (%) w i-węźle %\n" #: .././repair/dinode.c:1857 #, c-format msgid "correcting nextents for inode %, was %d - counted %\n" msgstr "" "poprawiono nextents dla i-wÄ™zÅ‚a % - byÅ‚o %d, naliczono %\n" #: .././repair/dinode.c:1865 #, c-format msgid "bad nextents %d for inode %, would reset to %\n" msgstr "" "błędne nextents %d dla i-wÄ™zÅ‚a %, zostaÅ‚oby przestawione na " "%\n" #: .././repair/dinode.c:1873 #, c-format msgid "too many attr fork extents (%) in inode %\n" msgstr "zbyt dużo ekstentów gałęzi atrybutów (%) w i-węźle %\n" #: .././repair/dinode.c:1880 #, c-format msgid "correcting anextents for inode %, was %d - counted %\n" msgstr "" "poprawiono anextents dla i-wÄ™zÅ‚a % - byÅ‚o %d, naliczono %\n" #: .././repair/dinode.c:1887 #, c-format msgid "bad anextents %d for inode %, would reset to %\n" msgstr "" "błędne anextents %d dla i-wÄ™zÅ‚a %, zostaÅ‚oby przestawione na " "%\n" #: .././repair/dinode.c:1899 #, c-format msgid "nblocks (%) smaller than nextents for inode %\n" msgstr "nblocks (%) mniejsze niż nextents dla i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:1964 .././repair/dinode.c:2002 #, c-format msgid "unknown format %d, ino % (mode = %d)\n" msgstr "nieznany format %d, i-wÄ™zeÅ‚ % (tryb = %d)\n" #: .././repair/dinode.c:1969 #, c-format msgid "bad data fork in inode %\n" msgstr "błędna gałąź danych w i-węźle %\n" #: .././repair/dinode.c:2040 #, c-format msgid "bad attribute format %d in inode %, " msgstr "błędny format atrybutów %d w i-węźle %, " #: .././repair/dinode.c:2043 msgid "resetting value\n" msgstr "przestawiono wartość\n" #: .././repair/dinode.c:2047 msgid "would reset value\n" msgstr "wartość zostaÅ‚aby przestawiona\n" #: .././repair/dinode.c:2092 #, c-format msgid "bad attribute fork in inode %" msgstr "błędna gałąź atrybutów w i-węźle %" #: .././repair/dinode.c:2096 msgid ", clearing attr fork\n" msgstr ", wyczyszczono gałąź atrybutów\n" #: .././repair/dinode.c:2105 msgid ", would clear attr fork\n" msgstr ", gałąź atrybutów zostaÅ‚aby wyczyszczona\n" #: .././repair/dinode.c:2133 #, c-format msgid "illegal attribute fmt %d, ino %\n" msgstr "niedozwolony format atrybutów %d, i-wÄ™zeÅ‚ %\n" #: .././repair/dinode.c:2153 #, c-format msgid "problem with attribute contents in inode %\n" msgstr "problem z zawartoÅ›ciÄ… atrybutu w i-węźle %\n" #: .././repair/dinode.c:2161 msgid "would clear attr fork\n" msgstr "gałąź atrybutów zostaÅ‚aby wyczyszczona\n" #: .././repair/dinode.c:2194 #, c-format msgid "" "clearing obsolete nlink field in version 2 inode %, was %d, now 0\n" msgstr "" "wyczyszczono przestarzaÅ‚e pole nlink w i-węźle % w wersji 2 - byÅ‚o " "%d, jest 0\n" #: .././repair/dinode.c:2200 #, c-format msgid "" "would clear obsolete nlink field in version 2 inode %, currently %d\n" msgstr "" "przestarzaÅ‚e pole nlink w i-węźle % w wersji 2 zostaÅ‚oby " "wyczyszczone, aktualnie %d\n" #: .././repair/dinode.c:2279 #, c-format msgid "bad CRC for inode %%c" msgstr "błędne CRC dla i-wÄ™zÅ‚a %%c" #: .././repair/dinode.c:2283 msgid " will rewrite\n" msgstr " zostanie poprawione\n" #: .././repair/dinode.c:2286 msgid " would rewrite\n" msgstr " zostaÅ‚oby poprawione\n" #: .././repair/dinode.c:2293 #, c-format msgid "bad magic number 0x%x on inode %%c" msgstr "błędna liczba magiczna 0x%x w i-węźle %%c" #: .././repair/dinode.c:2298 msgid " resetting magic number\n" msgstr " przestawiono liczbÄ™ magicznÄ…\n" #: .././repair/dinode.c:2302 msgid " would reset magic number\n" msgstr " liczba magiczna zostaÅ‚aby przestawiona\n" #: .././repair/dinode.c:2309 #, c-format msgid "bad version number 0x%x on inode %%c" msgstr "błędny numer wersji 0x%x w i-węźle %%c" #: .././repair/dinode.c:2314 msgid " resetting version number\n" msgstr " przestawiono numer wersji\n" #: .././repair/dinode.c:2319 msgid " would reset version number\n" msgstr " numer wersji zostaÅ‚by przestawiony\n" #: .././repair/dinode.c:2332 #, c-format msgid "inode identifier %llu mismatch on inode %\n" msgstr "niezgodność identyfikatora i-wÄ™zÅ‚a %llu dla i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2343 #, c-format msgid "UUID mismatch on inode %\n" msgstr "niezgodność UUID-a dla i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2356 #, c-format msgid "bad (negative) size % on inode %\n" msgstr "błędny (ujemny) rozmiar % w i-węźle %\n" #: .././repair/dinode.c:2389 #, c-format msgid "imap claims a free inode % is in use, " msgstr "imap odwoÅ‚uje siÄ™ do wolnego bloku %, który jest w użyciu, " #: .././repair/dinode.c:2391 msgid "correcting imap and clearing inode\n" msgstr "poprawiono imap i wyczyszczono i-wÄ™zeÅ‚\n" #: .././repair/dinode.c:2395 msgid "would correct imap and clear inode\n" msgstr "poprawiono by imap i wyczyszczono by i-wÄ™zeÅ‚\n" #: .././repair/dinode.c:2412 #, c-format msgid "bad inode format in inode %\n" msgstr "błędny format i-wÄ™zÅ‚a w i-węźle %\n" #: .././repair/dinode.c:2428 #, c-format msgid "Bad flags set in inode %\n" msgstr "Błędne flagi ustawione w i-węźle %\n" #: .././repair/dinode.c:2439 #, c-format msgid "inode % has RT flag set but there is no RT device\n" msgstr "i-wÄ™zeÅ‚ % ma ustawionÄ… flagÄ™ RT, ale nie ma urzÄ…dzenia RT\n" #: .././repair/dinode.c:2451 #, c-format msgid "inode % not rt bitmap\n" msgstr "i-wÄ™zeÅ‚ % nie jest bitmapÄ… rt\n" #: .././repair/dinode.c:2465 #, c-format msgid "directory flags set on non-directory inode %\n" msgstr "" "flagi katalogu ustawione dla nie bÄ™dÄ…cego katalogiem i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2479 #, c-format msgid "file flags set on non-file inode %\n" msgstr "flagi pliku ustawione dla nie bÄ™dÄ…cego plikiem i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2488 msgid "fixing bad flags.\n" msgstr "poprawiono błędne flagi.\n" #: .././repair/dinode.c:2492 msgid "would fix bad flags.\n" msgstr "poprawionoby błędne flagi.\n" #: .././repair/dinode.c:2507 #, c-format msgid "Bad flags2 set in inode %\n" msgstr "Błędne flags2 ustawione w i-węźle %\n" #: .././repair/dinode.c:2518 #, c-format msgid "DAX flag set on special inode %\n" msgstr "flaga DAX ustawiona dla specjalnego i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2529 #, c-format msgid "" "inode % is marked reflinked but file system does not support " "reflink\n" msgstr "" "i-wÄ™zeÅ‚ % oznaczony jako dowiÄ…zany, ale system plików nie obsÅ‚uguje " "funkcji reflink\n" #: .././repair/dinode.c:2540 #, c-format msgid "reflink flag set on non-file inode %\n" msgstr "flaga reflink ustawiona dla nie bÄ™dÄ…cego plikiem i-wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2551 #, c-format msgid "Cannot have a reflinked realtime inode %\n" msgstr "Nie można mieć dowiÄ…zanego i-wÄ™zla realtime %\n" #: .././repair/dinode.c:2561 #, c-format msgid "" "inode % has CoW extent size hint but file system does not support " "reflink\n" msgstr "" "i-wÄ™zeÅ‚ % ma rozmiar ekstentu CoW, ale system plików nie obsÅ‚uguje " "funkcji reflink\n" #: .././repair/dinode.c:2572 #, c-format msgid "CoW extent size flag set on non-file, non-directory inode %\n" msgstr "" "rozmiar ekstentu CoW ostawiony dla nie bÄ™dÄ…cego plikiem ani katalogiem i-" "wÄ™zÅ‚a %\n" #: .././repair/dinode.c:2583 #, c-format msgid "Cannot have CoW extent size hint on a realtime inode %\n" msgstr "Nie mozna mieć rozmiaru ekstentu CoW dla i-wÄ™zÅ‚a realtime %\n" #: .././repair/dinode.c:2591 msgid "fixing bad flags2.\n" msgstr "poprawiono błędne flags2.\n" #: .././repair/dinode.c:2595 msgid "would fix bad flags2.\n" msgstr "poprawionoby błędne flags2.\n" #: .././repair/dinode.c:2646 #, c-format msgid "bad inode type %#o inode %\n" msgstr "błędny typ i-wÄ™zÅ‚a %#o w i-węźle %\n" #: .././repair/dinode.c:2670 #, c-format msgid "bad non-zero extent size %u for non-realtime/extsize inode %, " msgstr "" "błędny niezerowy rozmiar ekstentu %u dla extsize i-wÄ™zÅ‚a nie-realtime " "%, " #: .././repair/dinode.c:2673 .././repair/dinode.c:2696 msgid "resetting to zero\n" msgstr "przestawiono na zero\n" #: .././repair/dinode.c:2677 .././repair/dinode.c:2701 msgid "would reset to zero\n" msgstr "zostaÅ‚by przestawiony na zero\n" #: .././repair/dinode.c:2693 #, c-format msgid "" "Cannot have non-zero CoW extent size %u on non-cowextsize inode %, " msgstr "" "Nie można mieć niezerowego rozmiaru ekstentu CoW %u na i-węźle bez " "cowextsize %, " #: .././repair/dinode.c:2712 #, c-format msgid "Cannot have CoW extent size of zero on cowextsize inode %, " msgstr "" "Nie można mieć zerowego rozmiaru ekstentu CoW na i-węźle cowextsize " "%, " #: .././repair/dinode.c:2715 msgid "clearing cowextsize flag\n" msgstr "wyczyszczono flagÄ™ cowextsize\n" #: .././repair/dinode.c:2719 msgid "would clear cowextsize flag\n" msgstr "flaga cowextsize zostaÅ‚aby wyczyszczona\n" #: .././repair/dinode.c:2778 #, c-format msgid "problem with directory contents in inode %\n" msgstr "problem z zawartoÅ›ciÄ… katalogu w i-węźle %\n" #: .././repair/dinode.c:2786 #, c-format msgid "problem with symbolic link in inode %\n" msgstr "problem z dowiÄ…zaniem symbolicznym w i-węźle %\n" #: .././repair/dinode.c:2881 #, c-format msgid "processing inode %d/%d\n" msgstr "analiza i-wÄ™zÅ‚a %d/%d\n" #: .././repair/dir2.c:50 #, c-format msgid "malloc failed (%zu bytes) dir2_add_badlist:ino %\n" msgstr "" "malloc nie powiodÅ‚o siÄ™ (%zu bajtów) w dir2_add_badlist:ino %\n" #: .././repair/dir2.c:93 msgid "couldn't malloc dir2 shortform copy\n" msgstr "nie udaÅ‚o siÄ™ przydzielić krótkiej kopii dir2\n" #: .././repair/dir2.c:229 msgid "current" msgstr "bieżącego i-wÄ™zÅ‚a" #: .././repair/dir2.c:232 .././repair/dir2.c:693 msgid "invalid" msgstr "nieprawidÅ‚owego i-wÄ™zÅ‚a" #: .././repair/dir2.c:235 .././repair/dir2.c:695 msgid "realtime bitmap" msgstr "i-wÄ™zÅ‚a bitmapy realtime" #: .././repair/dir2.c:238 .././repair/dir2.c:697 msgid "realtime summary" msgstr "i-wÄ™zÅ‚a opisu realtime" #: .././repair/dir2.c:241 .././repair/dir2.c:699 msgid "user quota" msgstr "i-wÄ™zÅ‚a limitów użytkownika" #: .././repair/dir2.c:244 .././repair/dir2.c:701 msgid "group quota" msgstr "i-wÄ™zÅ‚a limitów grupy" #: .././repair/dir2.c:247 .././repair/dir2.c:703 msgid "project quota" msgstr "i-wÄ™zÅ‚a limitów projektu" #: .././repair/dir2.c:265 .././repair/dir2.c:733 msgid "free" msgstr "free" #: .././repair/dir2.c:282 .././repair/dir2.c:713 msgid "non-existent" msgstr "nie istniejÄ…cego i-wÄ™zÅ‚a" #: .././repair/dir2.c:287 #, c-format msgid "" "entry \"%*.*s\" in shortform directory % references %s inode " "%\n" msgstr "" "wpis \"%*.*s\" w krótkim katalogu % odwoÅ‚uje siÄ™ do %s %\n" #: .././repair/dir2.c:293 msgid "is zero length" msgstr "jest zerowej dÅ‚ugoÅ›ci" #: .././repair/dir2.c:298 msgid "extends past end of dir" msgstr "wykracza poza koniec katalogu" #: .././repair/dir2.c:304 #, c-format msgid "entry #%d %s in shortform dir %" msgstr "wpis #%d %s w krótkim katalogu %" #: .././repair/dir2.c:307 #, c-format msgid ", junking %d entries\n" msgstr ", wyrzucono %d wpisów\n" #: .././repair/dir2.c:310 #, c-format msgid ", would junk %d entries\n" msgstr ", %d wpisów zostaÅ‚oby wyrzucone\n" #: .././repair/dir2.c:330 #, c-format msgid "entry contains illegal character in shortform dir %\n" msgstr "wpis zawiera niedozwolony znak w krótkim katalogu %\n" #: .././repair/dir2.c:337 #, c-format msgid "entry contains offset out of order in shortform dir %\n" msgstr "wpis zawiera uszkodzony offset w krótkim katalogu %\n" #: .././repair/dir2.c:394 #, c-format msgid "junking entry \"%s\" in directory inode %\n" msgstr "wyrzucono wpis \"%s\" w i-węźle katalogu %\n" #: .././repair/dir2.c:398 #, c-format msgid "would have junked entry \"%s\" in directory inode %\n" msgstr "wpis \"%s\" w i-węźle katalogu % zostaÅ‚by wyrzucony\n" #: .././repair/dir2.c:423 #, c-format msgid "would have corrected entry count in directory % from %d to %d\n" msgstr "liczba wpisów w katalogu % zostaÅ‚aby poprawiona z %d na %d\n" #: .././repair/dir2.c:427 #, c-format msgid "corrected entry count in directory %, was %d, now %d\n" msgstr "poprawiono liczbÄ™ wpisów w katalogu % - byÅ‚o %d, jest %d\n" #: .././repair/dir2.c:438 #, c-format msgid "would have corrected i8 count in directory % from %d to %d\n" msgstr "liczba i8 zostaÅ‚aby poprawiona w katalogu % z %d na %d\n" #: .././repair/dir2.c:442 #, c-format msgid "corrected i8 count in directory %, was %d, now %d\n" msgstr "poprawiono liczbÄ™ i8 w katalogu % - byÅ‚o %d, jest %d\n" #: .././repair/dir2.c:456 #, c-format msgid "" "would have corrected directory % size from % to %\n" msgstr "" "rozmiar katalogu % zostaÅ‚by poprawiony z % na %\n" #: .././repair/dir2.c:461 #, c-format msgid "corrected directory % size, was %, now %\n" msgstr "" "poprawiono rozmiar katalogu % - byÅ‚o %, jest %\n" #: .././repair/dir2.c:473 #, c-format msgid "directory % offsets too high\n" msgstr "offsety zbyt duże w katalogu %\n" #: .././repair/dir2.c:479 #, c-format msgid "would have corrected entry offsets in directory %\n" msgstr "offsety wpisów w katalogu % zostaÅ‚yby poprawione\n" #: .././repair/dir2.c:483 #, c-format msgid "corrected entry offsets in directory %\n" msgstr "poprawiono offsety wpisów w katalogu %\n" #: .././repair/dir2.c:502 #, c-format msgid "bogus .. inode number (%) in directory inode %, " msgstr "błędny numer i-wÄ™zÅ‚a .. (%) w i-węźle katalogu %, " #: .././repair/dir2.c:506 .././repair/dir2.c:541 msgid "clearing inode number\n" msgstr "wyczyszczono numer i-wÄ™zÅ‚a\n" #: .././repair/dir2.c:512 .././repair/dir2.c:547 msgid "would clear inode number\n" msgstr "numer i-wÄ™zÅ‚a zostaÅ‚by wyczyszczony\n" #: .././repair/dir2.c:520 #, c-format msgid "" "corrected root directory % .. entry, was %, now %\n" msgstr "" "poprawiono wpis .. głównego katalogu % - byÅ‚o %, jest " "%\n" #: .././repair/dir2.c:528 #, c-format msgid "" "would have corrected root directory % .. entry from % to " "%\n" msgstr "" "wpis .. głównego katalogu % zostaÅ‚by poprawiony z % na " "%\n" #: .././repair/dir2.c:538 #, c-format msgid "bad .. entry in directory inode %, points to self, " msgstr "błędny wpis .. w i-węźle katalogu %, wskazuje na siebie, " #: .././repair/dir2.c:651 #, c-format msgid "corrupt block %u in directory inode %\n" msgstr "uszkodzony blok %u w i-węźle katalogu %\n" #: .././repair/dir2.c:654 msgid "\twill junk block\n" msgstr "\tblok zostanie wyrzucony\n" #: .././repair/dir2.c:656 msgid "\twould junk block\n" msgstr "\tblok zostaÅ‚by wyrzucony\n" #: .././repair/dir2.c:742 #, c-format msgid "" "entry \"%*.*s\" at block %d offset % in directory inode % " "references %s inode %\n" msgstr "" "wpis \"%*.*s\" w bloku %d offsecie % w i-węźle katalogu % " "odwoÅ‚uje siÄ™ do %s %\n" #: .././repair/dir2.c:765 #, c-format msgid "" "entry at block %u offset % in directory inode %has 0 " "namelength\n" msgstr "" "wpis w bloku %u offsecie % w i-węźle katalogu % ma zerowÄ… " "dÅ‚ugość nazwy\n" #: .././repair/dir2.c:778 #, c-format msgid "\tclearing inode number in entry at offset %...\n" msgstr "\twyczyszczono numer i-wÄ™zÅ‚a we wpisie o offsecie %...\n" #: .././repair/dir2.c:784 #, c-format msgid "\twould clear inode number in entry at offset %...\n" msgstr "" "\tnumer i-wÄ™zÅ‚a we wpisie o offsecie % zostaÅ‚by wyczyszczony...\n" #: .././repair/dir2.c:797 #, c-format msgid "" "entry at block %u offset % in directory inode % has illegal " "name \"%*.*s\": " msgstr "" "wpis w bloku %u offsecie % w i-węźle katalogu % ma " "niedozwolonÄ… nazwÄ™ \"%*.*s\": " #: .././repair/dir2.c:828 #, c-format msgid "bad .. entry in directory inode %, points to self: " msgstr "błędny wpis .. w i-węźle katalogu %, wskazuje na siebie: " #: .././repair/dir2.c:839 #, c-format msgid "bad .. entry in root directory inode %, was %: " msgstr "błędny wpis w i-węźle głównego katalogu %, byÅ‚o %: " #: .././repair/dir2.c:842 .././repair/dir2.c:875 .././repair/phase2.c:222 #: .././repair/phase2.c:231 .././repair/phase2.c:240 msgid "correcting\n" msgstr "poprawiono\n" #: .././repair/dir2.c:846 .././repair/dir2.c:879 .././repair/phase2.c:224 #: .././repair/phase2.c:233 .././repair/phase2.c:242 msgid "would correct\n" msgstr "zostaÅ‚by poprawiony\n" #: .././repair/dir2.c:859 #, c-format msgid "multiple .. entries in directory inode %: " msgstr "wiele wpisów .. w i-węźle katalogu %: " #: .././repair/dir2.c:872 #, c-format msgid "bad . entry in directory inode %, was %: " msgstr "błędny wpis . w i-węźle katalogu %, byÅ‚o %: " #: .././repair/dir2.c:884 #, c-format msgid "multiple . entries in directory inode %: " msgstr "wiele wpisów . w i-węźle katalogu %: " #: .././repair/dir2.c:894 #, c-format msgid "entry \"%*.*s\" in directory inode % points to self: " msgstr "wpis \"%*.*s\" w i-węźle katalogu % wskazuje na siebie: " #: .././repair/dir2.c:905 msgid "clearing entry\n" msgstr "wyczyszczono wpis\n" #: .././repair/dir2.c:907 msgid "would clear entry\n" msgstr "wpis zostaÅ‚by wyczyszczony\n" #: .././repair/dir2.c:920 #, c-format msgid "bad bestfree table in block %u in directory inode %: " msgstr "błędna tablica bestfree w bloku %u w i-węźle katalogu %: " #: .././repair/dir2.c:923 msgid "repairing table\n" msgstr "naprawiono tablicÄ™\n" #: .././repair/dir2.c:928 msgid "would repair table\n" msgstr "tablica zostaÅ‚aby naprawiona\n" #: .././repair/dir2.c:968 #, c-format msgid "block %u for directory inode % is missing\n" msgstr "brak bloku %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:977 #, c-format msgid "can't read block %u for directory inode %\n" msgstr "nie można odczytać bloku %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:988 #, c-format msgid "" "bad directory block magic # %#x in block %u for directory inode %\n" msgstr "" "błędna liczba magiczna bloku katalogu %#x w bloku %u dla i-wÄ™zÅ‚a katalogu " "%\n" #: .././repair/dir2.c:1040 #, c-format msgid "bad entry count in block %u of directory inode %\n" msgstr "błędna liczba wpisów w bloku %u i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1048 #, c-format msgid "bad hash ordering in block %u of directory inode %\n" msgstr "błędna kolejność hasza w bloku %u i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1056 #, c-format msgid "bad stale count in block %u of directory inode %\n" msgstr "błędna liczba stale %u i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1105 #, c-format msgid "can't map block %u for directory inode %\n" msgstr "nie można odwzorować bloku %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1115 #, c-format msgid "can't read file block %u for directory inode %\n" msgstr "nie można odczytać bloku pliku %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1127 #, c-format msgid "bad directory leaf magic # %#x for directory inode % block %u\n" msgstr "" "błędna liczba magiczna liÅ›cia katalogu %#x dla i-wÄ™zÅ‚a katalogu % " "bloku %u\n" #: .././repair/dir2.c:1155 #, c-format msgid "bad sibling back pointer for block %u in directory inode %\n" msgstr "błędny wskaźnik wstecz dla bloku %u w i-węźle katalogu %\n" #: .././repair/dir2.c:1186 #, c-format msgid "bad hash path in directory %\n" msgstr "błędna Å›cieżka hasza w katalogu %\n" #: .././repair/dir2.c:1296 #, c-format msgid "block % for directory inode % is missing\n" msgstr "brak bloku % dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1305 #, c-format msgid "can't read block % for directory inode %\n" msgstr "nie można odczytać bloku % dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/dir2.c:1313 #, c-format msgid "" "bad directory block magic # %#x in block % for directory inode " "%\n" msgstr "" "błędna liczba magiczna bloku katalogu %#x w bloku % dla i-wÄ™zÅ‚a " "katalogu %\n" #: .././repair/dir2.c:1394 #, c-format msgid "bad size/format for directory %\n" msgstr "błędny rozmiar/format dla katalogu %\n" #: .././repair/dir2.c:1401 #, c-format msgid "no . entry for directory %\n" msgstr "brak wpisu . dla katalogu %\n" #: .././repair/dir2.c:1411 #, c-format msgid "no .. entry for directory %\n" msgstr "brak wpisu .. dla katalogu %\n" #: .././repair/dir2.c:1413 #, c-format msgid "no .. entry for root directory %\n" msgstr "brak wpisu .. dla katalogu głównego %\n" #: .././repair/incore.c:230 #, c-format msgid "couldn't allocate realtime block map, size = %\n" msgstr "nie udaÅ‚o siÄ™ przydzielić mapy bloków realtime, size = %\n" #: .././repair/incore.c:295 msgid "couldn't allocate block map btree roots\n" msgstr "nie udaÅ‚o siÄ™ przydzielić korzeni b-drzewa mapy bloków\n" #: .././repair/incore.c:299 msgid "couldn't allocate block map locks\n" msgstr "nie udaÅ‚o siÄ™ przydzielić blokad mapy bloków\n" #: .././repair/incore_ext.c:135 .././repair/incore_ext.c:562 msgid "couldn't allocate new extent descriptor.\n" msgstr "nie udaÅ‚o siÄ™ przydzielić nowego deskryptora ekstentu.\n" #: .././repair/incore_ext.c:232 msgid "duplicate bno extent range\n" msgstr "powtórzony przedziaÅ‚ ekstentów bno\n" #: .././repair/incore_ext.c:369 msgid ": duplicate bno extent range\n" msgstr ": powtórzony przedziaÅ‚ ekstentów bno\n" #: .././repair/incore_ext.c:644 .././repair/incore_ext.c:699 msgid "duplicate extent range\n" msgstr "powtórzony przedziaÅ‚ ekstentów\n" #: .././repair/incore_ext.c:752 .././repair/incore_ext.c:756 msgid "couldn't malloc dup extent tree descriptor table\n" msgstr "" "nie udaÅ‚o siÄ™ przydzielić tablicy deskryptorów drzewa powtórzonych " "ekstentów\n" #: .././repair/incore_ext.c:761 msgid "couldn't malloc free by-bno extent tree descriptor table\n" msgstr "" "nie udaÅ‚o siÄ™ przydzielić tablicy deskryptorów drzewa wolnych ekstentów wg " "bno\n" #: .././repair/incore_ext.c:766 msgid "couldn't malloc free by-bcnt extent tree descriptor table\n" msgstr "" "nie udaÅ‚o siÄ™ przydzielić tablicy deskryptorów drzewa wolnych ekstentów wg " "bcnt\n" #: .././repair/incore_ext.c:772 msgid "couldn't malloc bno extent tree descriptor\n" msgstr "nie udaÅ‚o siÄ™ przydzielić deskryptora drzewa ekstentów wg bno\n" #: .././repair/incore_ext.c:776 msgid "couldn't malloc bcnt extent tree descriptor\n" msgstr "nie udaÅ‚o siÄ™ przydzielić deskryptora drzewa ekstentów wg bcnt\n" #: .././repair/incore_ext.c:787 msgid "couldn't malloc dup rt extent tree descriptor\n" msgstr "" "nie udaÅ‚o siÄ™ przydzielić deskryptora drzewa powtórzonych ekstentów rt\n" #: .././repair/incore_ino.c:47 msgid "could not allocate nlink array\n" msgstr "Nie udaÅ‚o siÄ™ przydzielić tablicy nlink\n" #: .././repair/incore_ino.c:225 msgid "could not allocate ftypes array\n" msgstr "nie udaÅ‚o siÄ™ przydzielić tablicy ftypes\n" #: .././repair/incore_ino.c:251 msgid "inode map malloc failed\n" msgstr "przydzielenie mapy i-wÄ™złów nie powiodÅ‚o siÄ™\n" #: .././repair/incore_ino.c:367 msgid "add_aginode_uncertain - duplicate inode range\n" msgstr "add_aginode_uncertain - powtórzony przedziaÅ‚ i-wÄ™złów\n" #: .././repair/incore_ino.c:462 msgid "add_inode - duplicate inode range\n" msgstr "add_inode - powtórzony przedziaÅ‚ i-wÄ™złów\n" #: .././repair/incore_ino.c:556 #, c-format msgid "good inode list is --\n" msgstr "lista dobrych i-wÄ™złów to:\n" #: .././repair/incore_ino.c:559 #, c-format msgid "uncertain inode list is --\n" msgstr "lista niepewnych i-wÄ™złów to:\n" #: .././repair/incore_ino.c:564 #, c-format msgid "agno %d -- no inodes\n" msgstr "agno %d - brak i-wÄ™złów\n" #: .././repair/incore_ino.c:568 #, c-format msgid "agno %d\n" msgstr "agno %d\n" #: .././repair/incore_ino.c:572 #, c-format msgid "\tptr = %lx, start = 0x%x, free = 0x%llx, confirmed = 0x%llx\n" msgstr "\tptr = %lx, start = 0x%x, wolne = 0x%llx, potwierdzone = 0x%llx\n" #: .././repair/incore_ino.c:623 msgid "couldn't malloc parent list table\n" msgstr "nie udaÅ‚o siÄ™ przydzielić tablicy listy rodziców\n" #: .././repair/incore_ino.c:634 .././repair/incore_ino.c:680 msgid "couldn't memalign pentries table\n" msgstr "nie udaÅ‚o siÄ™ memalign na tablicy pentries\n" #: .././repair/incore_ino.c:738 msgid "could not malloc inode extra data\n" msgstr "nie udaÅ‚o siÄ™ przydzielić dodatkowych danych i-wÄ™zÅ‚a\n" #: .././repair/incore_ino.c:804 msgid "couldn't malloc inode tree descriptor table\n" msgstr "nie udaÅ‚o siÄ™ przydzielić tablicy deskryptorów drzewa i-wÄ™złów\n" #: .././repair/incore_ino.c:808 msgid "couldn't malloc uncertain ino tree descriptor table\n" msgstr "" "nie udaÅ‚o siÄ™ przydzielić tablicy deskryptorów drzewa i-wÄ™złów niepewnych\n" #: .././repair/incore_ino.c:813 msgid "couldn't malloc inode tree descriptor\n" msgstr "nie udaÅ‚o siÄ™ przydzielić deskryptora drzewa i-wÄ™złów\n" #: .././repair/incore_ino.c:817 msgid "couldn't malloc uncertain ino tree descriptor\n" msgstr "nie udaÅ‚o siÄ™ przydzielić deskryptora drzewa i-wÄ™złów niepewnych\n" #: .././repair/incore_ino.c:825 msgid "couldn't malloc uncertain inode cache area\n" msgstr "" "nie udaÅ‚o siÄ™ przydzielić obszaru pamiÄ™ci podrÄ™cznej i-wÄ™złów niepewnych\n" #: .././repair/init.c:46 #, c-format msgid "getrlimit(RLIMIT_FSIZE) failed!\n" msgstr "getrlimit(RLIMIT_FSIZE) nie powiodÅ‚o siÄ™!\n" #: .././repair/init.c:54 #, c-format msgid "setrlimit failed - current: %lld, max: %lld\n" msgstr "setrlimit nie powiodÅ‚o siÄ™ - bieżący: %lld, max: %lld\n" #: .././repair/init.c:107 #, c-format msgid "" "Unmount or use the dangerous (-d) option to repair a read-only mounted " "filesystem\n" msgstr "" "Aby naprawić system plików zamontowany do odczytu, trzeba go odmontować lub " "użyć opcji niebezpiecznej (-d).\n" #: .././repair/init.c:109 msgid "couldn't initialize XFS library\n" msgstr "nie udaÅ‚o siÄ™ zainicjować biblioteki XFS\n" #: .././repair/phase1.c:28 msgid "Sorry, could not find valid secondary superblock\n" msgstr "Niestety nie znaleziono poprawnego zapasowego superbloku\n" #: .././repair/phase1.c:29 msgid "Exiting now.\n" msgstr "ZakoÅ„czono.\n" #: .././repair/phase1.c:40 #, c-format msgid "could not allocate ag header buffer (%d bytes)\n" msgstr "nie udaÅ‚o siÄ™ przydzielić bufora nagłówka ag (%d bajtów)\n" #: .././repair/phase1.c:58 msgid "Phase 1 - find and verify superblock...\n" msgstr "Faza 1 - szukanie i sprawdzanie superbloku...\n" #: .././repair/phase1.c:75 msgid "error reading primary superblock\n" msgstr "błąd podczas odczytu głównego superbloku\n" #: .././repair/phase1.c:81 #, c-format msgid "bad primary superblock - %s !!!\n" msgstr "błędny główny superblok - %s!!!\n" #: .././repair/phase1.c:88 #, c-format msgid "couldn't verify primary superblock - %s !!!\n" msgstr "nie udaÅ‚o siÄ™ sprawdzić głównego superbloku - %s!!!\n" #: .././repair/phase1.c:106 msgid "superblock has a features2 mismatch, correcting\n" msgstr "superblok ma niepasujÄ…ce features2, poprawianie\n" #: .././repair/phase1.c:123 #, c-format msgid "Enabling lazy-counters\n" msgstr "Włączanie leniwych liczników\n" #: .././repair/phase1.c:127 #, c-format msgid "Cannot disable lazy-counters on V5 fs\n" msgstr "Nie można wyłączyć leniwych liczników w systemie plików V5\n" #: .././repair/phase1.c:132 #, c-format msgid "Disabling lazy-counters\n" msgstr "Wyłączanie leniwych liczników\n" #: .././repair/phase1.c:135 #, c-format msgid "Lazy-counters are already %s\n" msgstr "Leniwe liczniki już sÄ… %s\n" #: .././repair/phase1.c:136 msgid "enabled" msgstr "włączone" #: .././repair/phase1.c:136 msgid "disabled" msgstr "wyłączone" #: .././repair/phase1.c:143 msgid "resetting shared_vn to zero\n" msgstr "przestawianie shared_vn na zero\n" #: .././repair/phase1.c:150 msgid "writing modified primary superblock\n" msgstr "zapisano zmodyfikowany główny superblok\n" #: .././repair/phase1.c:153 msgid "would write modified primary superblock\n" msgstr "zmodyfikowany główny superblok zostaÅ‚by zapisany\n" #: .././repair/phase2.c:79 #, c-format msgid "zero_log: cannot find log head/tail (xlog_find_tail=%d)\n" msgstr "zero_log: nie znaleziono poczÄ…tku/koÅ„ca logu (xlog_find_tail=%d)\n" #: .././repair/phase2.c:83 msgid "" "ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n" "filesystem to replay the log or use the -L option to destroy the log and\n" "attempt a repair.\n" msgstr "" "BÅÄ„D: nie można wykryć poczÄ…tku i/lub koÅ„ca logu. ProszÄ™ spróbować " "zamontować\n" "system plików, aby odtworzyć log, albo użyć opcji -L, aby zniszczyć log\n" "i spróbować naprawić.\n" #: .././repair/phase2.c:90 #, c-format msgid "zero_log: head block % tail block %\n" msgstr "zero_log: blok poczÄ…tku % blok koÅ„ca %\n" #: .././repair/phase2.c:96 msgid "" "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "destroyed because the -L option was used.\n" msgstr "" "UWAGA: system plików zawiera wartoÅ›ciowe zmiany metadanych w logu, który " "jest\n" "niszczony, ponieważ użyto opcji -L.\n" #: .././repair/phase2.c:100 msgid "" "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "ignored because the -n option was used. Expect spurious inconsistencies\n" "which may be resolved by first mounting the filesystem to replay the log.\n" msgstr "" "UWAGA: system plików zawiera wartoÅ›ciowe zmiany metadanych w logu, który " "jest\n" "ignorowany, ponieważ użyto opcji -n. Należy oczekiwać faÅ‚szywych " "niespójnoÅ›ci,\n" "które można rozwiÄ…zać najpierw montujÄ…c system plików w celu odtworzenia " "logu.\n" #: .././repair/phase2.c:105 msgid "" "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running xfs_repair. If you are unable to mount the filesystem, then use\n" "the -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n" msgstr "" "BÅÄ„D: system plików zawiera wartoÅ›ciowe zmiany metadanych w logu, który\n" "musi być odtworzony. Należy zamontować system plików, aby odtworzyć log,\n" "a nastÄ™pnie odmontować go przed ponownym uruchomieniem xfs_repair. JeÅ›li\n" "systemu plików nie da siÄ™ zamontować, można użyć opcji -L, aby zniszczyć\n" "log i spróbować naprawić system plików.\n" "Należy zauważyć, że zniszczenie logu może spowodować uszkodzenia danych -\n" "proszÄ™ najpierw spróbować zamontować system plików.\n" #: .././repair/phase2.c:133 msgid "failed to clear log" msgstr "nie udaÅ‚o siÄ™ wyczyÅ›cić logu" #: .././repair/phase2.c:167 msgid "" "This filesystem has an external log. Specify log device with the -l " "option.\n" msgstr "" "Ten system plików ma zewnÄ™trzny log. Należy podać urzÄ…dzenie logu przy " "użyciu opcji -l.\n" #: .././repair/phase2.c:170 #, c-format msgid "Phase 2 - using external log on %s\n" msgstr "Faza 2 - użycie zewnÄ™trznego logu na %s\n" #: .././repair/phase2.c:172 msgid "Phase 2 - using internal log\n" msgstr "Faza 2 - użycie wewnÄ™trznego logu\n" #: .././repair/phase2.c:175 msgid " - zero log...\n" msgstr " - zerowanie logu...\n" #: .././repair/phase2.c:178 msgid " - scan filesystem freespace and inode maps...\n" msgstr "" " - przeszukiwanie wolnego miejsca i map i-wÄ™złów w systemie " "plików...\n" #: .././repair/phase2.c:194 msgid "root inode chunk not found\n" msgstr "nie znaleziono danych głównego i-wÄ™zÅ‚a\n" #: .././repair/phase2.c:213 msgid " - found root inode chunk\n" msgstr " - znaleziono dane głównego i-wÄ™zÅ‚a\n" #: .././repair/phase2.c:219 msgid "root inode marked free, " msgstr "główny i-wÄ™zeÅ‚ oznaczony jako wolny, " #: .././repair/phase2.c:228 msgid "realtime bitmap inode marked free, " msgstr "i-wÄ™zeÅ‚ bitmapy realtime oznaczony jako wolny, " #: .././repair/phase2.c:237 msgid "realtime summary inode marked free, " msgstr "i-wÄ™zeÅ‚ opisu realtime oznaczony jako wolny, " #: .././repair/phase3.c:47 #, c-format msgid "cannot read agi block % for ag %u\n" msgstr "nie można odczytać bloku agi % dla ag %u\n" #: .././repair/phase3.c:78 .././repair/phase4.c:142 .././repair/phase5.c:2217 #: .././repair/phase6.c:3139 #, c-format msgid " - agno = %d\n" msgstr " - agno = %d\n" #: .././repair/phase3.c:119 msgid "Phase 3 - for each AG...\n" msgstr "Faza 3 - dla każdej AG...\n" #: .././repair/phase3.c:121 msgid " - scan and clear agi unlinked lists...\n" msgstr " - przeszukiwanie i czyszczenie odłączonych list agi...\n" #: .././repair/phase3.c:123 msgid " - scan (but don't clear) agi unlinked lists...\n" msgstr "" " - przeszukiwanie (ale nie czyszczenie) odłączonych list agi...\n" #: .././repair/phase3.c:143 msgid " - process known inodes and perform inode discovery...\n" msgstr " - przetwarzanie znanych i-wÄ™złów i rozpoznawanie i-wÄ™złów...\n" #: .././repair/phase3.c:154 msgid " - process newly discovered inodes...\n" msgstr " - przetwarzanie nowo rozpoznanych i-wÄ™złów...\n" #: .././repair/phase3.c:159 msgid "no memory for uncertain inode counts\n" msgstr "brak pamiÄ™ci na liczniki niepewnych i-wÄ™złów\n" #: .././repair/phase4.c:165 #, c-format msgid "" "unable to finish adding attr/data fork reverse-mapping data for AG %u.\n" msgstr "" "nie udaÅ‚o siÄ™ ukoÅ„czyć dodawania danych odwrotnego odwzorowania gałęzi " "atrybutów/danych dla AG %u.\n" #: .././repair/phase4.c:181 #, c-format msgid "unable to add AG %u metadata reverse-mapping data.\n" msgstr "nie udaÅ‚o siÄ™ dodać danych odwrotnego odwzorowania metadanych AG %u.\n" #: .././repair/phase4.c:186 #, c-format msgid "unable to merge AG %u metadata reverse-mapping data.\n" msgstr "" "nie udaÅ‚o siÄ™ dołączyć danych odwrotnego odwzorowania metadanych AG %u.\n" #: .././repair/phase4.c:191 #, c-format msgid "%s while checking reverse-mappings" msgstr "%s podczas sprawdzania odwrotnych odwzorowaÅ„" #: .././repair/phase4.c:206 #, c-format msgid "%s while computing reference count records.\n" msgstr "%s podczas przeliczania rekordów licznika odwoÅ‚aÅ„.\n" #: .././repair/phase4.c:221 #, c-format msgid "%s while fixing inode reflink flags.\n" msgstr "%s podczas poprawiania flag odwoÅ‚aÅ„ i-wÄ™złów.\n" #: .././repair/phase4.c:236 #, c-format msgid "%s while checking reference counts" msgstr "%s podczas sprawdzania liczników odwoÅ‚aÅ„" #: .././repair/phase4.c:290 msgid "Phase 4 - check for duplicate blocks...\n" msgstr "Faza 4 - sprawdzanie powtórzonych bloków...\n" #: .././repair/phase4.c:291 msgid " - setting up duplicate extent list...\n" msgstr " - tworzenie listy powtórzonych ekstentów...\n" #: .././repair/phase4.c:305 msgid "root inode would be lost\n" msgstr "główny i-wÄ™zeÅ‚ zostaÅ‚by utracony\n" #: .././repair/phase4.c:307 msgid "root inode lost\n" msgstr "główny i-wÄ™zeÅ‚ utracony\n" #: .././repair/phase4.c:324 #, c-format msgid "unknown block state, ag %d, block %d\n" msgstr "nieznany stan bloku, ag %d, blok %d\n" #: .././repair/phase4.c:357 #, c-format msgid "unknown rt extent state, extent %\n" msgstr "nieznany stan ekstentu rt, ekstent %\n" #: .././repair/phase4.c:406 msgid " - check for inodes claiming duplicate blocks...\n" msgstr "" " - szukanie i-wÄ™złów odwoÅ‚ujÄ…cych siÄ™ do powtórzonych bloków...\n" #: .././repair/phase5.c:223 msgid "could not set up btree block array\n" msgstr "nie udaÅ‚o siÄ™ utworzyć tablicy bloków b-drzewa\n" #: .././repair/phase5.c:244 msgid "error - not enough free space in filesystem\n" msgstr "błąd - za maÅ‚o wolnego miejsca w systemie plików\n" #: .././repair/phase5.c:259 #, c-format msgid "could not set up btree rmaps: %s\n" msgstr "nie udaÅ‚o siÄ™ ustanowić rmap b-drzewa: %s\n" #: .././repair/phase5.c:475 #, c-format msgid "can't rebuild fs trees -- not enough free space on ag %u\n" msgstr "" "nie można przebudować drzew systemu plików - za maÅ‚o wolnego miejsca w ag " "%u\n" #: .././repair/phase5.c:498 #, c-format msgid "ag %u - not enough free space to build freespace btrees\n" msgstr "" "ag %u - za maÅ‚o wolnego miejsca na przebudowanie b-drzew wolnego miejsca\n" #: .././repair/phase5.c:533 #, c-format msgid "not enough free blocks left to describe all free blocks in AG %u\n" msgstr "za maÅ‚o wolnych bloków na opisanie wszystkich wolnych bloków w AG %u\n" #: .././repair/phase5.c:1584 msgid "Insufficient memory to construct reverse-map cursor." msgstr "Za maÅ‚o pamiÄ™ci, aby utworzyć kursor odwzorowania odwrotnego." #: .././repair/phase5.c:1887 msgid "Insufficient memory to construct refcount cursor." msgstr "Za maÅ‚o pamiÄ™ci, aby utworzyć kursor zliczania odwoÅ‚aÅ„." #: .././repair/phase5.c:2097 .././repair/phase5.c:2105 msgid "Insufficient memory saving lost blocks.\n" msgstr "Za maÅ‚o pamiÄ™ci podczas zapisu utraconych bloków.\n" #: .././repair/phase5.c:2160 .././repair/xfs_repair.c:1052 msgid "couldn't get superblock\n" msgstr "nie udaÅ‚o siÄ™ pobrać superbloku\n" #: .././repair/phase5.c:2240 #, c-format msgid "unable to rebuild AG %u. Not enough free space in on-disk AG.\n" msgstr "" "nie udaÅ‚o siÄ™ przebudować AG %u. Za maÅ‚o wolnego miejsca w AG na dysku.\n" #: .././repair/phase5.c:2292 #, c-format msgid "unable to rebuild AG %u. No free space.\n" msgstr "nie udaÅ‚o siÄ™ przebudować AG %u. Brak wolnego miejsca.\n" #: .././repair/phase5.c:2413 #, c-format msgid "unable to add AG %u reverse-mapping data to btree.\n" msgstr "" "nie udaÅ‚o siÄ™ dodać danych odwrotnego odwzorowania AG %u do b-drzewa.\n" #: .././repair/phase5.c:2473 msgid "Phase 5 - rebuild AG headers and trees...\n" msgstr "Faza 5 - przebudowywanie nagłówków i drzew AG...\n" #: .././repair/phase5.c:2502 msgid "cannot alloc sb_icount_ag buffers\n" msgstr "nie można przydzielić buforów sb_icount_ag\n" #: .././repair/phase5.c:2506 msgid "cannot alloc sb_ifree_ag buffers\n" msgstr "nie można przydzielić buforów sb_ifree_ag\n" #: .././repair/phase5.c:2510 msgid "cannot alloc sb_fdblocks_ag buffers\n" msgstr "nie można przydzielić buforów sb_fdblocks_ag\n" #: .././repair/phase5.c:2514 msgid "cannot alloc lost block slab\n" msgstr "nie można przydzielić pÅ‚yty utraconego bloku\n" #: .././repair/phase5.c:2533 msgid " - generate realtime summary info and bitmap...\n" msgstr " - generowanie opisu i bitmapy realtime...\n" #: .././repair/phase5.c:2538 msgid " - reset superblock...\n" msgstr " - przestawianie superbloku...\n" #: .././repair/phase5.c:2547 msgid "Unable to reinsert lost blocks into filesystem.\n" msgstr "Nie udaÅ‚o siÄ™ ponownie wstawić utraconych bloków do systemu plików.\n" #: .././repair/phase6.c:64 #, c-format msgid "malloc failed add_dotdot_update (%zu bytes)\n" msgstr "malloc nie powiodÅ‚o siÄ™ w add_dotdot_update (%zu bajtów)\n" #: .././repair/phase6.c:216 #, c-format msgid "malloc failed in dir_hash_add (%zu bytes)\n" msgstr "malloc nie powiodÅ‚o siÄ™ w dir_hash_add (%zu bajtów)\n" #: .././repair/phase6.c:270 msgid "ok" msgstr "ok" #: .././repair/phase6.c:271 msgid "duplicate leaf" msgstr "powtórzony liść" #: .././repair/phase6.c:272 msgid "hash value mismatch" msgstr "niezgodność wartoÅ›ci hasza" #: .././repair/phase6.c:273 msgid "no data entry" msgstr "brak wpisu danych" #: .././repair/phase6.c:274 msgid "no leaf entry" msgstr "brak wpisu liÅ›cia" #: .././repair/phase6.c:275 msgid "bad stale count" msgstr "błędna liczba stale" #: .././repair/phase6.c:283 #, c-format msgid "bad hash table for directory inode % (%s): " msgstr "błędna tablica haszujÄ…ca dla i-wÄ™zÅ‚a katalogu % (%s): " #: .././repair/phase6.c:286 msgid "rebuilding\n" msgstr "przebudowano\n" #: .././repair/phase6.c:288 msgid "would rebuild\n" msgstr "zostaÅ‚aby przebudowana\n" #: .././repair/phase6.c:324 msgid "calloc failed in dir_hash_init\n" msgstr "calloc nie powiodÅ‚o siÄ™ w dir_hash_init\n" #: .././repair/phase6.c:468 msgid "ran out of disk space!\n" msgstr "brak miejsca na dysku!\n" #: .././repair/phase6.c:470 #, c-format msgid "xfs_trans_reserve returned %d\n" msgstr "xfs_trans_reserve zwróciÅ‚o %d\n" #: .././repair/phase6.c:500 .././repair/phase6.c:603 #, c-format msgid "couldn't iget realtime bitmap inode -- error - %d\n" msgstr "nie udaÅ‚o siÄ™ wykonać iget dla i-wÄ™zÅ‚a bitmapy realtime - błąd %d\n" #: .././repair/phase6.c:558 #, c-format msgid "couldn't allocate realtime bitmap, error = %d\n" msgstr "nie udaÅ‚o siÄ™ przydzielić bitmapy realtime, błąd = %d\n" #: .././repair/phase6.c:572 #, c-format msgid "allocation of the realtime bitmap failed, error = %d\n" msgstr "przydzielenie bitmapy realtime nie powiodÅ‚o siÄ™, błąd = %d\n" #: .././repair/phase6.c:617 #, c-format msgid "couldn't map realtime bitmap block %, error = %d\n" msgstr "nie udaÅ‚o siÄ™ odwzorować bloku bitmapy realtime %, błąd = %d\n" #: .././repair/phase6.c:630 #, c-format msgid "" "can't access block % (fsbno %) of realtime bitmap inode " "%\n" msgstr "" "brak dostÄ™pu do bloku % (fsbno %) i-wÄ™zÅ‚a bitmapy realtime " "%\n" #: .././repair/phase6.c:674 .././repair/phase6.c:748 #, c-format msgid "couldn't iget realtime summary inode -- error - %d\n" msgstr "nie udaÅ‚o siÄ™ wykonać iget dla i-wÄ™zÅ‚a opisu realtime - błąd %d\n" #: .././repair/phase6.c:688 #, c-format msgid "couldn't map realtime summary inode block %, error = %d\n" msgstr "" "nie udaÅ‚o siÄ™ odwzorować bloku i-wÄ™zÅ‚a opisu realtime %, błąd = %d\n" #: .././repair/phase6.c:701 #, c-format msgid "" "can't access block % (fsbno %) of realtime summary inode " "%\n" msgstr "" "brak dostÄ™pu do bloku % (fsbno %) i-wÄ™zÅ‚a opisu realtime " "%\n" #: .././repair/phase6.c:811 #, c-format msgid "couldn't allocate realtime summary inode, error = %d\n" msgstr "nie udaÅ‚o siÄ™ przydzielić i-wÄ™zÅ‚a opisu realtime, błąd = %d\n" #: .././repair/phase6.c:825 #, c-format msgid "allocation of the realtime summary ino failed, error = %d\n" msgstr "przydzielenie i-wÄ™zÅ‚a opisu realtime nie powiodÅ‚o siÄ™, błąd = %d\n" #: .././repair/phase6.c:854 #, c-format msgid "could not iget root inode -- error - %d\n" msgstr "nie udaÅ‚o siÄ™ wykonać iget dla głównego i-wÄ™zÅ‚a - błąd %d\n" #: .././repair/phase6.c:931 #, c-format msgid "%d - couldn't iget root inode to obtain %s\n" msgstr "%d - nie udaÅ‚o siÄ™ wykonać iget dla głównego wÄ™zÅ‚a, aby uzyskać %s\n" #: .././repair/phase6.c:961 #, c-format msgid "%s inode allocation failed %d\n" msgstr "przydzielenie i-wÄ™zÅ‚a %s nie powiodÅ‚o siÄ™ - %d\n" #: .././repair/phase6.c:1008 #, c-format msgid "can't make %s, createname error %d\n" msgstr "nie można zrobić %s, błąd createname %d\n" #: .././repair/phase6.c:1029 #, c-format msgid "%s directory creation failed -- bmapf error %d\n" msgstr "tworzenie katalogu %s nie powiodÅ‚o siÄ™ - błąd bmapf %d\n" #: .././repair/phase6.c:1071 #, c-format msgid "%d - couldn't iget orphanage inode\n" msgstr "%d - nie udaÅ‚o siÄ™ wykonać iget dla i-wÄ™zÅ‚a sierociÅ„ca\n" #: .././repair/phase6.c:1082 #, c-format msgid "%d - couldn't iget disconnected inode\n" msgstr "%d - nie udaÅ‚o siÄ™ wykonać iget dla odłączonego i-wÄ™zÅ‚a\n" #: .././repair/phase6.c:1103 .././repair/phase6.c:1146 #: .././repair/phase6.c:1203 #, c-format msgid "space reservation failed (%d), filesystem may be out of space\n" msgstr "" "nie udaÅ‚o siÄ™ zarezerwować miejsca (%d), może brakować miejsca w systemie " "plików\n" #: .././repair/phase6.c:1114 .././repair/phase6.c:1158 #: .././repair/phase6.c:1214 #, c-format msgid "name create failed in %s (%d), filesystem may be out of space\n" msgstr "" "tworzenie nazwy nie powiodÅ‚o siÄ™ w %s (%d), może brakować miejsca w systemie " "plików\n" #: .././repair/phase6.c:1127 #, c-format msgid "creation of .. entry failed (%d), filesystem may be out of space\n" msgstr "" "tworzenie wpisu .. nie powiodÅ‚o siÄ™ (%d), może brakować miejsca w systemie " "plików\n" #: .././repair/phase6.c:1137 #, c-format msgid "bmap finish failed (err - %d), filesystem may be out of space\n" msgstr "" "zakoÅ„czenie bmap nie powiodÅ‚o siÄ™ (błąd %d), może brakować miejsca w " "systemie plików\n" #: .././repair/phase6.c:1177 #, c-format msgid "name replace op failed (%d), filesystem may be out of space\n" msgstr "" "operacja zastÄ…pienia nazwy nie powiodÅ‚a siÄ™ (%d), może brakować miejsca w " "systemie plików\n" #: .././repair/phase6.c:1185 .././repair/phase6.c:1225 #: .././repair/phase6.c:1361 #, c-format msgid "bmap finish failed (%d), filesystem may be out of space\n" msgstr "" "zakoÅ„czenie bmap nie powiodÅ‚o siÄ™ (%d), może brakować miejsca w systemie " "plików\n" #: .././repair/phase6.c:1244 msgid ", marking entry to be junked\n" msgstr ", zaznaczono wpis do wyrzucenia\n" #: .././repair/phase6.c:1248 msgid ", would junk entry\n" msgstr ", wpis zostaÅ‚by wyrzucony\n" #: .././repair/phase6.c:1281 #, c-format msgid "rebuilding directory inode %\n" msgstr "przebudowywanie i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:1303 #, c-format msgid "xfs_bmap_last_offset failed -- error - %d\n" msgstr "xfs_bmap_last_offset nie powiodÅ‚o siÄ™ - błąd %d\n" #: .././repair/phase6.c:1310 #, c-format msgid "xfs_bunmapi failed -- error - %d\n" msgstr "xfs_bunmapi nie powiodÅ‚o siÄ™ - błąd %d\n" #: .././repair/phase6.c:1318 #, c-format msgid "xfs_dir_init failed -- error - %d\n" msgstr "xfs_dir_init nie powiodÅ‚o siÄ™ - błąd %d\n" #: .././repair/phase6.c:1352 #, c-format msgid "" "name create failed in ino % (%d), filesystem may be out of space\n" msgstr "" "tworzenie nazwy nie powiodÅ‚o siÄ™ w i-węźle % (%d), może brakować " "miejsca w systemie plików\n" #: .././repair/phase6.c:1416 #, c-format msgid "shrink_inode failed inode % block %u\n" msgstr "shrink_inode nie powiodÅ‚o siÄ™ dla i-wÄ™zÅ‚a % bloku %u\n" #: .././repair/phase6.c:1508 .././repair/phase6.c:2307 #, c-format msgid "realloc failed in %s (%zu bytes)\n" msgstr "realloc nie powiodÅ‚o siÄ™ w %s (bajtów: %zu)\n" #: .././repair/phase6.c:1565 #, c-format msgid "empty data block %u in directory inode %: " msgstr "pusty blok danych %u w i-węźle katalogu %: " #: .././repair/phase6.c:1569 #, c-format msgid "corrupt block %u in directory inode %: " msgstr "uszkodzony blok %u w i-węźle katalogu %: " #: .././repair/phase6.c:1573 msgid "junking block\n" msgstr "wyrzucono blok\n" #: .././repair/phase6.c:1576 msgid "would junk block\n" msgstr "blok zostaÅ‚by wyrzucony\n" #: .././repair/phase6.c:1598 #, c-format msgid "" "bad directory block magic # %#x for directory inode % block %d: " msgstr "" "błędna liczba magiczna bloku katalogu %#x dla i-wÄ™zÅ‚a katalogu % " "bloku %d: " #: .././repair/phase6.c:1601 #, c-format msgid "fixing magic # to %#x\n" msgstr "poprawiono liczbÄ™ magicznÄ… na %#x\n" #: .././repair/phase6.c:1605 #, c-format msgid "would fix magic # to %#x\n" msgstr "liczba magiczna zostaÅ‚aby poprawiona na %#x\n" #: .././repair/phase6.c:1626 #, c-format msgid "directory inode % block %u has consecutive free entries: " msgstr "i-wÄ™zeÅ‚ katalogu % blok %u ma kolejne wolne wpisy: " #: .././repair/phase6.c:1630 msgid "joining together\n" msgstr "połączono\n" #: .././repair/phase6.c:1639 msgid "would join together\n" msgstr "zostaÅ‚yby połączone\n" #: .././repair/phase6.c:1672 #, c-format msgid "" "entry \"%s\" in directory inode % points to non-existent inode " "%" msgstr "" "wpis \"%s\" w i-węźle katalogu % wskazuje na nie istniejÄ…cy i-wÄ™zeÅ‚ " "%" #: .././repair/phase6.c:1689 #, c-format msgid "" "entry \"%s\" in directory inode % points to free inode %" msgstr "" "wpis \"%s\" w i-węźle katalogu % wskazuje na wolny i-wÄ™zeÅ‚ %" #: .././repair/phase6.c:1707 .././repair/phase6.c:2634 #, c-format msgid "%s (ino %) in root (%) is not a directory" msgstr "" "%s (i-wÄ™zeÅ‚ %) w katalogu głównym (%) nie jest katalogiem" #: .././repair/phase6.c:1729 .././repair/phase6.c:2656 #, c-format msgid "entry \"%s\" (ino %) in dir % is a duplicate name" msgstr "" "wpis \"%s\" (i-wÄ™zeÅ‚ %) w katalogu % jest powtórzonÄ… nazwÄ…" #: .././repair/phase6.c:1760 #, c-format msgid "" "entry \"%s\" (ino %) in dir % is not in the the first block" msgstr "" "wpis \"%s\" (i-wÄ™zeÅ‚ %) w katalogu % nie jest w pierwszym " "bloku" #: .././repair/phase6.c:1786 #, c-format msgid "entry \"%s\" in dir % is not the first entry" msgstr "wpis \"%s\" w katalogu % nie jest pierwszym wpisem" #: .././repair/phase6.c:1812 .././repair/phase6.c:2725 #, c-format msgid "" "would fix ftype mismatch (%d/%d) in directory/child inode %/" "%\n" msgstr "" "niezgodność ftype (%d/%d) w i-węźle katalogu/potomnym %/% " "zostaÅ‚aby poprawiona\n" #: .././repair/phase6.c:1817 .././repair/phase6.c:2730 #, c-format msgid "" "fixing ftype mismatch (%d/%d) in directory/child inode %/%\n" msgstr "" "niezgodność ftype (%d/%d) w i-węźle katalogu/potomnym %/% " "zostanie poprawiona\n" #: .././repair/phase6.c:1850 #, c-format msgid "" "entry \"%s\" in dir % points to an already connected directory inode " "%\n" msgstr "" "wpis \"%s\" w katalogu % wskazuje na już podłączony i-wÄ™zeÅ‚ katalogu " "%\n" #: .././repair/phase6.c:1859 .././repair/phase6.c:2694 #, c-format msgid "" "entry \"%s\" in dir ino % doesn't have a .. entry, will set it in " "ino %.\n" msgstr "" "wpis \"%s\" w i-węźle katalogu % nie ma wpisu .., zostanie ustawiony " "w i-węźle %.\n" #: .././repair/phase6.c:1869 #, c-format msgid "" "entry \"%s\" in dir inode % inconsistent with .. value (%) " "in ino %\n" msgstr "" "wpis \"%s\" w i-węźle katalogu % niespójny z wartoÅ›ciÄ… .. " "(%) w i-węźle %\n" #: .././repair/phase6.c:1881 #, c-format msgid "\twill clear entry \"%s\"\n" msgstr "\twpis \"%s\" zostanie wyczyszczony\n" #: .././repair/phase6.c:1884 #, c-format msgid "\twould clear entry \"%s\"\n" msgstr "\twpis \"%s\" zostaÅ‚by wyczyszczony\n" #: .././repair/phase6.c:1919 #, c-format msgid "expected owner inode %, got %llu, directory block %\n" msgstr "" "oczekiwano i-wÄ™zÅ‚a wÅ‚aÅ›ciciela %, napotkano %llu, blok katalogu " "%\n" #: .././repair/phase6.c:1926 #, c-format msgid "expected block %, got %llu, directory inode %\n" msgstr "" "oczekiwano bloku %, napotkano %llu, i-wÄ™zeÅ‚ katalogu %\n" #: .././repair/phase6.c:1933 #, c-format msgid "wrong FS UUID, directory inode % block %\n" msgstr "" "błędny UUID systemu plików, i-wÄ™zeÅ‚ katalogu % blok %\n" #: .././repair/phase6.c:1993 #, c-format msgid "leaf block %u for directory inode % bad CRC\n" msgstr "blok liÅ›cia %u dla i-wÄ™zÅ‚a katalogu % ma błędne CRC\n" #: .././repair/phase6.c:1998 #, c-format msgid "can't read block %u for directory inode %, error %d\n" msgstr "nie można odczytać bloku %u dla i-wÄ™zÅ‚a katalogu %, błąd %d\n" #: .././repair/phase6.c:2016 .././repair/phase6.c:2139 #, c-format msgid "leaf block %u for directory inode % bad header\n" msgstr "błędny nagłówek bloku liÅ›cia %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:2042 #, c-format msgid "leaf block %u for directory inode % bad tail\n" msgstr "błędna koÅ„cówka bloku liÅ›cia %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:2096 #, c-format msgid "can't read leaf block %u for directory inode %, error %d\n" msgstr "" "nie można odczytać bloku liÅ›cia %u dla i-wÄ™zÅ‚a katalogu %, błąd %d\n" #: .././repair/phase6.c:2108 #, c-format msgid "unknown magic number %#x for block %u in directory inode %\n" msgstr "" "nieznana liczba magiczna %#x dla bloku %u w i-węźle katalogu %\n" #: .././repair/phase6.c:2164 #, c-format msgid "can't read freespace block %u for directory inode %, error %d\n" msgstr "" "nie można odczytać bloku wolnego miejsca %u dla i-wÄ™zÅ‚a katalogu %, " "błąd %d\n" #: .././repair/phase6.c:2179 #, c-format msgid "free block %u for directory inode % bad header\n" msgstr "błędny nagłówek wolnego bloku %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:2197 #, c-format msgid "free block %u entry %i for directory ino % bad\n" msgstr "błędny wpis wolnego bloku %u numer %i dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:2207 #, c-format msgid "free block %u for directory inode % bad nused\n" msgstr "błędna liczba nused w wolnym bloku %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:2218 #, c-format msgid "missing freetab entry %u for directory inode %\n" msgstr "brak wpisu freetab %u dla i-wÄ™zÅ‚a katalogu %\n" #: .././repair/phase6.c:2257 #, c-format msgid "malloc failed in %s (% bytes)\n" msgstr "malloc nie powiodÅ‚o siÄ™ w %s (bajtów: %)\n" #: .././repair/phase6.c:2271 #, c-format msgid "calloc failed in %s (%zu bytes)\n" msgstr "calloc nie powiodÅ‚o siÄ™ w %s (bajtów: %zu)\n" #: .././repair/phase6.c:2320 #, c-format msgid "can't read data block %u for directory inode % error %d\n" msgstr "" "nie można odczytać bloku danych %u dla i-wÄ™zÅ‚a katalogu %, błąd %d\n" #: .././repair/phase6.c:2427 msgid "would junk entry\n" msgstr "wpis zostaÅ‚by wyrzucony\n" #: .././repair/phase6.c:2451 msgid "junking entry\n" msgstr "wyrzucono wpis\n" #: .././repair/phase6.c:2497 #, c-format msgid "would set .. in sf dir inode % to %\n" msgstr "" "wpis .. w i-węźle katalogu sf % zostaÅ‚by ustawiony na %\n" #: .././repair/phase6.c:2501 #, c-format msgid "setting .. in sf dir inode % to %\n" msgstr "ustawiono wpis .. w i-węźle katalogu sf % na %\n" #: .././repair/phase6.c:2601 #, c-format msgid "" "entry \"%s\" in shortform directory % references non-existent inode " "%\n" msgstr "" "wpis \"%s\" w krótkim katalogu % odwoÅ‚uje siÄ™ do nie istniejÄ…cego i-" "wÄ™zÅ‚a %\n" #: .././repair/phase6.c:2618 #, c-format msgid "" "entry \"%s\" in shortform directory inode % points to free inode " "%\n" msgstr "" "wpis \"%s\" w i-węźle krótkiego katalogu % wskazuje na wolny i-wÄ™zeÅ‚ " "%\n" #: .././repair/phase6.c:2680 #, c-format msgid "" "entry \"%s\" in directory inode % references already connected inode " "%.\n" msgstr "" "wpis \"%s\" w i-węźle katalogu % odwoÅ‚uje siÄ™ do już podłączonego i-" "wÄ™zÅ‚a %.\n" #: .././repair/phase6.c:2703 #, c-format msgid "" "entry \"%s\" in directory inode % not consistent with .. value " "(%) in inode %,\n" msgstr "" "wpis \"%s\" w i-węźle katalogu % niespójny z wartoÅ›ciÄ… .. " "(%) w i-węźle %,\n" #: .././repair/phase6.c:2760 #, c-format msgid "would fix i8count in inode %\n" msgstr "i8count w i-węźle % zostaÅ‚oby poprawione\n" #: .././repair/phase6.c:2775 #, c-format msgid "fixing i8count in inode %\n" msgstr "poprawiono i8count w i-węźle %\n" #: .././repair/phase6.c:2795 #, c-format msgid "setting size to % bytes to reflect junked entries\n" msgstr "ustawiono rozmiar na %, aby odzwierciedlaÅ‚ wyrzucone wpisy\n" #: .././repair/phase6.c:2834 .././repair/phase6.c:2838 .././repair/phase7.c:52 #, c-format msgid "couldn't map inode %, err = %d\n" msgstr "nie udaÅ‚o siÄ™ odwzorować i-wÄ™zÅ‚a %, błąd = %d\n" #: .././repair/phase6.c:2939 msgid "recreating root directory .. entry\n" msgstr "ponowne tworzenie wpisu .. głównego katalogu\n" #: .././repair/phase6.c:2955 #, c-format msgid "can't make \"..\" entry in root inode %, createname error %d\n" msgstr "" "nie można utworzyć wpisu \"..\" w i-węźle głównego katalogu %, błąd " "createname %d\n" #: .././repair/phase6.c:2966 msgid "would recreate root directory .. entry\n" msgstr "wpis .. głównego katalogu zostaÅ‚by ponownie utworzony\n" #: .././repair/phase6.c:2990 #, c-format msgid "would create missing \".\" entry in dir ino %\n" msgstr "brakujÄ…cy wpis \".\" w i-węźle katalogu % zostaÅ‚by utworzony\n" #: .././repair/phase6.c:2997 #, c-format msgid "creating missing \".\" entry in dir ino %\n" msgstr "tworzenie brakujÄ…cego wpisu \".\" w i-węźle katalogu %\n" #: .././repair/phase6.c:3013 #, c-format msgid "can't make \".\" entry in dir ino %, createname error %d\n" msgstr "" "nie można utworzyć wpisu \".\" w i-węźle katalogu %, błąd createname " "%d\n" #: .././repair/phase6.c:3106 #, c-format msgid "disconnected dir inode %, " msgstr "odłączony i-wÄ™zeÅ‚ katalogu %, " #: .././repair/phase6.c:3108 #, c-format msgid "disconnected inode %, " msgstr "odłączony i-wÄ™zeÅ‚ %, " #: .././repair/phase6.c:3112 #, c-format msgid "moving to %s\n" msgstr "przeniesiono do %s\n" #: .././repair/phase6.c:3115 #, c-format msgid "would move to %s\n" msgstr "zostaÅ‚by przeniesiony do %s\n" #: .././repair/phase6.c:3200 msgid "Phase 6 - check inode connectivity...\n" msgstr "Faza 6 - sprawdzanie łącznoÅ›ci i-wÄ™złów...\n" #: .././repair/phase6.c:3214 msgid "reinitializing root directory\n" msgstr "ponowne inicjowanie głównego katalogu\n" #: .././repair/phase6.c:3219 msgid "would reinitialize root directory\n" msgstr "główny katalog zostaÅ‚by ponownie zainicjowany\n" #: .././repair/phase6.c:3225 msgid "reinitializing realtime bitmap inode\n" msgstr "ponowne inicjowanie i-wÄ™zÅ‚a bitmapy realtime\n" #: .././repair/phase6.c:3229 msgid "would reinitialize realtime bitmap inode\n" msgstr "i-wÄ™zeÅ‚ bitmapy realtime zostaÅ‚by ponownie zainicjowany\n" #: .././repair/phase6.c:3235 msgid "reinitializing realtime summary inode\n" msgstr "ponowne inicjowanie i-wÄ™zÅ‚a opisu realtime\n" #: .././repair/phase6.c:3239 msgid "would reinitialize realtime summary inode\n" msgstr "i-wÄ™zeÅ‚ opisu realtime zostaÅ‚by ponownie zainicjowany\n" #: .././repair/phase6.c:3245 msgid " - resetting contents of realtime bitmap and summary inodes\n" msgstr " - przestawianie zawartoÅ›ci i-wÄ™złów bitmapy i opisu realtime\n" #: .././repair/phase6.c:3248 .././repair/phase6.c:3253 msgid "Warning: realtime bitmap may be inconsistent\n" msgstr "Uwaga: bitmapa realtime może być niespójna\n" #: .././repair/phase6.c:3259 msgid " - traversing filesystem ...\n" msgstr " - przechodzenie systemu plików...\n" #: .././repair/phase6.c:3282 msgid " - traversal finished ...\n" msgstr " - przechodzenie zakoÅ„czone...\n" #: .././repair/phase6.c:3283 #, c-format msgid " - moving disconnected inodes to %s ...\n" msgstr " - przenoszenie odłączonych i-wÄ™złów do %s...\n" #: .././repair/phase7.c:56 #, c-format msgid "couldn't map inode %, err = %d, can't compare link counts\n" msgstr "" "nie udaÅ‚o siÄ™ odwzorować i-wÄ™zÅ‚a %, błąd %d, nie można porównać " "liczby dowiÄ…zaÅ„\n" #: .././repair/phase7.c:68 #, c-format msgid "resetting inode % nlinks from %u to %u\n" msgstr "przestawiono nlinks i-wÄ™zÅ‚a % z %u na %u\n" #: .././repair/phase7.c:74 #, c-format msgid "would have reset inode % nlinks from %u to %u\n" msgstr "nlinks i-wÄ™zÅ‚a % zostaÅ‚oby przestawione z %u na %u\n" #: .././repair/phase7.c:143 msgid "Phase 7 - verify and correct link counts...\n" msgstr "Faza 7 - sprawdzanie i poprawianie liczby dowiÄ…zaÅ„...\n" #: .././repair/phase7.c:145 msgid "Phase 7 - verify link counts...\n" msgstr "Faza 7 - sprawdzanie liczby dowiÄ…zaÅ„...\n" #: .././repair/prefetch.c:543 msgid "prefetch corruption\n" msgstr "uszkodzenie prefetch\n" #: .././repair/prefetch.c:725 .././repair/prefetch.c:843 #, c-format msgid "failed to create prefetch thread: %s\n" msgstr "nie udaÅ‚o siÄ™ utworzyć wÄ…tku prefetch: %s\n" #: .././repair/prefetch.c:883 msgid "failed to initialize prefetch mutex\n" msgstr "nie udaÅ‚o siÄ™ zainicjować muteksu prefetch\n" #: .././repair/prefetch.c:885 .././repair/prefetch.c:887 msgid "failed to initialize prefetch cond var\n" msgstr "nie udaÅ‚o siÄ™ zainicjować zmiennej warunkowej prefetch\n" #: .././repair/progress.c:20 msgid "directories" msgstr "katalogów" #: .././repair/progress.c:22 msgid "allocation groups" msgstr "grup alokacji" #: .././repair/progress.c:24 msgid "AGI unlinked buckets" msgstr "odłączonych kubeÅ‚ków AGI" #: .././repair/progress.c:28 msgid "realtime extents" msgstr "ekstentów realtime" #: .././repair/progress.c:30 msgid "unlinked lists" msgstr "odłączonych list" #: .././repair/progress.c:37 #, c-format msgid " - %02d:%02d:%02d: %s - %llu of %llu %s done\n" msgstr " - %02d:%02d:%02d: %s - sprawdzono %llu z %llu %s\n" #: .././repair/progress.c:39 #, c-format msgid " - %02d:%02d:%02d: %s - %llu %s done\n" msgstr " - %02d:%02d:%02d: %s - sprawdzono %llu %s\n" #: .././repair/progress.c:51 msgid "scanning filesystem freespace" msgstr "przeszukiwanie wolnego miejsca w systemie plików" #: .././repair/progress.c:53 msgid "scanning agi unlinked lists" msgstr "przeszukiwanie odłączonych list agi" #: .././repair/progress.c:55 msgid "check uncertain AG inodes" msgstr "sprawdzanie niepewnych i-wÄ™złów AG" #: .././repair/progress.c:57 msgid "process known inodes and inode discovery" msgstr "przetwarzanie znanych i-wÄ™złów i rozpoznawanie i-wÄ™złów" #: .././repair/progress.c:59 msgid "process newly discovered inodes" msgstr "przetwarzanie nowo rozpoznanych i-wÄ™złów" #: .././repair/progress.c:61 msgid "setting up duplicate extent list" msgstr "tworzenie listy powtórzonych ekstentów" #: .././repair/progress.c:63 msgid "initialize realtime bitmap" msgstr "inicjowanie bitmapy realtime" #: .././repair/progress.c:65 msgid "reset realtime bitmaps" msgstr "ponowne tworzenie bitmapy realtime" #: .././repair/progress.c:67 msgid "check for inodes claiming duplicate blocks" msgstr "szukanie i-wÄ™złów odwoÅ‚ujÄ…cych siÄ™ do powtórzonych bloków" #: .././repair/progress.c:69 msgid "rebuild AG headers and trees" msgstr "przebudowywanie nagłówków i drzew AG" #: .././repair/progress.c:71 msgid "traversing filesystem" msgstr "przechodzenie systemu plików" #: .././repair/progress.c:73 msgid "traversing all unattached subtrees" msgstr "przechodzenie wszystkich odłączonych poddrzew" #: .././repair/progress.c:75 msgid "moving disconnected inodes to lost+found" msgstr "przenoszenie odłączonych i-wÄ™złów do lost+found" #: .././repair/progress.c:77 msgid "verify and correct link counts" msgstr "sprawdzanie i poprawianie liczby dowiÄ…zaÅ„" #: .././repair/progress.c:79 msgid "verify link counts" msgstr "sprawdzanie liczby dowiÄ…zaÅ„" #: .././repair/progress.c:118 msgid "cannot malloc pointer to done vector\n" msgstr "nie udaÅ‚o siÄ™ przydzielić wskaźnika do wektora wykonania\n" #: .././repair/progress.c:135 msgid "unable to create progress report thread\n" msgstr "nie udaÅ‚o siÄ™ utworzyć wÄ…tku raportowania postÄ™pu\n" #: .././repair/progress.c:178 msgid "progress_rpt: cannot malloc progress msg buffer\n" msgstr "progress_rpt: nie udaÅ‚o siÄ™ przydzielić bufora komunikatów postÄ™pu\n" #: .././repair/progress.c:191 msgid "progress_rpt: cannot create timer\n" msgstr "progress_rpt: nie można utworzyć zegara\n" #: .././repair/progress.c:194 msgid "progress_rpt: cannot set timer\n" msgstr "progress_rpt: nie można ustawić zegara\n" #: .././repair/progress.c:218 msgid "progress_rpt: cannot lock progress mutex\n" msgstr "progress_rpt: nie można zablokować muteksu\n" #: .././repair/progress.c:255 .././repair/progress.c:358 .././scrub/scrub.c:125 #, c-format msgid "%s" msgstr "%s" #: .././repair/progress.c:263 #, c-format msgid "" "\t- %02d:%02d:%02d: Phase %d: elapsed time %s - processed %d %s per minute\n" msgstr "" "\t- %02d:%02d:%02d: Faza %d: miniony czas %s - przetworzono %d %s na minutÄ™\n" #: .././repair/progress.c:268 #, c-format msgid "" "\t- %02d:%02d:%02d: Phase %d: %%% done - estimated remaining time " "%s\n" msgstr "" "\t- %02d:%02d:%02d: Faza %d: %%% zrobione - przewidywany pozostaÅ‚y " "czas %s\n" #: .././repair/progress.c:276 msgid "progress_rpt: error unlock msg mutex\n" msgstr "progress_rpt: błąd odblokowywania muteksu komunikatów\n" #: .././repair/progress.c:282 msgid "cannot delete timer\n" msgstr "nie można usunąć zegara\n" #: .././repair/progress.c:296 msgid "set_progress_msg: cannot lock progress mutex\n" msgstr "set_progress_msg: nie można zablokować mutekstu postÄ™pu\n" #: .././repair/progress.c:306 msgid "set_progress_msg: cannot unlock progress mutex\n" msgstr "set_progress_msg: nie można odblokować mutekstu postÄ™pu\n" #: .././repair/progress.c:326 msgid "print_final_rpt: cannot lock progress mutex\n" msgstr "print_final_rpt: nie można zablokować mutekstu postÄ™pu\n" #: .././repair/progress.c:362 msgid "print_final_rpt: cannot unlock progress mutex\n" msgstr "print_final_rpt: nie można odblokować muteksu postÄ™pu\n" #: .././repair/progress.c:411 #, c-format msgid "%02d:%02d:%02d" msgstr "%02d:%02d:%02d" #: .././repair/progress.c:433 #, c-format msgid "%d week" msgstr "%d tygodni" #: .././repair/progress.c:434 .././repair/progress.c:444 #: .././repair/progress.c:460 .././repair/progress.c:478 #: .././repair/progress.c:493 msgid "s" msgstr " " # XXX: ngettext() #: .././repair/progress.c:443 #, c-format msgid "%d day" msgstr "%d dni" #: .././repair/progress.c:450 .././repair/progress.c:467 #: .././repair/progress.c:485 .././repair/progress.c:495 msgid ", " msgstr ", " #: .././repair/progress.c:459 #, c-format msgid "%d hour" msgstr "%d godzin" #: .././repair/progress.c:477 #, c-format msgid "%d minute" msgstr "%d minut" #: .././repair/progress.c:492 #, c-format msgid "%d second" msgstr "%d sekund" #: .././repair/progress.c:513 #, c-format msgid "" "\n" " XFS_REPAIR Summary %s\n" msgstr "" "\n" " Podsumowanie XFS_REPAIR %s\n" #: .././repair/progress.c:515 msgid "Phase\t\tStart\t\tEnd\t\tDuration\n" msgstr "Faza\t\tPoczÄ…tek\tKoniec\t\tCzas trwania\n" #: .././repair/progress.c:520 .././repair/progress.c:523 #, c-format msgid "Phase %d:\tSkipped\n" msgstr "Faza %d:\tPominiÄ™ta\n" #: .././repair/progress.c:527 #, c-format msgid "Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n" msgstr "Faza %d:\t%02d.%02d %02d:%02d:%02d\t%02d.%02d %02d:%02d:%02d\t%s\n" #: .././repair/progress.c:533 #, c-format msgid "" "\n" "Total run time: %s\n" msgstr "" "\n" "CaÅ‚kowity czas trwania: %s\n" #: .././repair/rmap.c:84 msgid "couldn't allocate per-AG reverse map roots\n" msgstr "nie udaÅ‚o siÄ™ przydzielić korzeni odwrotnej mapy AG\n" #: .././repair/rmap.c:91 msgid "Insufficient memory while allocating reverse mapping slabs." msgstr "Za maÅ‚o pamiÄ™ci podczas przydzielania pÅ‚yt odwrotnych odwzorowaÅ„." #: .././repair/rmap.c:96 .././repair/rmap.c:335 msgid "" "Insufficient memory while allocating raw metadata reverse mapping slabs." msgstr "" "Za maÅ‚o pamiÄ™ci podczas przydzielania pÅ‚yt odwrotnych odwzorowaÅ„ surowych " "metadanych." #: .././repair/rmap.c:102 msgid "Insufficient memory while allocating refcount item slabs." msgstr "" "Za maÅ‚o pamiÄ™ci podczas przydzielania pÅ‚yt elementów zliczania odwoÅ‚aÅ„." #: .././repair/rmap.c:708 msgid "Insufficient memory while recreating refcount tree." msgstr "Za maÅ‚o pamiÄ™ci podczas ponownego tworzenia drzewa zliczania odwoÅ‚aÅ„." #: .././repair/rmap.c:965 msgid "would rebuild corrupt rmap btrees.\n" msgstr "uszkodzone b-drzewa rmap zostaÅ‚yby przebudowane.\n" #: .././repair/rmap.c:1008 #, c-format msgid "" "Missing reverse-mapping record for (%u/%u) %slen %u owner % %s%soff " "%\n" msgstr "" "Brak rekordu odwrotnego odwzorowania dla: (%u/%u) %sdÅ‚ugość %u wÅ‚aÅ›ciciel " "% %s%soff %\n" #: .././repair/rmap.c:1012 .././repair/rmap.c:1030 .././repair/rmap.c:1040 msgid "unwritten " msgstr "nie zapisana " #: .././repair/rmap.c:1016 .././repair/rmap.c:1034 .././repair/rmap.c:1044 msgid "attr " msgstr "attr " #: .././repair/rmap.c:1018 .././repair/rmap.c:1036 .././repair/rmap.c:1046 msgid "bmbt " msgstr "bmbt " #: .././repair/rmap.c:1026 #, c-format msgid "" "Incorrect reverse-mapping: saw (%u/%u) %slen %u owner % %s%soff " "%; should be (%u/%u) %slen %u owner % %s%soff %\n" msgstr "" "NieprawidÅ‚owe odwrotne odwzorowanie: widziano (%u/%u) %sdÅ‚ugość %u " "wÅ‚aÅ›ciciel % %s%soff %; powinno być (%u/%u) %sdÅ‚ugość %u " "wÅ‚aÅ›ciciel % %s%soff %\n" #: .././repair/rmap.c:1161 #, c-format msgid "setting reflink flag on inode %\n" msgstr "ustawiono flagÄ™ reflink dla i-wÄ™zÅ‚a %\n" #: .././repair/rmap.c:1165 #, c-format msgid "clearing reflink flag on inode %\n" msgstr "wyczyszczono flagÄ™ reflink dla i-wÄ™zÅ‚a %\n" #: .././repair/rmap.c:1236 #, c-format msgid "Unable to fix reflink flag on inode %.\n" msgstr "Nie udaÅ‚o siÄ™ poprawić flagi reflink dla i-wÄ™zÅ‚a %.\n" #: .././repair/rmap.c:1297 msgid "would rebuild corrupt refcount btrees.\n" msgstr "uszkodzone b-drzewa zliczania odwoÅ‚aÅ„ zostaÅ‚yby przebudowane.\n" #: .././repair/rmap.c:1330 .././repair/rmap.c:1341 #, c-format msgid "Missing reference count record for (%u/%u) len %u count %u\n" msgstr "Brak rekordu zliczania odwoÅ‚aÅ„ dla (%u/%u) dÅ‚ugość %u licznik %u\n" #: .././repair/rmap.c:1352 #, c-format msgid "" "Incorrect reference count: saw (%u/%u) len %u nlinks %u; should be (%u/%u) " "len %u nlinks %u\n" msgstr "" "NieprawidÅ‚owy licznik odwoÅ‚aÅ„: widziano (%u/%u) dÅ‚ugość %u nlinks %u; " "powinno być (%u/%u) dÅ‚ugość %u nlinks %u\n" #: .././repair/rmap.c:1395 .././repair/rmap.c:1426 #, c-format msgid "failed to fix AGFL on AG %d, error %d\n" msgstr "nie udaÅ‚o siÄ™ naprawić AGFL w AG %d, błąd %d\n" #: .././repair/rt.c:47 msgid "couldn't allocate memory for incore realtime bitmap.\n" msgstr "nie udaÅ‚o siÄ™ przydzielić pamiÄ™ci dla bitmapy realtime.\n" #: .././repair/rt.c:51 msgid "couldn't allocate memory for incore realtime summary info.\n" msgstr "nie udaÅ‚o siÄ™ przydzielić pamiÄ™ci dla opisu realtime.\n" #: .././repair/rt.c:203 #, c-format msgid "can't find block %d for rtbitmap inode\n" msgstr "nie można odnaleźć bloku %d dla i-wÄ™zÅ‚a bitmapy realtime\n" #: .././repair/rt.c:211 #, c-format msgid "can't read block %d for rtbitmap inode\n" msgstr "nie można odczytać bloku %d dla i-wÄ™zÅ‚a bitmapy realtime\n" #: .././repair/rt.c:265 #, c-format msgid "block %d for rtsummary inode is missing\n" msgstr "brak bloku %d dla i-wÄ™zÅ‚a opisu realtime\n" #: .././repair/rt.c:273 #, c-format msgid "can't read block %d for rtsummary inode\n" msgstr "nie można odczytać bloku %d dla i-wÄ™zÅ‚a opisu realtime\n" #: .././repair/sb.c:125 msgid "error finding secondary superblock -- failed to memalign buffer\n" msgstr "" "błąd podczas szukania zapasowego superbloku - nie udaÅ‚o siÄ™ memalign bufora\n" #: .././repair/sb.c:162 msgid "found candidate secondary superblock...\n" msgstr "znaleziono potencjalny zapasowy superblok...\n" #: .././repair/sb.c:174 msgid "verified secondary superblock...\n" msgstr "sprawdzono zapasowy superblok...\n" #: .././repair/sb.c:179 msgid "unable to verify superblock, continuing...\n" msgstr "nie udaÅ‚o siÄ™ sprawdzić superbloku, kontynuacja...\n" #: .././repair/sb.c:229 msgid "" "\n" "attempting to find secondary superblock...\n" msgstr "" "\n" "próba odnalezienia zapasowego superbloku...\n" #: .././repair/sb.c:517 msgid "failed to memalign superblock buffer\n" msgstr "nie udaÅ‚o siÄ™ wykonać memalign dla bufora superbloku\n" #: .././repair/sb.c:524 msgid "couldn't seek to offset 0 in filesystem\n" msgstr "nie udaÅ‚o siÄ™ wykonać seek na offset 0 w systemie plików\n" #: .././repair/sb.c:534 msgid "primary superblock write failed!\n" msgstr "zapis głównego superbloku nie powiódÅ‚ siÄ™!\n" #: .././repair/sb.c:552 #, c-format msgid "error reading superblock %u -- failed to memalign buffer\n" msgstr "" "błąd podczas odczytu superbloku %u - nie udaÅ‚o siÄ™ wykonać memalign dla " "bufora\n" #: .././repair/sb.c:563 #, c-format msgid "error reading superblock %u -- seek to offset % failed\n" msgstr "" "błąd podczas odczytu superbloku %u - seek na offset % nie powiódÅ‚ " "siÄ™\n" #: .././repair/sb.c:572 #, c-format msgid "superblock read failed, offset %, size %d, ag %u, rval %d\n" msgstr "" "odczyt superbloku nie powiódÅ‚ siÄ™, offset %, rozmiar %d, ag %u, rval " "%d\n" #: .././repair/sb.c:619 msgid "couldn't malloc geometry structure\n" msgstr "nie udaÅ‚o siÄ™ przydzielić struktury geometrii\n" #: .././repair/sb.c:773 msgid "" "Only two AGs detected and they do not match - cannot validate filesystem " "geometry.\n" "Use the -o force_geometry option to proceed.\n" msgstr "" "Wykryto tylko dwie AG i nie zgadzajÄ… siÄ™ - nie można sprawdzić poprawnoÅ›ci " "geometrii systemu plików.\n" "ProszÄ™ użyć opcji -o force_geometry, aby kontynuować.\n" #: .././repair/sb.c:789 msgid "" "Only one AG detected - cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n" msgstr "" "Wykryto tylko dwie AG - nie można sprawdzić poprawnoÅ›ci geometrii systemu " "plików.\n" "ProszÄ™ użyć opcji -o force_geometry, aby kontynuować.\n" #: .././repair/sb.c:804 msgid "Not enough matching superblocks - cannot proceed.\n" msgstr "Za maÅ‚o pasujÄ…cych superbloków - nie można kontynuować.\n" #: .././repair/sb.c:819 msgid "could not read superblock\n" msgstr "nie udaÅ‚o siÄ™ odczytać superbloku\n" #: .././repair/scan.c:85 .././repair/scan.c:140 #, c-format msgid "can't read btree block %d/%d\n" msgstr "nie można odczytać bloku b-drzewa %d/%d\n" #: .././repair/scan.c:89 .././repair/scan.c:152 #, c-format msgid "btree block %d/%d is suspect, error %d\n" msgstr "blok b-drzewa %d/%d jest podejrzany, błąd %d\n" #: .././repair/scan.c:213 #, c-format msgid "bad magic # %#x in inode % (%s fork) bmbt block %\n" msgstr "" "błędna liczba magiczna %#x w i-węźle % (gałąź %s) blok bmbt " "%\n" #: .././repair/scan.c:219 #, c-format msgid "" "expected level %d got %d in inode %, (%s fork) bmbt block %\n" msgstr "" "oczekiwano poziomu %d, a uzyskano %d w i-węźle %, (gałęzi %s) blok " "bmbt %\n" #: .././repair/scan.c:229 #, c-format msgid "expected owner inode %, got %llu, bmbt block %\n" msgstr "" "oczekiwano i-wÄ™zÅ‚a wÅ‚aÅ›ciciela %, napotkano %llu, blok bmbt " "%\n" #: .././repair/scan.c:239 #, c-format msgid "expected block %, got %llu, bmbt block %\n" msgstr "oczekiwano bloku %, napotkano %llu, blok bmbt %\n" #: .././repair/scan.c:249 #, c-format msgid "wrong FS UUID, bmbt block %\n" msgstr "błędny UUID systemu plików, blok bmbt %\n" #: .././repair/scan.c:269 #, c-format msgid "" "bad fwd (right) sibling pointer (saw % parent block says %)\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" "błędny wskaźnik w przód (prawy) (napotkano %, blok nadrzÄ™dny mówi " "%)\n" "\tw i-węźle % (gałęzi %s) bloku bmap btree %\n" #: .././repair/scan.c:279 #, c-format msgid "" "bad back (left) sibling pointer (saw %llu parent block says %)\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" "błędny wskaźnik wstecz (lewy) (napotkano %llu, blok nadrzÄ™dny mówi " "%)\n" "\tw i-węźle % (gałęzi %s) bloku bmap btree %\n" #: .././repair/scan.c:294 #, c-format msgid "" "bad back (left) sibling pointer (saw %llu should be NULL (0))\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" "błędny wskaźnik wstecz (lewy) (napotkano %llu, powinien być NULL (0))\n" "\tw i-węźle % (gałęzi %s) bloku bmap btree %\n" #: .././repair/scan.c:342 #, c-format msgid "inode 0x%bmap block 0x% claimed, state is %d\n" msgstr "i-wÄ™zeÅ‚ 0x% blok bmap 0x% przypisany, stan to %d\n" #: .././repair/scan.c:349 #, c-format msgid "inode 0x% bmap block 0x% claimed, state is %d\n" msgstr "i-wÄ™zeÅ‚ 0x% blok bmap 0x% przypisany, stan to %d\n" #: .././repair/scan.c:364 #, c-format msgid "bad state %d, inode % bmap block 0x%\n" msgstr "błędny stan %d, i-wÄ™zeÅ‚ % blok bmap 0x%\n" #: .././repair/scan.c:395 #, c-format msgid "couldn't add inode % bmbt block % reverse-mapping data." msgstr "" "nie udaÅ‚o siÄ™ dodać i-wÄ™zÅ‚a %, dane odwrotnego odwzorowania bloku " "bmbt %." #: .././repair/scan.c:403 .././repair/scan.c:454 #, c-format msgid "inode % bad # of bmap records (%u, min - %u, max - %u)\n" msgstr "" "błędna liczba rekordów bmap w i-węźle % (%u, minimum - %u, maksimum " "- %u)\n" #: .././repair/scan.c:433 #, c-format msgid "" "out-of-order bmap key (file offset) in inode %, %s fork, fsbno " "%\n" msgstr "" "uszkodzony klucz bmap (offset pliku) w i-węźle %, gałęzi %s, fsbno " "%\n" #: .././repair/scan.c:471 #, c-format msgid "bad bmap btree ptr 0x%llx in ino %\n" msgstr "błędny wskaźnik bmap btree 0x%llx w i-węźle %\n" #: .././repair/scan.c:499 #, c-format msgid "" "correcting bt key (was %llu, now %) in inode %\n" "\t\t%s fork, btree block %\n" msgstr "" "poprawiono klucz bt (byÅ‚o %llu, jest %) w i-węźle %\n" "\t\tgałąź %s, blok b-drzewa %\n" #: .././repair/scan.c:511 #, c-format msgid "" "bad btree key (is %llu, should be %) in inode %\n" "\t\t%s fork, btree block %\n" msgstr "" "błędny klucz b-drzewa (jest %llu, powinno być %) w i-węźle " "%\n" "\t\tgałąź %s, blok b-drzewa %\n" #: .././repair/scan.c:529 #, c-format msgid "" "bad fwd (right) sibling pointer (saw % should be NULLFSBLOCK)\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" "błędny wskaźnik w przód (prawy) (napotkano %, powinien być " "NULLFSBLOCK)\n" "\tw i-węźle % (gałęzi %s) bloku bmap btree %\n" #: .././repair/scan.c:587 .././repair/scan.c:964 #, c-format msgid "bad magic # %#x in bt%s block %d/%d\n" msgstr "błędna liczba magiczna %#x w bloku bt%s %d/%d\n" #: .././repair/scan.c:605 .././repair/scan.c:983 #, c-format msgid "expected level %d got %d in bt%s block %d/%d\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku bt%s %d/%d\n" #: .././repair/scan.c:619 #, c-format msgid "" "%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "blok b-drzewa wolnego miejsca %s przypisany (stan %d), agno %d, bno %d, " "podejrzany %d\n" #: .././repair/scan.c:639 .././repair/scan.c:740 .././repair/scan.c:1014 #: .././repair/scan.c:1158 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bt%s, blok %u/%u\n" #: .././repair/scan.c:657 .././repair/scan.c:1049 .././repair/scan.c:1335 #, c-format msgid "invalid start block %u in record %u of %s btree block %u/%u\n" msgstr "błędny blok poczÄ…tkowy %u w rekordzie %u bloku b-drzewa %s %u/%u\n" #: .././repair/scan.c:663 .././repair/scan.c:1055 .././repair/scan.c:1341 #, c-format msgid "invalid length %u in record %u of %s btree block %u/%u\n" msgstr "błędna dÅ‚ugość %u w rekordzie %u bloku b-drzewa %s %u/%u\n" #: .././repair/scan.c:710 #, c-format msgid "block (%d,%d-%d) multiply claimed by %s space tree, state - %d\n" msgstr "" "blok (%d,%d-%d) wielokrotnie przypisany do drzewa miejsca %s, stan - %d\n" #: .././repair/scan.c:839 #, c-format msgid "" "Static meta block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" "niezgodność statycznego bloku metadanych (%d,%d-%d) w drzewie %s, stan - %d," "%\n" #: .././repair/scan.c:848 #, c-format msgid "AG meta block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" "niezgodność bloku metadanych AG (%d,%d-%d) w drzewie %s, stan - %d," "%\n" #: .././repair/scan.c:856 #, c-format msgid "inode block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" "niezgodność bloku i-wÄ™zÅ‚a (%d,%d-%d) w drzewie %s, stan - %d,%\n" #: .././repair/scan.c:864 #, c-format msgid "" "AG refcount block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" "niezgodność bloku zliczania odwoÅ‚aÅ„ AG (%d,%d-%d) w drzewie %s, stan - %d," "%\n" #: .././repair/scan.c:873 #, c-format msgid "in use block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" "niezgodność używanego bloku (%d,%d-%d) w drzewie %s, stan - %d,%\n" #: .././repair/scan.c:895 #, c-format msgid "unknown block (%d,%d-%d) mismatch on %s tree, state - %d,%\n" msgstr "" "niezgodność nieznanego bloku (%d,%d-%d) w drzewie %s, stan - %d,%\n" #: .././repair/scan.c:995 #, c-format msgid "%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "blok b-drzewa rmap %s przypisany (stan %d), agno %d, bno %d, podejrzany %d\n" #: .././repair/scan.c:1039 #, c-format msgid "invalid flags in record %u of %s btree block %u/%u\n" msgstr "błędne flagi w rekordzie %u bloku b-drzewa %s %u/%u\n" #: .././repair/scan.c:1068 #, c-format msgid "invalid owner in rmap btree record %d (% %u) block %u/%u\n" msgstr "" "błędny wÅ‚aÅ›ciciel w rekordzie %d b-drzewa rmap (% %u) blok %u/%u\n" #: .././repair/scan.c:1075 #, c-format msgid "" "record %d of block (%u/%u) in %s btree cannot have non-inode owner with " "flags\n" msgstr "" "rekord %d bloku (%u/%u) w b-drzewie %s nie może mieć nie bÄ™dÄ…cego i-wÄ™zÅ‚em " "wÅ‚aÅ›ciciela z flagami\n" #: .././repair/scan.c:1079 #, c-format msgid "" "record %d of block (%u/%u) in %s btree cannot have non-inode owner with " "offset\n" msgstr "" "rekord %d bloku (%u/%u) w b-drzewie %s nie może mieć nie bÄ™dÄ…cego i-wÄ™zÅ‚em " "wÅ‚aÅ›ciciela z offsetem\n" #: .././repair/scan.c:1100 #, c-format msgid "" "out-of-order rmap btree record %d (%u % % %u) block %u/%u\n" msgstr "" "rekord %d b-drzewa rmap poza kolejnoÅ›ciÄ… (%u % % %u), blok " "%u/%u\n" #: .././repair/scan.c:1109 .././repair/scan.c:1387 #, c-format msgid "" "record %d in block (%u/%u) of %s tree should be merged with previous record\n" msgstr "" "rekord %d w bloku (%u/%u) drzewa %s powinien być połączony z poprzednim " "rekordem\n" #: .././repair/scan.c:1124 #, c-format msgid "record %d greater than high key of block (%u/%u) in %s tree\n" msgstr "rekord %d wiÄ™kszy niż górny klucz bloku (%u/%u) w drzewie %s\n" #: .././repair/scan.c:1180 #, c-format msgid "invalid flags in key %u of %s btree block %u/%u\n" msgstr "błędne flagi w kluczu %u bloku b-drzewa %s %u/%u\n" #: .././repair/scan.c:1186 #, c-format msgid "key %d greater than high key of block (%u/%u) in %s tree\n" msgstr "klucz %d wiÄ™kszy niż górny klucz bloku (%u/%u) w drzewie %s\n" #: .././repair/scan.c:1212 #, c-format msgid "invalid flags in high key %u of %s btree block %u/%u\n" msgstr "błędne flagi w górnym kluczu %u bloku b-drzewa %s %u/%u\n" #: .././repair/scan.c:1263 #, c-format msgid "bad magic # %#x in %s btree block %d/%d\n" msgstr "błędna liczba magiczna %#x w bloku b-drzewa %s %d/%d\n" #: .././repair/scan.c:1271 #, c-format msgid "expected level %d got %d in %s btree block %d/%d\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku b-drzewa %s %d/%d\n" #: .././repair/scan.c:1285 #, c-format msgid "%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "blok b-drzewa %s przypisany (stan %d), agno %d, bno %d, podejrzany %d\n" #: .././repair/scan.c:1304 .././repair/scan.c:1421 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in %s btree block %u/%u\n" msgstr "" "błędna liczba rekordów b-drzewa (%u, min=%u, max=%u) w bloku b-drzewa %s, " "blok %u/%u\n" #: .././repair/scan.c:1322 #, c-format msgid "" "leftover CoW extent has incorrect refcount in record %u of %s btree block %u/" "%u\n" msgstr "" "pozostaÅ‚y ekstent CoW ma niepoprawnÄ… liczbÄ™ odwoÅ‚aÅ„ w rekordzie %u bloku b-" "drzewa %s %u/%u\n" #: .././repair/scan.c:1327 #, c-format msgid "" "leftover CoW extent has invalid startblock in record %u of %s btree block %u/" "%u\n" msgstr "" "pozostaÅ‚y ekstent CoW ma błędny blok poczÄ…tkowy w rekordzie %u bloku b-" "drzewa %s %u/%u\n" #: .././repair/scan.c:1362 #, c-format msgid "extent (%u/%u) len %u claimed, state is %d\n" msgstr "ekstent (%u/%u) dÅ‚ugość %u przypisany, stan %d\n" #: .././repair/scan.c:1369 #, c-format msgid "invalid reference count %u in record %u of %s btree block %u/%u\n" msgstr "błędna liczba odwoÅ‚aÅ„ %u w rekordzie %u bloku b-drzewa %s %u/%u\n" #: .././repair/scan.c:1376 #, c-format msgid "out-of-order %s btree record %d (%u %u) block %u/%u\n" msgstr "rekord b-drzewa %s poza kolejnoÅ›ciÄ…: %d (%u %u), blok %u/%u\n" #: .././repair/scan.c:1502 #, c-format msgid "badly aligned %s rec (starting inode = %)\n" msgstr "błędnie wyrównany rekord %s (poczÄ…tkowy i-wÄ™zeÅ‚ = %)\n" #: .././repair/scan.c:1516 #, c-format msgid "bad starting inode # (% (0x%x 0x%x)) in %s rec, skipping rec\n" msgstr "" "błędny numer poczÄ…tkowego i-wÄ™zÅ‚a (% (0x%x 0x%x)) w rekordzie %s, " "pominiÄ™to rekord\n" #: .././repair/scan.c:1525 #, c-format msgid "bad ending inode # (% (0x%x 0x%zx)) in %s rec, skipping rec\n" msgstr "" "błędny numer koÅ„cowego i-wÄ™zÅ‚a (% (0x%x 0x%zx)) w rekordzie %s, " "pominiÄ™to rekord\n" #: .././repair/scan.c:1590 #, c-format msgid "" "ir_holemask/ir_free mismatch, %s chunk %d/%u, holemask 0x%x free 0x%llx\n" msgstr "" "niezgodność ir_holemask/ir_free, porcja %s %d/%u, holemask 0x%x free 0x%llx\n" #: .././repair/scan.c:1677 #, c-format msgid "" "inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n" msgstr "" "część i-wÄ™zÅ‚a odwoÅ‚uje siÄ™ do używanego bloku, blok inobt - agno %d, bno %d, " "inopb %d\n" #: .././repair/scan.c:1695 #, c-format msgid "" "inode rec for ino % (%d/%d) overlaps existing rec (start %d/%d)\n" msgstr "" "rekord i-wÄ™zÅ‚a dla i-wÄ™zÅ‚a % (%d/%d) nachodzi na istniejÄ…cy rekord " "(poczÄ…tek %d/%d)\n" #: .././repair/scan.c:1719 #, c-format msgid "ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n" msgstr "" "niezgodność ir_freecount/free, porcja i-wÄ™złów %d/%u, freecount %d nfree %d\n" #: .././repair/scan.c:1727 .././repair/scan.c:1917 #, c-format msgid "invalid inode count, inode chunk %d/%u, count %d ninodes %d\n" msgstr "błędna liczba i-wÄ™złów, porcja i-wÄ™złów %d/%u, licznik %d ninodes %d\n" #: .././repair/scan.c:1781 #, c-format msgid "" "sparse inode chunk claims inode block, finobt block - agno %d, bno %d, inopb " "%d\n" msgstr "" "część rzadkiego i-wÄ™zÅ‚a odwoÅ‚uje siÄ™ do bloku i-wÄ™zÅ‚a, blok finobt - agno " "%d, bno %d, inopb %d\n" #: .././repair/scan.c:1796 .././repair/scan.c:1808 #, c-format msgid "" "inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb " "%d\n" msgstr "" "część i-wÄ™zÅ‚a odwoÅ‚uje siÄ™ do nieÅ›ledzonego bloku, blok finobt - agno %d, " "bno %d, inopb %d\n" #: .././repair/scan.c:1818 #, c-format msgid "" "inode chunk claims used block, finobt block - agno %d, bno %d, inopb %d\n" msgstr "" "część i-wÄ™zÅ‚a odwoÅ‚uje siÄ™ do używanego bloku, blok finobt - agno %d, bno " "%d, inopb %d\n" #: .././repair/scan.c:1840 #, c-format msgid "" "finobt rec for ino % (%d/%u) does not match existing rec (%d/%d)\n" msgstr "" "rekord finobt dla i-wÄ™zÅ‚a % (%d/%u) nie pasuje do istniejÄ…cego " "rekordu (%d/%d)\n" #: .././repair/scan.c:1882 #, c-format msgid "undiscovered finobt record, ino % (%d/%u)\n" msgstr "nie rozpoznany rekord finobt, i-wÄ™zeÅ‚ % (%d/%u)\n" #: .././repair/scan.c:1904 #, c-format msgid "" "finobt ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n" msgstr "" "niezgodność finobt ir_freecount/free, porcja i-wÄ™złów %d/%u, freecount %d " "nfree %d\n" #: .././repair/scan.c:1910 #, c-format msgid "finobt record with no free inodes, inode chunk %d/%u\n" msgstr "rekord finobt bez wolnych i-wÄ™złów, porcja i-wÄ™złów %d/%u\n" #: .././repair/scan.c:1963 #, c-format msgid "bad magic # %#x in inobt block %d/%d\n" msgstr "błędna liczba magiczna %#x w bloku inobt %d/%d\n" #: .././repair/scan.c:1971 #, c-format msgid "expected level %d got %d in inobt block %d/%d\n" msgstr "oczekiwano poziomu %d, a uzyskano %d w bloku inobt %d/%d\n" #: .././repair/scan.c:1994 #, c-format msgid "inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" "blok b-drzewa i-wÄ™złów przypisany (stan %d), agno %d, bno %d, podejrzany %d\n" #: .././repair/scan.c:2017 #, c-format msgid "dubious inode btree block header %d/%d\n" msgstr "wÄ…tpliwy nagłówek bloku b-drzewa i-wÄ™złów %d/%d\n" #: .././repair/scan.c:2135 #, c-format msgid "can't read agfl block for ag %d\n" msgstr "nie można odczytać bloku agfl dla ag %d\n" #: .././repair/scan.c:2139 #, c-format msgid "agfl has bad CRC for ag %d\n" msgstr "agfl ma błędnÄ… sumÄ™ kontrolnÄ… dla ag %d\n" #: .././repair/scan.c:2160 #, c-format msgid "bad agbno %u in agfl, agno %d\n" msgstr "błędne agbno %u w agfl, agno %d\n" #: .././repair/scan.c:2169 #, c-format msgid "freeblk count %d != flcount %d in ag %d\n" msgstr "liczba freeblk %d != flcount %d w ag %d\n" #: .././repair/scan.c:2195 #, c-format msgid "bad agbno %u for btbno root, agno %d\n" msgstr "błędne agbno %u dla korzenia btbno, agno %d\n" #: .././repair/scan.c:2207 #, c-format msgid "bad agbno %u for btbcnt root, agno %d\n" msgstr "błędne agbno %u dla korzenia btbcnt, agno %d\n" #: .././repair/scan.c:2226 #, c-format msgid "bad rmapbt block count %u, saw %u\n" msgstr "błędna liczba bloków rmapbt %u, widziano %u\n" #: .././repair/scan.c:2230 #, c-format msgid "bad agbno %u for rmapbt root, agno %d\n" msgstr "błędne agbno %u dla korzenia rmapbt, agno %d\n" #: .././repair/scan.c:2247 #, c-format msgid "bad refcountbt block count %u, saw %u\n" msgstr "błędna liczba bloków refcountbt %u, widziano %u\n" #: .././repair/scan.c:2251 #, c-format msgid "bad agbno %u for refcntbt root, agno %d\n" msgstr "błędne agbno %u dla korzenia refcntbt, agno %d\n" #: .././repair/scan.c:2269 #, c-format msgid "agf_btreeblks %u, counted % in ag %u\n" msgstr "agf_btreeblks %u, naliczono % w ag %u\n" #: .././repair/scan.c:2293 #, c-format msgid "bad agbno %u for inobt root, agno %d\n" msgstr "błędne agbno %u dla głównego inobt, agno %d\n" #: .././repair/scan.c:2306 #, c-format msgid "bad agbno %u for finobt root, agno %d\n" msgstr "błędne agbno %u dla głównego finobt, agno %d\n" #: .././repair/scan.c:2323 #, c-format msgid "agi_freecount %u, counted %u in ag %u finobt\n" msgstr "agi_freecount %u, naliczono %u w ag %u finobt\n" #: .././repair/scan.c:2333 #, c-format msgid "agi unlinked bucket %d is %u in ag %u (inode=%)\n" msgstr "niedowiÄ…zany kubeÅ‚ek agi %d to %u w ag %u (i-wÄ™zeÅ‚=%)\n" #: .././repair/scan.c:2364 msgid "can't allocate memory for superblock\n" msgstr "nie można przydzielić pamiÄ™ci dla superbloku\n" #: .././repair/scan.c:2371 msgid "root superblock" msgstr "główny superblok" #: .././repair/scan.c:2380 msgid "agf block" msgstr "blok agf" #: .././repair/scan.c:2389 msgid "agi block" msgstr "blok agi" #: .././repair/scan.c:2410 #, c-format msgid "reset bad sb for ag %d\n" msgstr "przestawiono błędny superblok dla ag %d\n" #: .././repair/scan.c:2413 #, c-format msgid "would reset bad sb for ag %d\n" msgstr "błędny superblok dla ag %d zostaÅ‚by przestawiony\n" #: .././repair/scan.c:2418 #, c-format msgid "reset bad agf for ag %d\n" msgstr "przestawiono błędne agf dla ag %d\n" #: .././repair/scan.c:2421 #, c-format msgid "would reset bad agf for ag %d\n" msgstr "błędne agf dla ag %d zostaÅ‚oby przestawione\n" #: .././repair/scan.c:2426 #, c-format msgid "reset bad agi for ag %d\n" msgstr "przestawiono błędne agi dla ag %d\n" #: .././repair/scan.c:2429 #, c-format msgid "would reset bad agi for ag %d\n" msgstr "błędna agi dla ag %d zostaÅ‚oby przestawione\n" #: .././repair/scan.c:2434 #, c-format msgid "bad uncorrected agheader %d, skipping ag...\n" msgstr "błędny nie poprawiony agheader %d, pominiÄ™to ag...\n" #: .././repair/scan.c:2497 #, c-format msgid "can't get %s for ag %d\n" msgstr "nie można uzyskać %s dla ag %d\n" #: .././repair/scan.c:2517 msgid "no memory for ag header counts\n" msgstr "brak pamiÄ™ci na liczniki nagłówków ag\n" #: .././repair/scan.c:2543 #, c-format msgid "sb_icount %, counted %\n" msgstr "sb_icount %, naliczono %\n" #: .././repair/scan.c:2548 #, c-format msgid "sb_ifree %, counted %\n" msgstr "sb_ifree %, naliczono %\n" #: .././repair/scan.c:2553 #, c-format msgid "sb_fdblocks %, counted %\n" msgstr "sb_fdblocks %, naliczono %\n" #: .././repair/scan.c:2559 #, c-format msgid "used blocks %, counted %\n" msgstr "użytych bloków %, naliczono %\n" #: .././repair/threads.c:34 #, c-format msgid "cannot create worker threads, error = [%d] %s\n" msgstr "nie można utworzyć wÄ…tków pracujÄ…cych, błąd: [%d] %s\n" #: .././repair/threads.c:49 #, c-format msgid "cannot allocate worker item, error = [%d] %s\n" msgstr "nie można przydzielić elementu pracujÄ…cego, błąd: [%d] %s\n" #: .././repair/versions.c:68 #, c-format msgid "bogus quota flags 0x%x set in superblock" msgstr "niepoprawne flagi limitów 0x%x ustawione w superbloku" #: .././repair/versions.c:74 msgid ", bogus flags will be cleared\n" msgstr ", błędne flagi zostanÄ… wyczyszczone\n" #: .././repair/versions.c:76 msgid ", bogus flags would be cleared\n" msgstr ", błędne flagi zostaÅ‚yby wyczyszczone\n" #: .././repair/versions.c:115 .././repair/versions.c:120 #: .././repair/versions.c:125 msgid "Shared Version bit set. Not supported. Ever.\n" msgstr "Ustawiony bit wersji współdzielonej. Nie jest obsÅ‚ugiwany. Nigdy.\n" #: .././repair/versions.c:138 msgid "This filesystem has uninitialized extent flags.\n" msgstr "Ten system plików ma niezainicjowane flagi ekstentów.\n" #: .././repair/versions.c:144 msgid "" "This filesystem uses feature(s) not yet supported in this release.\n" "Please run a more recent version of xfs_repair.\n" msgstr "" "Ten system plików używa możliwoÅ›ci jeszcze nie obsÅ‚ugiwanych w tym wydaniu.\n" "ProszÄ™ uruchomić nowszÄ… wersjÄ™ xfs_repair.\n" #: .././repair/versions.c:150 #, c-format msgid "WARNING: unknown superblock version %d\n" msgstr "UWAGA: nieznana wersja superbloku %d\n" #: .././repair/versions.c:153 msgid "This filesystem contains features not understood by this program.\n" msgstr "Ten system plików zawiera cechÄ™ nie rozumianÄ… przez ten program.\n" #: .././repair/versions.c:161 msgid "" "WARNING: you have disallowed superblock-feature-bits-allowed\n" "\tbut this superblock has feature bits. The superblock\n" "\twill be downgraded. This may cause loss of filesystem meta-data\n" msgstr "" "UWAGA: zabroniono superblock-feature-bits-allowed, ale ten\n" "\tsuperblok ma ustawione bity cech. Superblok zostanie zdegradowany.\n" "\tMoże to spowodować utratÄ™ metadanych systemu plików.\n" #: .././repair/versions.c:166 msgid "" "WARNING: you have disallowed superblock-feature-bits-allowed\n" "\tbut this superblock has feature bits. The superblock\n" "\twould be downgraded. This might cause loss of filesystem\n" "\tmeta-data.\n" msgstr "" "UWAGA: zabroniono superblock-feature-bits-allowed, ale ten\n" "\tsuperblok ma ustawione bity cech. Superblok zostaÅ‚by zdegradowany.\n" "\tMogÅ‚oby to spowodować utratÄ™ metadanych systemu plików.\n" #: .././repair/versions.c:182 #, c-format msgid "" "Superblock has unknown compat/rocompat/incompat features (0x%x/0x%x/0x%x).\n" "Using a more recent xfs_repair is recommended.\n" msgstr "" "Superblok zawiera nieznane cechy compat/rocompat/incompat (0x%x/0x%x/0x%x).\n" "Zalecane jest użycie nowszej wersji xfs_repair.\n" #: .././repair/versions.c:194 msgid "" "WARNING: you have disallowed attributes but this filesystem\n" "\thas attributes. The filesystem will be downgraded and\n" "\tall attributes will be removed.\n" msgstr "" "UWAGA: zabroniono używania atrybutów, ale ten system plików zawiera\n" "\tatrybuty. System plików zostanie zdegradowany, a wszystkie\n" "\tatrybuty usuniÄ™te.\n" #: .././repair/versions.c:199 msgid "" "WARNING: you have disallowed attributes but this filesystem\n" "\thas attributes. The filesystem would be downgraded and\n" "\tall attributes would be removed.\n" msgstr "" "UWAGA: zabroniono używania atrybutów, ale ten system plików zawiera\n" "\tatrybuty. System plików zostaÅ‚by zdegradowany, a wszystkie\n" "\tatrybuty usuniÄ™te.\n" #: .././repair/versions.c:212 msgid "" "WARNING: you have disallowed attr2 attributes but this filesystem\n" "\thas attributes. The filesystem will be downgraded and\n" "\tall attr2 attributes will be removed.\n" msgstr "" "UWAGA: zabroniono używania atrybutów attr2, ale ten system plików\n" "\tzawiera atrybuty. System plików zostanie zdegradowany, a wszystkie\n" "\tatrybuty attr2 usuniÄ™te.\n" #: .././repair/versions.c:217 msgid "" "WARNING: you have disallowed attr2 attributes but this filesystem\n" "\thas attributes. The filesystem would be downgraded and\n" "\tall attr2 attributes would be removed.\n" msgstr "" "UWAGA: zabroniono używania atrybutów attr2, ale ten system plików\n" "\tzawiera atrybuty. System plików zostaÅ‚by zdegradowany, a wszystkie\n" "\tatrybuty attr2 usuniÄ™te.\n" #: .././repair/versions.c:229 msgid "" "WARNING: you have a V1 inode filesystem. It will be converted to a\n" "\tversion 2 inode filesystem. If you do not want this, run an older\n" "\tversion of xfs_repair.\n" msgstr "" "UWAGA: to jest system plików z i-wÄ™zÅ‚ami V1. Zostanie przekonwertowany\n" "\tdo systemu plików z i-wÄ™zÅ‚ami V2. Jeżeli nie jest to pożądane, należy\n" "\tużyć starszej wersji xfs_repair.\n" #: .././repair/versions.c:234 msgid "" "WARNING: you have a V1 inode filesystem. It would be converted to a\n" "\tversion 2 inode filesystem. If you do not want this, run an older\n" "\tversion of xfs_repair.\n" msgstr "" "UWAGA: to jest system plików z i-wÄ™zÅ‚ami V1. ZostaÅ‚by przekonwertowany\n" "\tdo systemu plików z i-wÄ™zÅ‚ami V2. Jeżeli nie jest to pożądane, należy\n" "\tużyć starszej wersji xfs_repair.\n" #: .././repair/versions.c:244 msgid "" "WARNING: you have disallowed quotas but this filesystem\n" "\thas quotas. The filesystem will be downgraded and\n" "\tall quota information will be removed.\n" msgstr "" "UWAGA: zabroniono używania limitów (quot), ale ten system plików\n" "\tzawiera limity. System plików zostanie zdegradowany, a wszystkie\n" "\tinformacje o limitach usuniÄ™te.\n" #: .././repair/versions.c:249 msgid "" "WARNING: you have disallowed quotas but this filesystem\n" "\thas quotas. The filesystem would be downgraded and\n" "\tall quota information would be removed.\n" msgstr "" "UWAGA: zabroniono używania limitów (quot), ale ten system plików\n" "\tzawiera limity. System plików zostaÅ‚by zdegradowany, a wszystkie\n" "\tinformacje o limitach usuniÄ™te.\n" #: .././repair/versions.c:277 msgid "" "WARNING: you have disallowed aligned inodes but this filesystem\n" "\thas aligned inodes. The filesystem will be downgraded.\n" "\tThis will permanently degrade the performance of this filesystem.\n" msgstr "" "UWAGA: zabroniono używania wyrównanych i-wÄ™złów, ale ten system plików\n" "\tzawiera wyrównane i-wÄ™zÅ‚y. System plików zostanie zdegradowany.\n" "\tTrwale zdegraduje to wydajność tego systemu plików.\n" #: .././repair/versions.c:282 msgid "" "WARNING: you have disallowed aligned inodes but this filesystem\n" "\thas aligned inodes. The filesystem would be downgraded.\n" "\tThis would permanently degrade the performance of this filesystem.\n" msgstr "" "UWAGA: zabroniono używania wyrównanych i-wÄ™złów, ale ten system plików\n" "\tzawiera wyrównane i-wÄ™zÅ‚y. System plików zostaÅ‚by zdegradowany.\n" "\tTrwale zdegradowaÅ‚oby to wydajność tego systemu plików.\n" #: .././repair/xfs_repair.c:85 #, c-format msgid "" "Usage: %s [options] device\n" "\n" "Options:\n" " -f The device is a file\n" " -L Force log zeroing. Do this as a last resort.\n" " -l logdev Specifies the device where the external log resides.\n" " -m maxmem Maximum amount of memory to be used in megabytes.\n" " -n No modify mode, just checks the filesystem for damage.\n" " -P Disables prefetching.\n" " -r rtdev Specifies the device where the realtime section resides.\n" " -v Verbose output.\n" " -c subopts Change filesystem parameters - use xfs_admin.\n" " -o subopts Override default behaviour, refer to man page.\n" " -t interval Reporting interval in seconds.\n" " -d Repair dangerously.\n" " -V Reports version and exits.\n" msgstr "" "SkÅ‚adnia: %s [opcje] urzÄ…dzenie\n" "\n" "Opcje:\n" " -f UrzÄ…dzenie jest plikiem\n" " -L Wymuszenie wyzerowania logu. Wykonywać tylko w " "ostatecznoÅ›ci.\n" " -l urz_logu OkreÅ›lenie urzÄ…dzenia z zewnÄ™trznym logiem.\n" " -m maks_pam Maksymalna ilość pamiÄ™ci do użycia w megabajtach.\n" " -n Tryb bez modyfikacji, tylko sprawdzenie systemu plików.\n" " -P Wyłączenie prefetch.\n" " -r urz_rt OkreÅ›lenie urzÄ…dzenia z sekcjÄ… realtime.\n" " -v Szczegółowe wyjÅ›cie.\n" " -c podopcje Zmiana parametrów systemu plików przy użyciu xfs_admina.\n" " -o podopcje Zmiana domyÅ›lnego zachowania, wiÄ™cej na stronie manuala.\n" " -t czas Okres informowania o postÄ™pach w minutach.\n" " -d Naprawianie w sposób niebezpieczny.\n" " -V Wypisanie informacji o wersji i zakoÅ„czenie.\n" #: .././repair/xfs_repair.c:111 msgid "no error" msgstr "brak błędu" #: .././repair/xfs_repair.c:112 msgid "bad magic number" msgstr "błędna liczba magiczna" #: .././repair/xfs_repair.c:113 msgid "bad blocksize field" msgstr "błędne pole blocksize" #: .././repair/xfs_repair.c:114 msgid "bad blocksize log field" msgstr "błędne pole logu blocksize" #: .././repair/xfs_repair.c:115 msgid "bad or unsupported version" msgstr "błędna lub nie obsÅ‚ugiwana wersja" #: .././repair/xfs_repair.c:117 msgid "filesystem mkfs-in-progress bit set" msgstr "ustawiony bit mkfs-in-progress systemu plików" #: .././repair/xfs_repair.c:119 msgid "inconsistent filesystem geometry information" msgstr "niespójne informacje o geometrii systemu plików" #: .././repair/xfs_repair.c:121 msgid "bad inode size or inconsistent with number of inodes/block" msgstr "błędny rozmiar i-wÄ™zÅ‚a lub niespójność z liczbÄ… i-wÄ™złów/blok" #: .././repair/xfs_repair.c:122 msgid "bad sector size" msgstr "błędny rozmiar sektora" #: .././repair/xfs_repair.c:124 msgid "AGF geometry info conflicts with filesystem geometry" msgstr "informacje o geometrii AGF sÄ… w konflikcie z geometriÄ… systemu plików" #: .././repair/xfs_repair.c:126 msgid "AGI geometry info conflicts with filesystem geometry" msgstr "informacje o geometrii AGI sÄ… w konflikcie z geometriÄ… systemu plików" #: .././repair/xfs_repair.c:128 msgid "AG superblock geometry info conflicts with filesystem geometry" msgstr "" "informacje o geometrii superbloku AG sÄ… w konflikcie z geometriÄ… systemu " "plików" #: .././repair/xfs_repair.c:129 msgid "attempted to perform I/O beyond EOF" msgstr "próbowano wykonać operacjÄ™ we/wy poza koÅ„cem pliku" #: .././repair/xfs_repair.c:131 msgid "inconsistent filesystem geometry in realtime filesystem component" msgstr "niespójna geometria systemu plików w skÅ‚adniku realtime" #: .././repair/xfs_repair.c:133 msgid "maximum indicated percentage of inodes > 100%" msgstr "okreÅ›lono maksymalny procent i-wÄ™złów > 100%" #: .././repair/xfs_repair.c:135 msgid "inconsistent inode alignment value" msgstr "niespójna wartość wyrównania i-wÄ™zÅ‚a" #: .././repair/xfs_repair.c:137 msgid "not enough secondary superblocks with matching geometry" msgstr "za maÅ‚o zapasowych superbloków o pasujÄ…cej geometrii" #: .././repair/xfs_repair.c:139 msgid "bad stripe unit in superblock" msgstr "błędna jednostka pasa w superbloku" #: .././repair/xfs_repair.c:141 msgid "bad stripe width in superblock" msgstr "błędna szerokość pasa w superbloku" #: .././repair/xfs_repair.c:143 msgid "bad shared version number in superblock" msgstr "błędny numer wersji współdzielenia w superbloku" #: .././repair/xfs_repair.c:145 msgid "bad CRC in superblock" msgstr "błędna suma kontrolna w superbloku" #: .././repair/xfs_repair.c:147 msgid "inconsistent directory geometry information" msgstr "niespójne informacje o geometrii katalogu" #: .././repair/xfs_repair.c:152 #, c-format msgid "bad error code - %d\n" msgstr "błędny kod błędu - %d\n" #: .././repair/xfs_repair.c:160 #, c-format msgid "-%c %s option cannot have a value\n" msgstr "opcja -%c %s nie przyjmuje wartoÅ›ci\n" #: .././repair/xfs_repair.c:250 msgid "-o ihash option has been removed and will be ignored\n" msgstr "opcja -o ihash zostaÅ‚a usuniÄ™ta i zostanie zignorowana\n" #: .././repair/xfs_repair.c:255 msgid "-o bhash option cannot be used with -m option\n" msgstr "opcja -o bhash nie może być użyta wraz z opcjÄ… -m\n" #: .././repair/xfs_repair.c:307 msgid "-m option cannot be used with -o bhash option\n" msgstr "opcja -m nie może być użyta wraz z opcjÄ… -o bhash\n" #: .././repair/xfs_repair.c:349 #, c-format msgid "" "\n" "fatal error -- " msgstr "" "\n" "błąd krytyczny - " #: .././repair/xfs_repair.c:476 #, c-format msgid "sb root inode value % %sinconsistent with calculated value %u\n" msgstr "" "wartość i-wÄ™zÅ‚a głównego superbloku % %sniespójna z obliczonÄ… " "wartoÅ›ciÄ… %u\n" #: .././repair/xfs_repair.c:483 #, c-format msgid "resetting superblock root inode pointer to %u\n" msgstr "przestawiono wskaźnik i-wÄ™zÅ‚a głównego superbloku na %u\n" #: .././repair/xfs_repair.c:487 #, c-format msgid "would reset superblock root inode pointer to %u\n" msgstr "wskaźnik i-wÄ™zÅ‚a głównego superbloku zostaÅ‚by przestawiony na %u\n" #: .././repair/xfs_repair.c:499 #, c-format msgid "" "sb realtime bitmap inode % %sinconsistent with calculated value %u\n" msgstr "" "i-wÄ™zeÅ‚ bitmapy realtime superbloku % %sniespójny z obliczonÄ… " "wartoÅ›ciÄ… %u\n" #: .././repair/xfs_repair.c:506 #, c-format msgid "resetting superblock realtime bitmap ino pointer to %u\n" msgstr "przestawiono wskaźnik i-wÄ™zÅ‚a bitmapy realtime superbloku na %u\n" #: .././repair/xfs_repair.c:510 #, c-format msgid "would reset superblock realtime bitmap ino pointer to %u\n" msgstr "" "wskaźnik i-wÄ™zÅ‚a bitmapy realtime superbloku zostaÅ‚by przestawiony na %u\n" #: .././repair/xfs_repair.c:522 #, c-format msgid "" "sb realtime summary inode % %sinconsistent with calculated value %u\n" msgstr "" "i-wÄ™zeÅ‚ opisu realtime superbloku % %sniespójny z obliczonÄ… " "wartoÅ›ciÄ… %u\n" #: .././repair/xfs_repair.c:529 #, c-format msgid "resetting superblock realtime summary ino pointer to %u\n" msgstr "przestawiono wskaźnik i-wÄ™zÅ‚a opisu realtime superbloku na %u\n" #: .././repair/xfs_repair.c:533 #, c-format msgid "would reset superblock realtime summary ino pointer to %u\n" msgstr "" "wskaźnik i-wÄ™zÅ‚a opisu realtime superbloku zostaÅ‚by przestawiony na %u\n" #: .././repair/xfs_repair.c:589 #, c-format msgid "Maximum metadata LSN (%d:%d) is ahead of log (%d:%d).\n" msgstr "Maksymalny LSN metadanych (%d:%d) jest poza logiem (%d:%d).\n" #: .././repair/xfs_repair.c:593 #, c-format msgid "Would format log to cycle %d.\n" msgstr "Log zostaÅ‚by sformatowany na cykl %d.\n" #: .././repair/xfs_repair.c:597 #, c-format msgid "Format log to cycle %d.\n" msgstr "Log zostanie sformatowany na cykl %d.\n" #: .././repair/xfs_repair.c:647 msgid "" "Cannot get host filesystem geometry.\n" "Repair may fail if there is a sector size mismatch between\n" "the image and the host filesystem.\n" msgstr "" "Nie można pobrać geometrii systemu plików hosta.\n" "Naprawienie może siÄ™ nie powieść, jeÅ›li istnieje niespójność rozmiaru\n" "sektora miÄ™dzy obrazem a systemem plików hosta.\n" #: .././repair/xfs_repair.c:657 msgid "" "Sector size on host filesystem larger than image sector size.\n" "Cannot turn off direct IO, so exiting.\n" msgstr "" "Rozmiar sektora na systemie plików hosta wiÄ™kszy niż rozmiar sektora " "obrazu.\n" "Nie można wyłączyć bezpoÅ›redniego we/wy - zakoÅ„czono dziaÅ‚anie.\n" #: .././repair/xfs_repair.c:700 #, c-format msgid "%s: couldn't stat \"%s\"\n" msgstr "%s: nie udaÅ‚o siÄ™ wykonać stat na \"%s\"\n" #: .././repair/xfs_repair.c:718 msgid "" "Primary superblock would have been modified.\n" "Cannot proceed further in no_modify mode.\n" "Exiting now.\n" msgstr "" "Główny superblok zostaÅ‚by zmodyfikowany.\n" "Nie można kontynuować w trybie bez modyfikacji.\n" "ZakoÅ„czono.\n" #: .././repair/xfs_repair.c:726 msgid "" "Primary superblock bad after phase 1!\n" "Exiting now.\n" msgstr "" "NieprawidÅ‚owy główny superblok po fazie 1!\n" "Koniec dziaÅ‚ania.\n" #: .././repair/xfs_repair.c:748 #, c-format msgid "%s: cannot repair this filesystem. Sorry.\n" msgstr "%s: niestety nie można naprawić tego systemu plików.\n" #: .././repair/xfs_repair.c:824 #, c-format msgid " - reporting progress in intervals of %s\n" msgstr " - informowanie o postÄ™pie w odstÄ™pach %s\n" #: .././repair/xfs_repair.c:869 #, c-format msgid "" " - max_mem = %lu, icount = %, imem = %, dblock = " "%, dmem = %\n" msgstr "" " - max_mem = %lu, icount = %, imem = %, dblock = " "%, dmem = %\n" #: .././repair/xfs_repair.c:878 #, c-format msgid "" "Required memory for repair is greater that the maximum specified\n" "with the -m option. Please increase it to at least %lu.\n" msgstr "" "Pamięć wymagana do naprawy przekracza maksimum okreÅ›lone opcjÄ… -m.\n" "ProszÄ™ jÄ… zwiÄ™kszyć do co najmniej %lu.\n" #: .././repair/xfs_repair.c:883 #, c-format msgid "" "Memory available for repair (%luMB) may not be sufficient.\n" "At least %luMB is needed to repair this filesystem efficiently\n" "If repair fails due to lack of memory, please\n" msgstr "" "Pamięć dostÄ™pna przy naprawie (%luMB) może nie być wystarczajÄ…ca.\n" "Aby wydajnie naprawić ten system plików, niezbÄ™dne jest co najmniej %luMB.\n" "JeÅ›li naprawa nie powiedzie siÄ™ z powodu braku pamiÄ™ci, proszÄ™\n" #: .././repair/xfs_repair.c:889 msgid "turn prefetching off (-P) to reduce the memory footprint.\n" msgstr "wyłączyć prefetch (-P), aby zmniejszyć zużycie pamiÄ™ci.\n" #: .././repair/xfs_repair.c:892 #, c-format msgid "increase system RAM and/or swap space to at least %luMB.\n" msgstr "" "proszÄ™ rozszerzyć rozmiar RAM systemu i/lub przestrzeni wymiany do co " "najmniej %luMB.\n" #: .././repair/xfs_repair.c:907 #, c-format msgid " - block cache size set to %d entries\n" msgstr " - rozmiar bufora bloku ustawiony na %d wpisów\n" #: .././repair/xfs_repair.c:932 msgid "Found unsupported filesystem features. Exiting now.\n" msgstr "Znaleziono nie obsÅ‚ugiwane cechy systemu plików. ZakoÅ„czono.\n" #: .././repair/xfs_repair.c:950 #, c-format msgid "No modify flag set, skipping phase 5\n" msgstr "Ustawiono flagÄ™ braku modyfikacji, pominiÄ™to fazÄ™ 5\n" #: .././repair/xfs_repair.c:970 msgid "Inode allocation btrees are too corrupted, skipping phases 6 and 7\n" msgstr "B-drzewa alokacji i-wÄ™złów sÄ… zbyt uszkodzone, pominiÄ™to fazy 6 i 7\n" #: .././repair/xfs_repair.c:976 msgid "Warning: no quota inodes were found. Quotas disabled.\n" msgstr "Uwaga: nie znaleziono i-wÄ™złów limitów (quot). Limity wyłączone.\n" #: .././repair/xfs_repair.c:979 msgid "Warning: no quota inodes were found. Quotas would be disabled.\n" msgstr "" "Uwaga: nie znaleziono i-wÄ™złów limitów (quot). Limity zostaÅ‚yby wyłączone.\n" #: .././repair/xfs_repair.c:984 msgid "Warning: quota inodes were cleared. Quotas disabled.\n" msgstr "Uwaga: i-wÄ™zÅ‚y limitów (quot) byÅ‚y wyczyszczone. Limity wyłączone.\n" #: .././repair/xfs_repair.c:987 msgid "Warning: quota inodes would be cleared. Quotas would be disabled.\n" msgstr "" "Uwaga: i-wÄ™zÅ‚y limitów (quot) zostaÅ‚yby wyczyszczone. Limity zostaÅ‚yby " "wyłączone.\n" #: .././repair/xfs_repair.c:993 msgid "" "Warning: user quota information was cleared.\n" "User quotas can not be enforced until limit information is recreated.\n" msgstr "" "Uwaga: informacje o limitach użytkowników byÅ‚y wyczyszczone.\n" "Limity użytkowników nie mogÄ… być wymuszone do czasu odtworzenia informacji.\n" #: .././repair/xfs_repair.c:997 msgid "" "Warning: user quota information would be cleared.\n" "User quotas could not be enforced until limit information was recreated.\n" msgstr "" "Uwaga: informacje o limitach użytkowników zostaÅ‚yby wyczyszczone.\n" "Limity użytkowników nie mogÅ‚yby być wymuszone do czasu odtworzenia " "informacji.\n" #: .././repair/xfs_repair.c:1005 msgid "" "Warning: group quota information was cleared.\n" "Group quotas can not be enforced until limit information is recreated.\n" msgstr "" "Uwaga: informacje o limitach grup byÅ‚y wyczyszczone.\n" "Limity grup nie mogÄ… być wymuszone do czasu odtworzenia informacji.\n" #: .././repair/xfs_repair.c:1009 msgid "" "Warning: group quota information would be cleared.\n" "Group quotas could not be enforced until limit information was recreated.\n" msgstr "" "Uwaga: informacje o limitach grup zostaÅ‚yby wyczyszczone.\n" "Limity grup nie mogÅ‚yby być wymuszone do czasu odtworzenia informacji.\n" #: .././repair/xfs_repair.c:1017 msgid "" "Warning: project quota information was cleared.\n" "Project quotas can not be enforced until limit information is recreated.\n" msgstr "" "Uwaga: informacje o limitach projektów byÅ‚y wyczyszczone.\n" "Limity projektów nie mogÄ… być wymuszone do czasu odtworzenia informacji.\n" #: .././repair/xfs_repair.c:1021 msgid "" "Warning: project quota information would be cleared.\n" "Project quotas could not be enforced until limit information was recreated.\n" msgstr "" "Uwaga: informacje o limitach projektów zostaÅ‚yby wyczyszczone.\n" "Limity projektów nie mogÅ‚yby być wymuszone do czasu odtworzenia informacji.\n" #: .././repair/xfs_repair.c:1038 msgid "No modify flag set, skipping filesystem flush and exiting.\n" msgstr "" "Flaga braku modyfikacji ustawiona, pominiÄ™to zrzucanie systemu plików, " "zakoÅ„czono.\n" #: .././repair/xfs_repair.c:1057 msgid "Note - quota info will be regenerated on next quota mount.\n" msgstr "" "Uwaga - informacje o limitach zostanÄ… ponownie wygenerowane przy nastÄ™pnym " "montowaniu.\n" #: .././repair/xfs_repair.c:1064 #, c-format msgid "" "Note - stripe unit (%d) and width (%d) were copied from a backup " "superblock.\n" "Please reset with mount -o sunit=,swidth= if necessary\n" msgstr "" "Uwaga - pola jednostki pasa (%d) i szerokoÅ›ci pasa (%d) zostaÅ‚y skopiowane\n" "z kopii zapasowej superbloku. W razie potrzeby można je przestawić przy " "użyciu\n" "mount -o sunit=,swidth=\n" #: .././repair/xfs_repair.c:1088 msgid "done\n" msgstr "gotowe\n" #: .././repair/xfs_repair.c:1092 msgid "Repair of readonly mount complete. Immediate reboot encouraged.\n" msgstr "" "Naprawa systemu zamontowanego tylko do odczytu zakoÅ„czona. Zalecany " "natychmiastowy restart systemu.\n" #: .././rtcp/xfs_rtcp.c:30 #, c-format msgid "%s [-e extsize] [-p] [-V] source target\n" msgstr "%s [-e rozm_ekstentu] [-p] [-V] źródÅ‚o cel\n" #: .././rtcp/xfs_rtcp.c:69 #, c-format msgid "%s: must specify files to copy\n" msgstr "%s: trzeba podać pliki do skopiowania\n" #: .././rtcp/xfs_rtcp.c:84 #, c-format msgid "%s: stat of %s failed\n" msgstr "%s: stat na %s nie powiodÅ‚o siÄ™\n" #: .././rtcp/xfs_rtcp.c:91 #, c-format msgid "%s: final argument is not directory\n" msgstr "%s: ostatni argument nie jest katalogiem\n" #: .././rtcp/xfs_rtcp.c:138 #, c-format msgid "%s: failed stat on %s: %s\n" msgstr "%s: nie udaÅ‚o siÄ™ wykonać stat na %s: %s\n" #: .././rtcp/xfs_rtcp.c:159 #, c-format msgid "%s: %s filesystem has no realtime partition\n" msgstr "%s: system plików %s nie ma partycji realtime\n" #: .././rtcp/xfs_rtcp.c:180 .././rtcp/xfs_rtcp.c:208 #, c-format msgid "%s: open of %s failed: %s\n" msgstr "%s: otwarcie %s nie powiodÅ‚o siÄ™: %s\n" #: .././rtcp/xfs_rtcp.c:197 #, c-format msgid "%s: set attributes on %s failed: %s\n" msgstr "%s: ustawienie atrybutów dla %s nie powiodÅ‚o siÄ™: %s\n" #: .././rtcp/xfs_rtcp.c:215 #, c-format msgid "%s: get attributes of %s failed: %s\n" msgstr "%s: pobranie atrybutów %s nie powiodÅ‚o siÄ™: %s\n" #: .././rtcp/xfs_rtcp.c:225 .././rtcp/xfs_rtcp.c:262 #, c-format msgid "%s: %s is not a realtime file.\n" msgstr "%s: %s nie jest plikiem realtime.\n" #: .././rtcp/xfs_rtcp.c:235 #, c-format msgid "%s: %s file extent size is %d, instead of %d.\n" msgstr "%s: plik %s ma rozmiar ekstentu %d zamiast %d.\n" #: .././rtcp/xfs_rtcp.c:248 .././rtcp/xfs_rtcp.c:271 #, c-format msgid "%s: open of %s source failed: %s\n" msgstr "%s: otwarcie źródÅ‚a %s nie powiodÅ‚o siÄ™: %s\n" #: .././rtcp/xfs_rtcp.c:285 #, c-format msgid "%s: couldn't get direct I/O information: %s\n" msgstr "%s: nie udaÅ‚o siÄ™ uzyskać informacji o bezpoÅ›rednim we/wy: %s\n" #: .././rtcp/xfs_rtcp.c:295 #, c-format msgid "%s: extent size %d not a multiple of %d.\n" msgstr "%s: rozmiar ekstentu %d nie jest wielokrotnoÅ›ciÄ… %d.\n" #: .././rtcp/xfs_rtcp.c:309 #, c-format msgid "The size of %s is not a multiple of %d.\n" msgstr "Rozmiar %s nie jest wielokrotnoÅ›ciÄ… %d.\n" #: .././rtcp/xfs_rtcp.c:312 #, c-format msgid "%s will be padded to %lld bytes.\n" msgstr "%s: zostanie dopeÅ‚niony do %lld bajtów.\n" #: .././rtcp/xfs_rtcp.c:318 #, c-format msgid "" "Use the -p option to pad %s to a size which is a multiple of %d bytes.\n" msgstr "" "Można użyć opcji -p do dopeÅ‚nienia %s do rozmiaru bÄ™dÄ…cego wielokrotnoÅ›ciÄ… " "%d bajtów.\n" #: .././rtcp/xfs_rtcp.c:360 #, c-format msgid "%s: write error: %s\n" msgstr "%s: błąd zapisu: %s\n" #: .././rtcp/xfs_rtcp.c:388 #, c-format msgid "%s: could not open %s: %s\n" msgstr "%s: nie udaÅ‚o siÄ™ otworzyć %s: %s\n" #: .././scrub/common.c:106 #, c-format msgid "%s." msgstr "%s." #: .././scrub/common.c:114 #, c-format msgid " (%s line %d)" msgstr " (%s linia %d)" #: .././scrub/common.c:359 #, c-format msgid "More than %u naming warnings, shutting up." msgstr "Ponad %u ostrzeżeÅ„ dotyczÄ…cych nazw, uciszenie reszty." #: .././scrub/filemap.c:68 #, c-format msgid "%s attr" msgstr "atrybuty %s" #: .././scrub/filemap.c:71 #, c-format msgid "%s CoW" msgstr "CoW %s" #: .././scrub/filemap.c:74 #, c-format msgid "%s data" msgstr "dane %s" #: .././scrub/fscounters.c:106 .././scrub/inodes.c:236 #, c-format msgid "dev %d:%d AG %u inodes" msgstr "urzÄ…dzenie %d:%d AG %u i-wÄ™zÅ‚y" #: .././scrub/fscounters.c:142 .././scrub/inodes.c:269 .././scrub/phase2.c:97 #: .././scrub/spacemap.c:220 .././scrub/vfs.c:206 msgid "Could not create workqueue." msgstr "Nie udaÅ‚o siÄ™ utworzyć kolejki zadaÅ„." #: .././scrub/fscounters.c:150 #, c-format msgid "Could not queue AG %u icount work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania icount AG %u." #: .././scrub/inodes.c:185 msgid "Changed too many times during scan; giving up." msgstr "Za dużo zmian w trakcie skanowania; poddajÄ™ siÄ™." #: .././scrub/inodes.c:278 #, c-format msgid "Could not queue AG %u bulkstat work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania bulkstat AG %u." #: .././scrub/phase1.c:61 msgid "Shutting down filesystem!" msgstr "Zamykanie systemu plików!" #: .././scrub/phase1.c:107 msgid "Must be root to run scrub." msgstr "Do uruchomienia procesu scrub trzeba być rootem." #: .././scrub/phase1.c:131 #, c-format msgid "%s: using %d threads to scrub.\n" msgstr "%s: użycie %d wÄ…tków do doczyszczania.\n" #: .././scrub/phase1.c:138 msgid "Does not appear to be an XFS filesystem!" msgstr "To nie wyglÄ…da na system plików XFS!" #: .././scrub/phase1.c:168 msgid "getting fshandle" msgstr "pobieranie fshandle" #: .././scrub/phase1.c:178 msgid "Kernel metadata scrubbing facility is not available." msgstr "Funkcja doczyszczania metadanych w jÄ…drze nie jest dostÄ™pna." #: .././scrub/phase1.c:185 msgid "Kernel metadata repair facility is not available. Use -n to scrub." msgstr "" "Funkcja naprawy metadanych w jÄ…drze nie jest dostÄ™pna. ProszÄ™ dodać -n do " "polecenia scrub." #: .././scrub/phase1.c:195 msgid "Unable to find XFS information." msgstr "Nie udaÅ‚o siÄ™ odnaleźć informacji XFS." #: .././scrub/phase1.c:203 msgid "Unable to find log device path." msgstr "Nie udaÅ‚o siÄ™ odnaleźć Å›cieżki do urzÄ…dzenia logu." #: .././scrub/phase1.c:208 msgid "Unable to find realtime device path." msgstr "Nie udaÅ‚o siÄ™ odnaleźć Å›cieżki do urzÄ…dzenia realtime." #: .././scrub/phase2.c:48 #, c-format msgid "AG %u" msgstr "AG %u" #: .././scrub/phase2.c:115 #, c-format msgid "Could not queue AG %u scrub work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania doczyszczenia AG %u." #: .././scrub/phase2.c:127 msgid "Could not queue filesystem scrub work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania doczyszczenia systemu plików." #: .././scrub/phase3.c:140 msgid "Could not create counter." msgstr "Nie udaÅ‚o sie utworzyć licznika." #: .././scrub/phase5.c:63 msgid "Zero length name found." msgstr "Znaleziono nazwÄ™ zerowej dÅ‚ugoÅ›ci." #: .././scrub/phase5.c:82 #, c-format msgid "Control character found in %s name \"%s\"." msgstr "Znaleziono znak sterujÄ…cy w nazwie %s \"%s\"." #: .././scrub/phase5.c:188 .././scrub/unicrash.c:390 msgid "extended attribute" msgstr "atrybut rozszerzony" #: .././scrub/phase5.c:257 #, c-format msgid "inode % (%u/%u)" msgstr "i-wÄ™zeÅ‚ % (%u/%u)" #: .././scrub/phase5.c:303 msgid "Filesystem has errors, skipping connectivity checks." msgstr "System plików ma błędy, pomijanie kontroli łącznoÅ›ci." #: .././scrub/phase6.c:153 #, c-format msgid "offset %llu failed read verification." msgstr "nie powiodÅ‚a sie weryfikacja odczytu offsetu %llu." #: .././scrub/phase6.c:195 #, c-format msgid "inode % (unlinked)" msgstr "i-wÄ™zeÅ‚ % (nie dowiÄ…zany)" #: .././scrub/phase6.c:212 msgid "Disappeared during read error reporting." msgstr "ZnikÅ‚ podczas raportowania błędu odczytu." #: .././scrub/phase6.c:329 #, c-format msgid "disk offset %" msgstr "offset na dysku %" #: .././scrub/phase6.c:335 #, c-format msgid "%s failed read verification." msgstr "nie powiodÅ‚a siÄ™ weryfikacja odczytu %s." #: .././scrub/phase6.c:386 #, c-format msgid "dev %d:%d ioerr @ %:% " msgstr "urzÄ…dzenie %d:%d błąd we/wy @ %:% " #: .././scrub/phase6.c:489 msgid "Could not create media verifier." msgstr "Nie udaÅ‚o siÄ™ utworzyć weryfikatora noÅ›nika." #: .././scrub/phase7.c:183 msgid "data blocks" msgstr "bloki danych" #: .././scrub/phase7.c:185 msgid "realtime blocks" msgstr "bloki realtime" #: .././scrub/phase7.c:198 #, c-format msgid "%.1f%s data used; %.1f%s realtime data used; %.2f%s inodes used.\n" msgstr "" "używanych danych %.1f%s; używanych danych realtime %.1f%s; używanych i-" "wÄ™złów %.2f%s.\n" #: .././scrub/phase7.c:204 #, c-format msgid "%.1f%s data found; %.1f%s realtime data found; %.2f%s inodes found.\n" msgstr "" "znaleziono danych %.1f%s; znaleziono danych realtime %.1f%s; znaleziono i-" "wÄ™złów %.2f%s.\n" #: .././scrub/phase7.c:210 #, c-format msgid "%.1f%s data used; %.1f%s inodes used.\n" msgstr "używanych danych %.1f%s; używanych i-wÄ™złów %.1f%s.\n" #: .././scrub/phase7.c:215 #, c-format msgid "%.1f%s data found; %.1f%s inodes found.\n" msgstr "znaleziono danych %.1f%s; znaleziono i-wÄ™złów %.1f%s.\n" #: .././scrub/phase7.c:227 msgid "checked inodes" msgstr "sprawdzono i-wÄ™zÅ‚y" #: .././scrub/phase7.c:234 #, c-format msgid "%.1f%s inodes counted; %.1f%s inodes checked.\n" msgstr "naliczono i-wÄ™złów %.1f%s; sprawdzono i-wÄ™złów %.1f%s.\n" #: .././scrub/phase7.c:247 msgid "verified blocks" msgstr "zweryfikowano bloki" #: .././scrub/phase7.c:254 #, c-format msgid "%.1f%s data counted; %.1f%s data verified.\n" msgstr "naliczono danych %.1f%s; zweryfikowano danych %.1f%s.\n" #: .././scrub/progress.c:97 #, c-format msgid "%u % % %s" msgstr "%u % % %s" #: .././scrub/progress.c:119 #, c-format msgid "Phase %u: |" msgstr "Faza %u: |" #: .././scrub/read_verify.c:191 msgid "Could not queue read-verify work." msgstr "Nie udaÅ‚o siÄ™ skolejnować zadania odczytu-weryfikacji." #: .././scrub/scrub.c:117 #, c-format msgid "AG %u %s" msgstr "AG %u %s" #: .././scrub/scrub.c:121 #, c-format msgid "Inode % %s" msgstr "i-wÄ™zeÅ‚ % %s" #: .././scrub/scrub.c:179 msgid "Check incomplete." msgstr "Sprzedzenie niepeÅ‚ne." #: .././scrub/scrub.c:183 .././scrub/scrub.c:185 msgid "Possibly suspect metadata." msgstr "MogÄ… być podejrzane metadane." #: .././scrub/scrub.c:189 msgid "Cross-referencing failed." msgstr "Tworzenie odsyÅ‚aczy nie powiodÅ‚o siÄ™." #: .././scrub/scrub.c:223 .././scrub/scrub.c:730 msgid "Filesystem is shut down, aborting." msgstr "System plików jest zamkniÄ™ty, przerwano." #: .././scrub/scrub.c:239 #, c-format msgid "Kernel bug! errno=%d" msgstr "Błąd w jÄ…drze! errno=%d" #: .././scrub/scrub.c:270 msgid "Repairs are required." msgstr "Wymagane sÄ… naprawy." #: .././scrub/scrub.c:286 msgid "Optimization is possible." msgstr "Możliwa jest optymalizacja." #: .././scrub/scrub.c:317 #, c-format msgid "Optimizations of %s are possible." msgstr "Możliwe sÄ… optymalizacje elementów: %s." #: .././scrub/scrub.c:584 msgid "Filesystem is mounted read-only; cannot proceed." msgstr "System plików zamontowany tylko do odczytu; nie można kontynuować." #: .././scrub/scrub.c:588 msgid "Filesystem is mounted norecovery; cannot proceed." msgstr "System plików zamontowany z opcjÄ… norecovery; nie można kontynuować." #: .././scrub/scrub.c:594 #, c-format msgid "Kernel %s %s facility not detected." msgstr "Nie wykryto funkcji jÄ…dra %2$s elementu %1$s." #: .././scrub/scrub.c:596 msgid "repair" msgstr "naprawy" #: .././scrub/scrub.c:596 msgid "scrub" msgstr "doczyszczania" #: .././scrub/scrub.c:706 msgid "Attempting repair." msgstr "Próba naprawy." #: .././scrub/scrub.c:708 msgid "Attempting optimization." msgstr "Próba optymalizacji." #: .././scrub/scrub.c:725 msgid "Filesystem is busy, deferring repair." msgstr "System plików jest zajÄ™ty, opóźnianie naprawy." #: .././scrub/scrub.c:744 msgid "Don't know how to fix; offline repair required." msgstr "Nie wiem jak poprawić; wymagana naprawa offline." #: .././scrub/scrub.c:750 msgid "Read-only filesystem; cannot make changes." msgstr "System plików tylko do odczytu; nie można wykonać zmian." #: .././scrub/scrub.c:773 msgid "Repair unsuccessful; offline repair required." msgstr "Niepowodzenie naprawy; wymagana naprawa offline." #: .././scrub/scrub.c:777 msgid "Repairs successful." msgstr "Naprawy powiodÅ‚y siÄ™." #: .././scrub/scrub.c:779 msgid "Optimization successful." msgstr "Optymalizacja powiodÅ‚a siÄ™." #: .././scrub/spacemap.c:130 #, c-format msgid "dev %d:%d AG %u fsmap" msgstr "urzÄ…dzenie %d:%d AG %u, fsmap" #: .././scrub/spacemap.c:161 #, c-format msgid "dev %d:%d fsmap" msgstr "urzÄ…dzenie %d:%d, fsmap" #: .././scrub/spacemap.c:229 msgid "Could not queue rtdev fsmap work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania fsmap urzÄ…dzenia rt." #: .././scrub/spacemap.c:239 msgid "Could not queue logdev fsmap work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania fsmap urzÄ…dzenia logu." #: .././scrub/spacemap.c:248 #, c-format msgid "Could not queue AG %u fsmap work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania fsmap AG %u." #: .././scrub/unicrash.c:275 #, c-format msgid "Unicode name \"%s\" in %s should be normalized as \"%s\"." msgstr "Nazwa unikodowa \"%s\" w %s powinna być znormalizowana jako \"%s\"." #: .././scrub/unicrash.c:279 #, c-format msgid "Duplicate normalized Unicode name \"%s\" found in %s." msgstr "Napotkano powtórzonÄ… znormalizowanÄ… nazwÄ™ unikodowÄ… \"%s\" w %s." #: .././scrub/vfs.c:149 msgid "Could not queue subdirectory scan work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania skanowania podkatalogu." #: .././scrub/vfs.c:212 msgid "Could not queue directory scan work." msgstr "Nie udaÅ‚o siÄ™ skolejkować zadania skanowania katalogu." #: .././scrub/vfs.c:249 msgid "fstrim" msgstr "fstrim" #: .././scrub/xfs_scrub.c:176 #, c-format msgid "Usage: %s [OPTIONS] mountpoint | device\n" msgstr "SkÅ‚adnia: %s [OPCJE] punkt-montowania | urzÄ…dzenie\n" #: .././scrub/xfs_scrub.c:178 #, c-format msgid "Options:\n" msgstr "Opcje:\n" #: .././scrub/xfs_scrub.c:179 #, c-format msgid " -a count Stop after this many errors are found.\n" msgstr " -a liczba Zatrzymanie po napotkaniu podanej liczby błędów.\n" #: .././scrub/xfs_scrub.c:180 #, c-format msgid " -b Background mode.\n" msgstr " -b DziaÅ‚anie w tle.\n" #: .././scrub/xfs_scrub.c:181 #, c-format msgid " -C fd Print progress information to this fd.\n" msgstr " -C fd Wypisywanie informacji o postÄ™pie do podanego fd.\n" #: .././scrub/xfs_scrub.c:182 #, c-format msgid " -e behavior What to do if errors are found.\n" msgstr " -e zachowanie Co robić w przypadku znalezienia błędów.\n" #: .././scrub/xfs_scrub.c:183 #, c-format msgid " -k Do not FITRIM the free space.\n" msgstr " -k Bez wykonywania FITRIM dla wolnego miejsca.\n" #: .././scrub/xfs_scrub.c:184 #, c-format msgid " -m path Path to /etc/mtab.\n" msgstr " -m Å›cieżka Åšcieżka do /etc/mtab.\n" #: .././scrub/xfs_scrub.c:185 #, c-format msgid " -n Dry run. Do not modify anything.\n" msgstr " -n DziaÅ‚anie \"na sucho\", bez modyfikowania niczego.\n" #: .././scrub/xfs_scrub.c:186 #, c-format msgid " -T Display timing/usage information.\n" msgstr " -T WyÅ›wietlenie informacji o czasie/użyciu.\n" #: .././scrub/xfs_scrub.c:187 #, c-format msgid " -v Verbose output.\n" msgstr " -v Szczegółowe wyjÅ›cie.\n" #: .././scrub/xfs_scrub.c:188 #, c-format msgid " -V Print version.\n" msgstr " -V Wypisanie wersji.\n" #: .././scrub/xfs_scrub.c:189 #, c-format msgid " -x Scrub file data too.\n" msgstr " -x Doczyszczenie także danych plików.\n" #: .././scrub/xfs_scrub.c:273 .././scrub/xfs_scrub.c:324 msgid "getrusage" msgstr "getrusage" #: .././scrub/xfs_scrub.c:280 .././scrub/xfs_scrub.c:317 msgid "gettimeofday" msgstr "gettimeofday" #: .././scrub/xfs_scrub.c:286 #, c-format msgid "Phase %u: %s\n" msgstr "Faza %u: %s\n" #: .././scrub/xfs_scrub.c:329 #, c-format msgid "Phase %u: " msgstr "Faza %u: " #: .././scrub/xfs_scrub.c:337 #, c-format msgid "%sMemory used: %luk/%luk (%luk/%luk), " msgstr "%sUżyta pamięć: %luk/%luk (%luk/%luk), " #: .././scrub/xfs_scrub.c:342 #, c-format msgid "%sMemory used: %luk, " msgstr "%sUżyta pamięć: %luk, " #: .././scrub/xfs_scrub.c:349 #, c-format msgid "time: %5.2f/%5.2f/%5.2fs\n" msgstr "czas: %5.2f/%5.2f/%5.2fs\n" #: .././scrub/xfs_scrub.c:368 #, c-format msgid "%sI/O: %.1f%s in, %.1f%s out, %.1f%s tot\n" msgstr "%sWe/wy: we %.1f%s, wy %.1f%s, razem %.1f%s\n" #: .././scrub/xfs_scrub.c:371 #, c-format msgid "%sI/O rate: %.1f%s/s in, %.1f%s/s out, %.1f%s/s tot\n" msgstr "%sSzybkość we/wy: we %.1f%s/s, wy %.1f%s/s, razem %.1f%s/s\n" #: .././scrub/xfs_scrub.c:388 msgid "Find filesystem geometry." msgstr "Sprawdzanie geometrii systemu plików." #: .././scrub/xfs_scrub.c:393 msgid "Check internal metadata." msgstr "Sprawdzanie metadanych wewnÄ™trznych." #: .././scrub/xfs_scrub.c:398 msgid "Scan all inodes." msgstr "Skanowanie wszystkich i-wÄ™złów." #: .././scrub/xfs_scrub.c:403 msgid "Defer filesystem repairs." msgstr "Opóźnienie napraw systemu plików." #: .././scrub/xfs_scrub.c:408 msgid "Check directory tree." msgstr "Sprawdzenie drzewa katalogów." #: .././scrub/xfs_scrub.c:413 msgid "Verify data file integrity." msgstr "Weryfikacja integralnoÅ›ci plików danych." #: .././scrub/xfs_scrub.c:418 msgid "Check summary counters." msgstr "Sprawdzenie liczników podsumowaÅ„." #: .././scrub/xfs_scrub.c:445 msgid "Repair filesystem." msgstr "Naprawa systemu plików." #: .././scrub/xfs_scrub.c:478 #, c-format msgid "Scrub aborted after phase %d." msgstr "Doczyszczanie przerwane po fazie %d." #: .././scrub/xfs_scrub.c:508 #, c-format msgid "%s: warnings found: %llu\n" msgstr "%s: znaleziono ostrzeżeÅ„: %llu\n" #: .././scrub/xfs_scrub.c:511 #, c-format msgid "%s: errors found: %llu\n" msgstr "%s: znaleziono błędów: %llu\n" #: .././scrub/xfs_scrub.c:514 #, c-format msgid "%s: errors found: %llu; warnings found: %llu\n" msgstr "%s: znaleziono błędów: %llu; ostrzeżeÅ„: %llu\n" #: .././scrub/xfs_scrub.c:518 #, c-format msgid "%s: Unmount and run xfs_repair.\n" msgstr "%s: Konieczne odmontowanie i uruchomienie xfs_prepair.\n" #: .././scrub/xfs_scrub.c:583 #, c-format msgid "Unknown error behavior \"%s\".\n" msgstr "Nieznane zachowanie w przypadku błędów \"%s\".\n" #: .././scrub/xfs_scrub.c:676 #, c-format msgid "%s: Not a XFS mount point or block device.\n" msgstr "%s: To nie jest punkt montowania XFS-a ani urzÄ…dzenie blokowe.\n" #: .././scrub/xfs_scrub.c:708 msgid "Too many errors; aborting." msgstr "Zbyt dużo błędów; zakoÅ„czenie." #: .././scrub/xfs_scrub.c:711 msgid "Injecting error." msgstr "Wstrzykiwanie błędu." #: .././spaceman/file.c:40 #, c-format msgid "%c%03d%c %-14s\n" msgstr "%c%03d%c %-14s\n" #: .././spaceman/file.c:80 #, c-format msgid "%s: cannot find mount point." msgstr "%s: nie odnaleziono punktu montowania." #: .././spaceman/file.c:135 msgid "list current open files" msgstr "lista aktualnie otwartych plików" #: .././spaceman/freesp.c:58 #, c-format msgid "Too many histogram buckets.\n" msgstr "Zbyt dużo kubeÅ‚ków histogramu.\n" #: .././spaceman/freesp.c:177 #, c-format msgid "%s: fsmap malloc failed.\n" msgstr "%s: malloc dla fsmap nie powiodÅ‚o siÄ™.\n" #: .././spaceman/freesp.c:202 #, c-format msgid "%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n" msgstr "%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n" #: .././spaceman/freesp.c:236 #, c-format msgid " rtdev %10llu %10llu\n" msgstr " rtdev %10llu %10llu\n" #: .././spaceman/freesp.c:239 #, c-format msgid "%10u %10llu %10llu\n" msgstr "%10u %10llu %10llu\n" #: .././spaceman/freesp.c:254 #, c-format msgid "Unrecognized AG number: %s\n" msgstr "Nierozpoznany numer AG %s\n" #: .././spaceman/freesp.c:355 #, c-format msgid " AG extents blocks\n" msgstr " AG ekstenty bloki\n" #: .././spaceman/freesp.c:381 #, c-format msgid "" "\n" "Examine filesystem free space\n" "\n" " -a agno -- Scan only the given AG agno.\n" " -b -- binary histogram bin size\n" " -d -- debug output\n" " -e bsize -- Use fixed histogram bin size of bsize\n" " -g -- Print only a per-AG summary.\n" " -h hbsz -- Use custom histogram bin size of h1.\n" " Multiple specifications are allowed.\n" " -m bmult -- Use histogram bin size multiplier of bmult.\n" " -r -- Display realtime device free space information.\n" " -s -- Emit freespace summary information.\n" "\n" "Only one of -b, -e, -h, or -m may be specified.\n" "\n" msgstr "" "\n" "Zbadanie wolnego miejsca w systemie plików\n" "\n" " -a agno - przeszukanie tylko podanej AG.\n" " -b - rozmiar paczki binarnego histogramu.\n" " -d - wyjÅ›cie diagnostyczne.\n" " -e rozm - użycie danego staÅ‚ego rozmiaru paczki histogramu.\n" " -g - wypisanie tylko podsumowania dla AG.\n" " -h hbsz - użycie wÅ‚asnego rozmiaru paczki histogramu h1.\n" " Dozwolone jest wiele wartoÅ›co.\n" " -m mnoż - użycie danego mnożnika rozmiaru paczki histogramu.\n" " -r - wyÅ›wietlenie informacji o wolnym miejscu urzÄ…dzenia realtime.\n" " -s - informacje podsumowujÄ…ce wolne miejsce.\n" "\n" "Można wybrać tylko jedno z -b, -e, -h, -m.\n" #: .././spaceman/freesp.c:410 msgid "Examine filesystem free space" msgstr "Zbadanie wolnego miejsca w systemie plików" #: .././spaceman/init.c:33 #, c-format msgid "Usage: %s [-c cmd] file\n" msgstr "SkÅ‚adnia: %s [-c polecenie] plik\n" #: .././spaceman/init.c:102 #, c-format msgid "Not an XFS filesystem!\n" msgstr "To nie jest system plików XFS!\n" #: .././spaceman/prealloc.c:79 #, c-format msgid "%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n" msgstr "%s: XFS_IOC_FREE_EOFBLOCKS na %s: %s\n" #: .././spaceman/prealloc.c:89 #, c-format msgid "" "\n" "Remove speculative preallocation\n" "\n" " -g gid -- remove prealloc on files matching group \n" " -m minlen -- only consider files larger than \n" " -p prid -- remove prealloc on files matching project \n" " -s -- wait for removal to complete\n" " -u uid -- remove prealloc on files matching user \n" "\n" "If none of -u, -g, or -p are specified, this command acts on all files.\n" "minlen can take units.\n" "\n" msgstr "" "\n" "UsuniÄ™cie prealokacji heurystycznej\n" "\n" " -g gid - usuniÄ™cie prealokacji dla plików pasujÄ…cych do grupy \n" " -m minlen - uwzglÄ™dnienie tylko plików wiÄ™kszych niż \n" " -p prid - usuniÄ™cie prealokacji dla plików pasujÄ…cych do projektu \n" " -s - oczekiwanie na zakoÅ„czenie usuwania\n" " -u uid - usuniÄ™cie prealokacji dla plików pasujÄ…cych do użytkownika " "\n" "\n" "JeÅ›li nie podano żadnej z opcji -u, -g ani -p, to polecenie dziaÅ‚a na\n" "wszystkich plikach.\n" "minlen można podać w jednostkach.\n" #: .././spaceman/prealloc.c:114 msgid "Remove speculative preallocation" msgstr "UsuniÄ™cie prealokacji heurystycznej" #: .././spaceman/trim.c:53 #, c-format msgid "bad agno value %s\n" msgstr "błędna wartość agno %s\n" #: .././spaceman/trim.c:104 #, c-format msgid "" "\n" "Discard filesystem free space\n" "\n" " -a agno -- trim all the freespace in the given AG agno\n" " -f -- trim all the freespace in the entire filesystem\n" " offset length -- trim the freespace in the range {offset, length}\n" " -m minlen -- skip freespace extents smaller than minlen\n" "\n" "One of -a, -f, or the offset/length pair are required.\n" "\n" msgstr "" "\n" "Porzucenie wolnego miejsca w systemie plików\n" "\n" " -a agno - obciÄ™cie caÅ‚ego wolnego miejsca w podanej AG\n" " -f - obciÄ™cie caÅ‚ego wolnego miejsca w systemie plików\n" " offset dÅ‚ugość - obciÄ™cie wolnego miwjsca w podanym przedziale\n" " -m minlen - pominiÄ™cie ekstentów wolnego miejsca krótszych niż minlen\n" "\n" "Wymagana jest jedna z opcji -a, -f lub para offset/dÅ‚ugość.\n" "\n" #: .././spaceman/trim.c:127 msgid "Discard filesystem free space" msgstr "przeszukiwanie wolnego miejsca w systemie plików" xfsprogs-5.3.0/quota/Makefile0000644000175000017500000000142013435336037016041 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_quota HFILES = init.h quota.h CFILES = init.c util.c \ edit.c free.c linux.c path.c project.c quot.c quota.c report.c state.c LLDLIBS = $(LIBXCMD) $(LIBFROG) LTDEPENDENCIES = $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static ifeq ($(ENABLE_READLINE),yes) LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP) CFLAGS += -DENABLE_READLINE endif ifeq ($(ENABLE_EDITLINE),yes) LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP) CFLAGS += -DENABLE_EDITLINE endif default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/quota/edit.c0000644000175000017500000004052613466663244015513 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include #include "input.h" #include "command.h" #include "init.h" #include "quota.h" static cmdinfo_t limit_cmd; static cmdinfo_t restore_cmd; static cmdinfo_t timer_cmd; static cmdinfo_t warn_cmd; static void limit_help(void) { printf(_( "\n" " modify quota limits for the specified user\n" "\n" " Example:\n" " 'limit bsoft=100m bhard=110m tanya\n" "\n" " Changes the soft and/or hard block limits, inode limits and/or realtime\n" " block limits that are currently being used for the specified user, group,\n" " or project. The filesystem identified by the current path is modified.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota limits\n" " -p -- modify project quota limits\n" " -u -- modify user quota limits\n" " The block limit values can be specified with a units suffix - accepted\n" " units are: k (kilobytes), m (megabytes), g (gigabytes), and t (terabytes).\n" " The user/group/project can be specified either by name or by number.\n" "\n")); } static void timer_help(void) { printf(_( "\n" " modify quota enforcement timeout for the current filesystem\n" "\n" " Example:\n" " 'timer -i 3days'\n" " (soft inode limit timer is changed to 3 days)\n" "\n" " Changes the timeout value associated with the block limits, inode limits\n" " and/or realtime block limits for all users, groups, or projects on the\n" " current filesystem.\n" " As soon as a user consumes the amount of space or number of inodes set as\n" " the soft limit, a timer is started. If the timer expires and the user is\n" " still over the soft limit, the soft limit is enforced as the hard limit.\n" " The default timeout is 7 days.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota timer\n" " -p -- modify project quota timer\n" " -u -- modify user quota timer\n" " -b -- modify the blocks-used timer\n" " -i -- modify the inodes-used timer\n" " -r -- modify the blocks-used timer for the (optional) realtime subvolume\n" " The timeout value is specified as a number of seconds, by default.\n" " However, a suffix may be used to alternatively specify minutes (m),\n" " hours (h), days (d), or weeks (w) - either the full word or the first\n" " letter of the word can be used.\n" "\n")); } static void warn_help(void) { printf(_( "\n" " modify the number of quota warnings sent to the specified user\n" "\n" " Example:\n" " 'warn 2 jimmy'\n" " (tell the quota system that two warnings have been sent to user jimmy)\n" "\n" " Changes the warning count associated with the block limits, inode limits\n" " and/or realtime block limits for the specified user, group, or project.\n" " When a user has been warned the maximum number of times allowed, the soft\n" " limit is enforced as the hard limit. It is intended as an alternative to\n" " the timeout system, where the system administrator updates a count of the\n" " number of warnings issued to people, and they are penalised if the warnings\n" " are ignored.\n" " -d -- set maximum warning count, which triggers soft limit enforcement\n" " -g -- set group quota warning count\n" " -p -- set project quota warning count\n" " -u -- set user quota warning count\n" " -b -- set the blocks-used warning count\n" " -i -- set the inodes-used warning count\n" " -r -- set the blocks-used warn count for the (optional) realtime subvolume\n" " The user/group/project can be specified either by name or by number.\n" "\n")); } static void set_limits( uint32_t id, uint type, uint mask, char *dev, uint64_t *bsoft, uint64_t *bhard, uint64_t *isoft, uint64_t *ihard, uint64_t *rtbsoft, uint64_t *rtbhard) { fs_disk_quota_t d; memset(&d, 0, sizeof(d)); d.d_version = FS_DQUOT_VERSION; d.d_id = id; d.d_flags = type; d.d_fieldmask = mask; d.d_blk_hardlimit = *bhard; d.d_blk_softlimit = *bsoft; d.d_ino_hardlimit = *ihard; d.d_ino_softlimit = *isoft; d.d_rtb_hardlimit = *rtbhard; d.d_rtb_softlimit = *rtbsoft; if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set limits: %s\n"), progname, strerror(errno)); } } static void set_user_limits( char *name, uint type, uint mask, uint64_t *bsoft, uint64_t *bhard, uint64_t *isoft, uint64_t *ihard, uint64_t *rtbsoft, uint64_t *rtbhard) { uid_t uid = uid_from_string(name); if (uid == -1) { exitcode = 1; fprintf(stderr, _("%s: invalid user name: %s\n"), progname, name); } else set_limits(uid, type, mask, fs_path->fs_name, bsoft, bhard, isoft, ihard, rtbsoft, rtbhard); } static void set_group_limits( char *name, uint type, uint mask, uint64_t *bsoft, uint64_t *bhard, uint64_t *isoft, uint64_t *ihard, uint64_t *rtbsoft, uint64_t *rtbhard) { gid_t gid = gid_from_string(name); if (gid == -1) { exitcode = 1; fprintf(stderr, _("%s: invalid group name: %s\n"), progname, name); } else set_limits(gid, type, mask, fs_path->fs_name, bsoft, bhard, isoft, ihard, rtbsoft, rtbhard); } static void set_project_limits( char *name, uint type, uint mask, uint64_t *bsoft, uint64_t *bhard, uint64_t *isoft, uint64_t *ihard, uint64_t *rtbsoft, uint64_t *rtbhard) { prid_t prid = prid_from_string(name); if (prid == -1) { exitcode = 1; fprintf(stderr, _("%s: invalid project name: %s\n"), progname, name); } else set_limits(prid, type, mask, fs_path->fs_name, bsoft, bhard, isoft, ihard, rtbsoft, rtbhard); } /* extract number of blocks from an ascii string */ static int extractb( char *string, const char *prefix, int length, uint blocksize, uint sectorsize, uint64_t *value) { long long v; char *s = string; if (strncmp(string, prefix, length) == 0) { s = string + length + 1; v = cvtnum(blocksize, sectorsize, s); if (v == -1LL) { fprintf(stderr, _("%s: Error: could not parse size %s.\n"), progname, s); return 0; } *value = (uint64_t)v >> 9; /* syscalls use basic blocks */ if (v > 0 && *value == 0) fprintf(stderr, _("%s: Warning: `%s' in quota blocks is 0 (unlimited).\n"), progname, s); return 1; } return 0; } /* extract number of inodes from an ascii string */ static int extracti( char *string, const char *prefix, int length, uint64_t *value) { char *sp, *s = string; if (strncmp(string, prefix, length) == 0) { s = string + length + 1; *value = strtoll(s, &sp, 0); return 1; } return 0; } static int limit_f( int argc, char **argv) { char *name; uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard; int c, type = 0, mask = 0, flags = 0; uint bsize, ssize, endoptions; init_cvtnum(&bsize, &ssize); bsoft = bhard = isoft = ihard = rtbsoft = rtbhard = 0; while ((c = getopt(argc, argv, "dgpu")) != EOF) { switch (c) { case 'd': flags |= DEFAULTS_FLAG; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; default: return command_usage(&limit_cmd); } } /* * In the usual case, we need at least 2 more arguments - * one (or more) limits and a user name/id. * For setting defaults (-d) we don't want a user name/id. */ if (flags & DEFAULTS_FLAG) { if (argc < optind + 1) return command_usage(&limit_cmd); endoptions = 1; } else if (argc < optind + 2) { return command_usage(&limit_cmd); } else { endoptions = 2; } /* * Extract limit values from remaining optional arguments. */ while (argc > optind + endoptions - 1) { char *s = argv[optind++]; if (extractb(s, "bsoft=", 5, bsize, ssize, &bsoft)) mask |= FS_DQ_BSOFT; else if (extractb(s, "bhard=", 5, bsize, ssize, &bhard)) mask |= FS_DQ_BHARD; else if (extracti(s, "isoft=", 5, &isoft)) mask |= FS_DQ_ISOFT; else if (extracti(s, "ihard=", 5, &ihard)) mask |= FS_DQ_IHARD; else if (extractb(s, "rtbsoft=", 7, bsize, ssize, &rtbsoft)) mask |= FS_DQ_RTBSOFT; else if (extractb(s, "rtbhard=", 7, bsize, ssize, &rtbhard)) mask |= FS_DQ_RTBHARD; else { exitcode = 1; fprintf(stderr, _("%s: unrecognised argument %s\n"), progname, s); return 0; } } if (!mask) { exitcode = 1; fprintf(stderr, _("%s: cannot find any valid arguments\n"), progname); return 0; } name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++]; if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage(&limit_cmd); } switch (type) { case XFS_USER_QUOTA: set_user_limits(name, type, mask, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); break; case XFS_GROUP_QUOTA: set_group_limits(name, type, mask, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); break; case XFS_PROJ_QUOTA: set_project_limits(name, type, mask, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); break; } return 0; } /* * Iterate through input file, restoring the limits. * File format is as follows: * fs = * bsoft bhard isoft ihard [rtbsoft rtbhard] */ static void restore_file( FILE *fp, uint type) { char buffer[512]; char dev[512]; uint mask; int cnt; uint32_t id; uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard; while (fgets(buffer, sizeof(buffer), fp) != NULL) { if (strncmp("fs = ", buffer, 5) == 0) { /* * Copy the device name to dev, strip off the trailing * newline, and move on to the next line. */ strncpy(dev, buffer + 5, sizeof(dev) - 1); dev[strlen(dev) - 1] = '\0'; continue; } rtbsoft = rtbhard = 0; cnt = sscanf(buffer, "%u %llu %llu %llu %llu %llu %llu\n", &id, (unsigned long long *)&bsoft, (unsigned long long *)&bhard, (unsigned long long *)&isoft, (unsigned long long *)&ihard, (unsigned long long *)&rtbsoft, (unsigned long long *)&rtbhard); if (cnt == 5 || cnt == 7) { mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD; if (cnt == 7) mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD; set_limits(id, type, mask, dev, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); } } } static int restore_f( int argc, char **argv) { FILE *fp = stdin; char *fname = NULL; int c, type = 0; while ((c = getopt(argc, argv, "f:gpu")) != EOF) { switch (c) { case 'f': fname = optarg; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; default: return command_usage(&restore_cmd); } } if (argc < optind) return command_usage(&restore_cmd); if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage(&restore_cmd); } if (fname) { if ((fp = fopen(fname, "r")) == NULL) { exitcode = 1; fprintf(stderr, _("%s: fopen on %s failed: %s\n"), progname, fname, strerror(errno)); return 0; } } restore_file(fp, type); if (fname) fclose(fp); return 0; } static void set_timer( uint type, uint mask, char *dev, uint value) { fs_disk_quota_t d; memset(&d, 0, sizeof(d)); d.d_version = FS_DQUOT_VERSION; d.d_flags = type; d.d_fieldmask = mask; d.d_itimer = value; d.d_btimer = value; d.d_rtbtimer = value; if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set timer: %s\n"), progname, strerror(errno)); } } static int timer_f( int argc, char **argv) { uint value; int c, type = 0, mask = 0; while ((c = getopt(argc, argv, "bgipru")) != EOF) { switch (c) { case 'b': mask |= FS_DQ_BTIMER; break; case 'i': mask |= FS_DQ_ITIMER; break; case 'r': mask |= FS_DQ_RTBTIMER; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; default: return command_usage(&timer_cmd); } } if (argc != optind + 1) return command_usage(&timer_cmd); value = cvttime(argv[optind++]); if (!mask) mask = FS_DQ_TIMER_MASK; if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage(&timer_cmd); } set_timer(type, mask, fs_path->fs_name, value); return 0; } static void set_warnings( uint32_t id, uint type, uint mask, char *dev, uint value) { fs_disk_quota_t d; memset(&d, 0, sizeof(d)); d.d_version = FS_DQUOT_VERSION; d.d_id = id; d.d_flags = type; d.d_fieldmask = mask; d.d_iwarns = value; d.d_bwarns = value; d.d_rtbwarns = value; if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set warnings: %s\n"), progname, strerror(errno)); } } static void set_user_warnings( char *name, uint type, uint mask, uint value) { uid_t uid = uid_from_string(name); if (uid == -1) { exitcode = 1; fprintf(stderr, _("%s: invalid user name: %s\n"), progname, name); } else set_warnings(uid, type, mask, fs_path->fs_name, value); } static void set_group_warnings( char *name, uint type, uint mask, uint value) { gid_t gid = gid_from_string(name); if (gid == -1) { exitcode = 1; fprintf(stderr, _("%s: invalid group name: %s\n"), progname, name); } else set_warnings(gid, type, mask, fs_path->fs_name, value); } static void set_project_warnings( char *name, uint type, uint mask, uint value) { prid_t prid = prid_from_string(name); if (prid == -1) { exitcode = 1; fprintf(stderr, _("%s: invalid project name: %s\n"), progname, name); } else set_warnings(prid, type, mask, fs_path->fs_name, value); } static int warn_f( int argc, char **argv) { char *name; uint value; int c, flags = 0, type = 0, mask = 0; while ((c = getopt(argc, argv, "bdgipru")) != EOF) { switch (c) { case 'd': flags |= DEFAULTS_FLAG; break; case 'b': mask |= FS_DQ_BWARNS; break; case 'i': mask |= FS_DQ_IWARNS; break; case 'r': mask |= FS_DQ_RTBWARNS; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; default: return command_usage(&warn_cmd); } } /* * In the usual case, we need at least 2 more arguments - * one (or more) value and a user name/id. * For setting defaults (-d) we don't want a user name/id. */ if (flags & DEFAULTS_FLAG) { if (argc != optind + 1) return command_usage(&warn_cmd); } else if (argc != optind + 2) { return command_usage(&warn_cmd); } value = atoi(argv[optind++]); name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++]; if (!mask) mask = FS_DQ_WARNS_MASK; if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage(&warn_cmd); } switch (type) { case XFS_USER_QUOTA: set_user_warnings(name, type, mask, value); break; case XFS_GROUP_QUOTA: set_group_warnings(name, type, mask, value); break; case XFS_PROJ_QUOTA: set_project_warnings(name, type, mask, value); break; } return 0; } void edit_init(void) { limit_cmd.name = "limit"; limit_cmd.cfunc = limit_f; limit_cmd.argmin = 2; limit_cmd.argmax = -1; limit_cmd.args = \ _("[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name"); limit_cmd.oneline = _("modify quota limits"); limit_cmd.help = limit_help; limit_cmd.flags = CMD_FLAG_FOREIGN_OK; restore_cmd.name = "restore"; restore_cmd.cfunc = restore_f; restore_cmd.argmin = 0; restore_cmd.argmax = -1; restore_cmd.args = _("[-g|-p|-u] [-f file]"); restore_cmd.oneline = _("restore quota limits from a backup file"); restore_cmd.flags = CMD_FLAG_FOREIGN_OK; timer_cmd.name = "timer"; timer_cmd.cfunc = timer_f; timer_cmd.argmin = 2; timer_cmd.argmax = -1; timer_cmd.args = _("[-bir] [-g|-p|-u] value"); timer_cmd.oneline = _("set quota enforcement timeouts"); timer_cmd.help = timer_help; timer_cmd.flags = CMD_FLAG_FOREIGN_OK; warn_cmd.name = "warn"; warn_cmd.cfunc = warn_f; warn_cmd.argmin = 2; warn_cmd.argmax = -1; warn_cmd.args = _("[-bir] [-g|-p|-u] value -d|id|name"); warn_cmd.oneline = _("get/set enforcement warning counter"); warn_cmd.help = warn_help; if (expert) { add_command(&limit_cmd); add_command(&restore_cmd); add_command(&timer_cmd); add_command(&warn_cmd); } } xfsprogs-5.3.0/quota/free.c0000644000175000017500000002171313570057155015476 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "command.h" #include "init.h" #include "quota.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" static cmdinfo_t free_cmd; static void free_help(void) { printf(_( "\n" " reports the number of free disk blocks and inodes\n" "\n" " This command reports the number of total, used, and available disk blocks.\n" " It can optionally report the same set of numbers for inodes and realtime\n" " disk blocks, and will report on all known XFS filesystem mount points and\n" " project quota paths by default (see 'print' command for a list).\n" " -b -- report the block count values\n" " -i -- report the inode count values\n" " -r -- report the realtime block count values\n" " -h -- report in a human-readable format\n" " -N -- suppress the header from the output\n" "\n")); } /* * The data and realtime block counts returned (count, used, and * free) are all in basic block units. */ static int mount_free_space_data( struct fs_path *mount, uint64_t *bcount, uint64_t *bused, uint64_t *bfree, uint64_t *icount, uint64_t *iused, uint64_t *ifree, uint64_t *rcount, uint64_t *rused, uint64_t *rfree) { struct xfs_fsop_counts fscounts; struct xfs_fsop_geom fsgeo; struct statfs st; uint64_t logsize, count, free; int fd, ret; if ((fd = open(mount->fs_dir, O_RDONLY)) < 0) { exitcode = 1; fprintf(stderr, "%s: cannot open %s: %s\n", progname, mount->fs_dir, strerror(errno)); return 0; } if (platform_fstatfs(fd, &st) < 0) { perror("fstatfs"); close(fd); return 0; } if (!(mount->fs_flags & FS_FOREIGN)) { ret = -xfrog_geometry(fd, &fsgeo); if (ret) { xfrog_perror(ret, "XFS_IOC_FSGEOMETRY"); close(fd); return 0; } if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) { perror("XFS_IOC_FSCOUNTS"); close(fd); return 0; } logsize = fsgeo.logstart ? fsgeo.logblocks : 0; count = (fsgeo.datablocks - logsize) * fsgeo.blocksize; free = fscounts.freedata * fsgeo.blocksize; *bcount = BTOBB(count); *bfree = BTOBB(free); *bused = BTOBB(count - free); count = fsgeo.rtextents * fsgeo.rtextsize * fsgeo.blocksize; free = fscounts.freertx * fsgeo.rtextsize * fsgeo.blocksize; *rcount = BTOBB(count); *rfree = BTOBB(free); *rused = BTOBB(count - free); } else { count = st.f_blocks * st.f_bsize; free = st.f_bfree * st.f_bsize; *bcount = BTOBB(count); *bfree = BTOBB(free); *bused = BTOBB(count - free); *rcount = BTOBB(0); *rfree = BTOBB(0); *rused = BTOBB(0); } *icount = st.f_files; *ifree = st.f_ffree; *iused = st.f_files - st.f_ffree; close(fd); return 1; } /* * The data and realtime block counts returned (count, used, and * free) are all in basic block units. */ static int projects_free_space_data( struct fs_path *path, uint64_t *bcount, uint64_t *bused, uint64_t *bfree, uint64_t *icount, uint64_t *iused, uint64_t *ifree, uint64_t *rcount, uint64_t *rused, uint64_t *rfree) { fs_quota_stat_t qfs; fs_disk_quota_t d; struct fsxattr fsx; uint type = XFS_PROJ_QUOTA; char *dev = path->fs_name; int fd; if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, &qfs) < 0 || !(qfs.qs_flags & XFS_QUOTA_PDQ_ACCT)) return 0; if ((fd = open(path->fs_dir, O_RDONLY)) < 0) { exitcode = 1; fprintf(stderr, "%s: cannot open %s: %s\n", progname, path->fs_dir, strerror(errno)); return 0; } if ((xfsctl(path->fs_dir, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { exitcode = 1; perror("FS_IOC_FSGETXATTR"); close(fd); return 0; } if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) { exitcode = 1; fprintf(stderr, _("%s: project quota flag not set on %s\n"), progname, path->fs_dir); close(fd); return 0; } if (path->fs_prid != fsx.fsx_projid) { exitcode = 1; fprintf(stderr, _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"), progname, path->fs_prid, projects_file, fsx.fsx_projid, path->fs_dir); close(fd); return 0; } xfsquotactl(XFS_QSYNC, dev, type, fsx.fsx_projid, NULL); if (xfsquotactl(XFS_GETQUOTA, dev, type, fsx.fsx_projid, &d) < 0) { perror("XFS_GETQUOTA"); close(fd); return 0; } /* If no softlimit is set for any of blk/ino/rt, get actual usage */ if (!d.d_blk_softlimit || !d.d_ino_softlimit || !d.d_rtb_softlimit) { mount_free_space_data(path, bcount, bused, bfree, icount, iused, ifree, rcount, rused, rfree); } if (d.d_blk_softlimit) { *bcount = d.d_blk_softlimit; *bfree = (d.d_blk_softlimit - d.d_bcount); } *bused = d.d_bcount; if (d.d_ino_softlimit) { *icount = d.d_ino_softlimit; *ifree = (d.d_ino_softlimit - d.d_icount); } *iused = d.d_icount; if (d.d_rtb_softlimit) { *rcount = d.d_rtb_softlimit; *rfree = (d.d_rtb_softlimit - d.d_rtbcount); } *rused = d.d_rtbcount; close(fd); return 1; } static int free_space( FILE *fp, uint form, fs_path_t *path, uint flags) { uint64_t bcount, bused, bfree; uint64_t icount, iused, ifree; uint64_t rcount, rused, rfree; char a[8], s[8], u[8], p[8]; int count; count = (path->fs_flags & FS_PROJECT_PATH) ? projects_free_space_data(path, &bcount, &bused, &bfree, &icount, &iused, &ifree, &rcount, &rused, &rfree) : mount_free_space_data(path, &bcount, &bused, &bfree, &icount, &iused, &ifree, &rcount, &rused, &rfree); if (!count) return 0; if (!(flags & NO_HEADER_FLAG)) { fprintf(fp, (flags & HUMAN_FLAG) ? _("Filesystem ") : _("Filesystem ")); if (form & (XFS_BLOCK_QUOTA|XFS_RTBLOCK_QUOTA)) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Size Used Avail Use%%") : _(" 1K-blocks Used Available Use%%")); else if (form & XFS_INODE_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Inodes Used Free Use%%") : _(" Inodes IUsed IFree IUse%%")); fprintf(fp, _(" Pathname\n")); } if (flags & HUMAN_FLAG) { count = fprintf(fp, "%-12s", path->fs_name); if (count > 13) fprintf(fp, "\n%12s", " "); } else { count = fprintf(fp, "%-19s", path->fs_name); if (count > 20) fprintf(fp, "\n%19s", " "); } if (form & XFS_BLOCK_QUOTA) { if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %3s%%", bbs_to_string(bcount, s, sizeof(s)), bbs_to_string(bused, u, sizeof(u)), bbs_to_string(bfree, a, sizeof(a)), pct_to_string(bused, bcount, p, sizeof(p))); else fprintf(fp, " %10llu %10llu %10llu %3s%%", (unsigned long long)bcount >> 1, (unsigned long long)bused >> 1, (unsigned long long)bfree >> 1, pct_to_string(bused, bcount, p, sizeof(p))); } else if (form & XFS_INODE_QUOTA) { if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %3s%%", num_to_string(icount, s, sizeof(s)), num_to_string(iused, u, sizeof(u)), num_to_string(ifree, a, sizeof(a)), pct_to_string(iused, icount, p, sizeof(p))); else fprintf(fp, " %10llu %10llu %10llu %3s%%", (unsigned long long)icount, (unsigned long long)iused, (unsigned long long)ifree, pct_to_string(iused, icount, p, sizeof(p))); } else if (form & XFS_RTBLOCK_QUOTA) { if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %3s%%", bbs_to_string(rcount, s, sizeof(s)), bbs_to_string(rused, u, sizeof(u)), bbs_to_string(rfree, a, sizeof(a)), pct_to_string(rused, rcount, p, sizeof(p))); else fprintf(fp, " %10llu %10llu %10llu %3s%%", (unsigned long long)rcount >> 1, (unsigned long long)rused >> 1, (unsigned long long)rfree >> 1, pct_to_string(rused, rcount, p, sizeof(p))); } fprintf(fp, " %s\n", path->fs_dir); return 1; } static void free_space_list( FILE *fp, uint form, char *dir, uint flags) { fs_cursor_t cursor; fs_path_t *path; fs_cursor_initialise(dir, 0, &cursor); while ((path = fs_cursor_next_entry(&cursor))) { if (free_space(fp, form, path, flags)) flags |= NO_HEADER_FLAG; } } static int free_f( int argc, char **argv) { FILE *fp = NULL; char *fname = NULL; int c, flags = 0, form = 0; while ((c = getopt(argc, argv, "bf:hNir")) != EOF) { switch (c) { case 'f': fname = optarg; break; case 'b': form |= XFS_BLOCK_QUOTA; break; case 'i': form |= XFS_INODE_QUOTA; break; case 'r': form |= XFS_RTBLOCK_QUOTA; break; case 'h': flags |= HUMAN_FLAG; break; case 'N': flags |= NO_HEADER_FLAG; break; default: return command_usage(&free_cmd); } } if (!form) form = XFS_BLOCK_QUOTA; if ((fp = fopen_write_secure(fname)) == NULL) return 0; if (argc == optind) free_space_list(fp, form, NULL, flags); else while (argc > optind) free_space_list(fp, form, argv[optind++], flags); if (fname) fclose(fp); return 0; } void free_init(void) { free_cmd.name = "df"; free_cmd.altname = "free"; free_cmd.cfunc = free_f; free_cmd.argmin = 0; free_cmd.argmax = -1; free_cmd.args = _("[-bir] [-hN] [-f file]"); free_cmd.oneline = _("show free and used counts for blocks and inodes"); free_cmd.help = free_help; free_cmd.flags = CMD_FLAG_FOREIGN_OK; add_command(&free_cmd); } xfsprogs-5.3.0/quota/init.c0000644000175000017500000000746313570057155015526 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libfrog/paths.h" #include "command.h" #include "input.h" #include "init.h" char *progname; int exitcode; int expert; bool foreign_allowed = false; static char **projopts; /* table of project names (cmdline) */ static int nprojopts; /* number of entries in name table. */ static void add_project_opt( char *optarg) { nprojopts++; projopts = realloc(projopts, sizeof(char*) * nprojopts); if (!projopts) { perror("realloc"); exit(1); } projopts[nprojopts - 1] = optarg; } static void usage(void) { fprintf(stderr, _("Usage: %s [-V] [-x] [-f] [-p prog] [-c cmd]... [-d project]... [path]\n"), progname); exit(1); } void init_cvtnum( unsigned int *blocksize, unsigned int *sectsize) { *blocksize = 4096; *sectsize = 512; } static void init_commands(void) { edit_init(); free_init(); help_init(); path_init(); project_init(); quot_init(); quota_init(); quit_init(); report_init(); state_init(); } /* * This function allows xfs_quota commands to iterate across all discovered * quota enabled filesystems. Commands that should not iterate all filesystems * should specify CMD_FLAG_ONESHOT in their command flags. */ static int filesystem_iterator( int index) { if (index >= fs_count) return 0; do { fs_path = &fs_table[index++]; /* skip project quota entries */ if ((fs_path->fs_flags & FS_PROJECT_PATH)) continue; /* only consider foreign filesystems if told so */ if (!foreign_allowed && (fs_path->fs_flags & FS_FOREIGN)) continue; /* We can use this one */ break; } while (index < fs_count); if (fs_path->fs_flags & FS_PROJECT_PATH) return 0; if (!foreign_allowed && (fs_path->fs_flags & FS_FOREIGN)) return 0; if (index > fs_count) return 0; return index; } static int init_check_command( const cmdinfo_t *ct) { if (!fs_path) return 1; /* If it's an XFS filesystem, always run the command. */ if (!(fs_path->fs_flags & FS_FOREIGN)) return 1; /* If the user specified foreign filesystems are ok (-f), run cmd. */ if (foreign_allowed && (ct->flags & CMD_FLAG_FOREIGN_OK)) return 1; /* If cmd not allowed on foreign fs, regardless of -f flag, skip it. */ if (!(ct->flags & CMD_FLAG_FOREIGN_OK)) { fprintf(stderr, _("%s: command is for XFS filesystems only\n"), ct->name); return 0; } /* foreign fs, but cmd only allowed via -f flag. Skip it. */ fprintf(stderr, _("%s: foreign filesystem. Invoke xfs_quota with -f to enable.\n"), ct->name); return 0; } static void init( int argc, char **argv) { int c; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); while ((c = getopt(argc, argv, "c:d:D:fP:p:t:xV")) != EOF) { switch (c) { case 'c': /* commands */ add_user_command(optarg); break; case 'd': add_project_opt(optarg); break; case 'f': foreign_allowed = true; break; case 't': mtab_file = optarg; break; case 'D': projects_file = optarg; break; case 'P': projid_file = optarg; break; case 'p': progname = optarg; break; case 'x': expert++; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); default: usage(); } } fs_table_initialise(argc - optind, &argv[optind], nprojopts, projopts); free(projopts); init_commands(); add_command_iterator(filesystem_iterator); add_check_command(init_check_command); /* * Ensure that global commands don't end up with an invalid path pointer * by setting the default device at the first specified on the CLI */ if (argc != optind) fs_path = fs_table_lookup(argv[optind], FS_MOUNT_POINT); else fs_path = &fs_table[0]; } int main( int argc, char **argv) { init(argc, argv); command_loop(); return exitcode; } xfsprogs-5.3.0/quota/init.h0000644000175000017500000000077413435336037015530 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2005 Silicon Graphics, Inc. * All Rights Reserved. */ extern char *progname; extern int exitcode; extern int expert; extern bool foreign_allowed; extern void edit_init(void); extern void free_init(void); extern void path_init(void); extern void project_init(void); extern void quot_init(void); extern void quota_init(void); extern void report_init(void); extern void state_init(void); extern void init_cvtnum(unsigned int *, unsigned int *); xfsprogs-5.3.0/quota/linux.c0000644000175000017500000000214113435336037015705 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "quota.h" #include #ifndef PRJQUOTA #define PRJQUOTA 2 #endif static int xtype_to_qtype( uint type) { switch (type) { case XFS_USER_QUOTA: return USRQUOTA; case XFS_GROUP_QUOTA: return GRPQUOTA; case XFS_PROJ_QUOTA: return PRJQUOTA; } return 0; } static int xcommand_to_qcommand( uint command) { switch (command) { case XFS_QUOTAON: return Q_XQUOTAON; case XFS_QUOTAOFF: return Q_XQUOTAOFF; case XFS_GETQUOTA: return Q_XGETQUOTA; case XFS_GETNEXTQUOTA: return Q_XGETNEXTQUOTA; case XFS_SETQLIM: return Q_XSETQLIM; case XFS_GETQSTAT: return Q_XGETQSTAT; case XFS_GETQSTATV: return Q_XGETQSTATV; case XFS_QUOTARM: return Q_XQUOTARM; case XFS_QSYNC: return Q_XQUOTASYNC; } return 0; } int xfsquotactl( int command, const char *device, uint type, uint id, void *addr) { int qcommand, qtype; qtype = xtype_to_qtype(type); qcommand = xcommand_to_qcommand(command); return quotactl(QCMD(qcommand, qtype), device, id, addr); } xfsprogs-5.3.0/quota/path.c0000644000175000017500000000616213435336037015511 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "quota.h" static cmdinfo_t path_cmd; static cmdinfo_t print_cmd; static void printpath( struct fs_path *path, int index, int number, int braces) { fs_quota_stat_t qstat; fs_project_t *prj; int c; if (index == 0) { printf(_("%s%sFilesystem Pathname\n"), number ? _(" ") : "", foreign_allowed ? _(" ") : ""); } if (number) printf(_("%c%03d%c "), braces? '[':' ', index, braces? ']':' '); if (foreign_allowed) printf("%s", (path->fs_flags & FS_FOREIGN) ? "(F) " : " "); printf(_("%-19s %s"), path->fs_dir, path->fs_name); if (path->fs_flags & FS_PROJECT_PATH) { prj = getprprid(path->fs_prid); printf(_(" (project %u"), path->fs_prid); if (prj) printf(_(", %s"), prj->pr_name); printf(")"); } else if (xfsquotactl(XFS_GETQSTAT, path->fs_name, 0, 0, (void *)&qstat) == 0 && qstat.qs_flags) { c = 0; printf(" ("); if (qstat.qs_flags & XFS_QUOTA_UDQ_ENFD) c = printf("uquota"); else if (qstat.qs_flags & XFS_QUOTA_UDQ_ACCT) c = printf("uqnoenforce"); if (qstat.qs_flags & XFS_QUOTA_GDQ_ENFD) c = printf("%sgquota", c ? ", " : ""); else if (qstat.qs_flags & XFS_QUOTA_GDQ_ACCT) c = printf("%sgqnoenforce", c ? ", " : ""); if (qstat.qs_flags & XFS_QUOTA_PDQ_ENFD) printf("%spquota", c ? ", " : ""); else if (qstat.qs_flags & XFS_QUOTA_PDQ_ACCT) printf("%spqnoenforce", c ? ", " : ""); printf(")"); } printf("\n"); } static int pathlist_f(void) { int i; struct fs_path *path; for (i = 0; i < fs_count; i++) { path = &fs_table[i]; /* Table is ordered xfs first, then foreign */ if (path->fs_flags & FS_FOREIGN && !foreign_allowed) break; printpath(path, i, 1, path == fs_path); } return 0; } static int print_f( int argc, char **argv) { int i; struct fs_path *path; for (i = 0; i < fs_count; i++) { path = &fs_table[i]; if (path->fs_flags & FS_FOREIGN && !foreign_allowed) break; printpath(path, i, 0, 0); } return 0; } static int path_f( int argc, char **argv) { int i; int max = foreign_allowed ? fs_count : xfs_fs_count; if (fs_count == 0) { printf(_("No paths are available\n")); return 0; } if (argc <= 1) return pathlist_f(); i = atoi(argv[1]); if (i < 0 || i >= max) { printf(_("value %d is out of range (0-%d)\n"), i, max - 1); } else { fs_path = &fs_table[i]; pathlist_f(); } return 0; } void path_init(void) { path_cmd.name = "path"; path_cmd.altname = "paths"; path_cmd.args = _("[N]"); path_cmd.cfunc = path_f; path_cmd.argmin = 0; path_cmd.argmax = 1; path_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK; path_cmd.oneline = _("set current path, or show the list of paths"); print_cmd.name = "print"; print_cmd.altname = "p"; print_cmd.cfunc = print_f; print_cmd.argmin = 0; print_cmd.argmax = 0; print_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK; print_cmd.oneline = _("list known mount points and projects"); if (expert) add_command(&path_cmd); add_command(&print_cmd); } xfsprogs-5.3.0/quota/project.c0000644000175000017500000002213113570057155016216 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "command.h" #include "input.h" #include "init.h" #include "quota.h" static cmdinfo_t project_cmd; static prid_t prid; static int recurse_depth = -1; enum { CHECK_PROJECT = 0x1, SETUP_PROJECT = 0x2, CLEAR_PROJECT = 0x4, }; #define EXCLUDED_FILE_TYPES(x) \ (S_ISCHR((x)) \ || S_ISBLK((x)) \ || S_ISFIFO((x)) \ || S_ISLNK((x)) \ || S_ISSOCK((x))) static void project_help(void) { printf(_( "\n" " list projects or setup a project tree for tree quota management\n" "\n" " Example:\n" " 'project -c logfiles'\n" " (match project 'logfiles' to a directory, and setup the directory tree)\n" "\n" " Without arguments, report all projects found in the /etc/projects file.\n" " The project quota mechanism in XFS can be used to implement a form of\n" " directory tree quota, where a specified directory and all of the files\n" " and subdirectories below it (i.e. a tree) can be restricted to using a\n" " subset of the available space in the filesystem.\n" "\n" " A managed tree must be setup initially using the -s option with a project.\n" " The specified project name or identifier is matched to one or more trees\n" " defined in /etc/projects, and these trees are then recursively descended\n" " to mark the affected inodes as being part of that tree - which sets inode\n" " flags and the project identifier on every file.\n" " Once this has been done, new files created in the tree will automatically\n" " be accounted to the tree based on their project identifier. An attempt to\n" " create a hard link to a file in the tree will only succeed if the project\n" " identifier matches the project identifier for the tree. The xfs_io utility\n" " can be used to set the project ID for an arbitrary file, but this can only\n" " be done by a privileged user.\n" "\n" " A previously setup tree can be cleared from project quota control through\n" " use of the -C option, which will recursively descend the tree, clearing\n" " the affected inodes from project quota control.\n" "\n" " The -c option can be used to check whether a tree is setup, it reports\n" " nothing if the tree is correct, otherwise it reports the paths of inodes\n" " which do not have the project ID of the rest of the tree, or if the inode\n" " flag is not set.\n" "\n" " The -p option can be used to manually specify project path without\n" " need to create /etc/projects file. This option can be used multiple times\n" " to specify multiple paths. When using this option only one projid/name can\n" " be specified at command line. Note that /etc/projects is also used if exists.\n" "\n" " The -d option allows to descend at most levels of directories\n" " below the command line arguments. -d 0 means only apply the actions\n" " to the top level of the projects. -d -1 means no recursion limit (default).\n" "\n" " The /etc/projid and /etc/projects file formats are simple, and described\n" " on the xfs_quota man page.\n" "\n")); } static int check_project( const char *path, const struct stat *stat, int flag, struct FTW *data) { struct fsxattr fsx; int fd; if (recurse_depth >= 0 && data->level > recurse_depth) return 0; if (flag == FTW_NS ){ exitcode = 1; fprintf(stderr, _("%s: cannot stat file %s\n"), progname, path); return 0; } if (EXCLUDED_FILE_TYPES(stat->st_mode)) { fprintf(stderr, _("%s: skipping special file %s\n"), progname, path); return 0; } if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1) { exitcode = 1; fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); } else if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, path, strerror(errno)); } else { if (fsx.fsx_projid != prid) printf(_("%s - project identifier is not set" " (inode=%u, tree=%u)\n"), path, fsx.fsx_projid, (unsigned int)prid); if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) && S_ISDIR(stat->st_mode)) printf(_("%s - project inheritance flag is not set\n"), path); } if (fd != -1) close(fd); return 0; } static int clear_project( const char *path, const struct stat *stat, int flag, struct FTW *data) { struct fsxattr fsx; int fd; if (recurse_depth >= 0 && data->level > recurse_depth) return 0; if (flag == FTW_NS ){ exitcode = 1; fprintf(stderr, _("%s: cannot stat file %s\n"), progname, path); return 0; } if (EXCLUDED_FILE_TYPES(stat->st_mode)) { fprintf(stderr, _("%s: skipping special file %s\n"), progname, path); return 0; } if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1) { exitcode = 1; fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); return 0; } else if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, path, strerror(errno)); close(fd); return 0; } fsx.fsx_projid = 0; fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT; if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot clear project on %s: %s\n"), progname, path, strerror(errno)); } close(fd); return 0; } static int setup_project( const char *path, const struct stat *stat, int flag, struct FTW *data) { struct fsxattr fsx; int fd; if (recurse_depth >= 0 && data->level > recurse_depth) return 0; if (flag == FTW_NS ){ exitcode = 1; fprintf(stderr, _("%s: cannot stat file %s\n"), progname, path); return 0; } if (EXCLUDED_FILE_TYPES(stat->st_mode)) { fprintf(stderr, _("%s: skipping special file %s\n"), progname, path); return 0; } if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1) { exitcode = 1; fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); return 0; } else if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), progname, path, strerror(errno)); close(fd); return 0; } fsx.fsx_projid = prid; fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT; if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set project on %s: %s\n"), progname, path, strerror(errno)); } close(fd); return 0; } static void project_operations( char *project, char *dir, int type) { switch (type) { case CHECK_PROJECT: printf(_("Checking project %s (path %s)...\n"), project, dir); nftw(dir, check_project, 100, FTW_PHYS|FTW_MOUNT); break; case SETUP_PROJECT: printf(_("Setting up project %s (path %s)...\n"), project, dir); nftw(dir, setup_project, 100, FTW_PHYS|FTW_MOUNT); break; case CLEAR_PROJECT: printf(_("Clearing project %s (path %s)...\n"), project, dir); nftw(dir, clear_project, 100, FTW_PHYS|FTW_MOUNT); break; } } static void project( char *project, int type) { fs_cursor_t cursor; fs_path_t *path; int count = 0; fs_cursor_initialise(NULL, FS_PROJECT_PATH, &cursor); while ((path = fs_cursor_next_entry(&cursor))) { if (prid != path->fs_prid && path->fs_prid != -1) continue; project_operations(project, path->fs_dir, type); count++; } printf(_("Processed %d (%s and cmdline) paths for project %s with " "recursion depth %s (%d).\n"), count, projects_file, project, recurse_depth < 0 ? _("infinite") : _("limited"), recurse_depth); } static int project_f( int argc, char **argv) { int c, type = 0, ispath = 0; while ((c = getopt(argc, argv, "cd:p:sC")) != EOF) { switch (c) { case 'c': type = CHECK_PROJECT; break; case 'd': recurse_depth = atoi(optarg); if (recurse_depth < 0) recurse_depth = -1; break; case 'p': ispath = 1; fs_table_insert_project_path(optarg, -1); break; case 's': type = SETUP_PROJECT; break; case 'C': type = CLEAR_PROJECT; break; default: return command_usage(&project_cmd); } } if (argc == optind) return command_usage(&project_cmd); /* no options - just check the given projects */ if (!type) type = CHECK_PROJECT; setprfiles(); if (!ispath && access(projects_file, F_OK) != 0) { exitcode = 1; fprintf(stderr, _("projects file \"%s\" doesn't exist\n"), projects_file); return 0; } if (ispath && argc - optind > 1) { exitcode = 1; fprintf(stderr, _("%s: only one projid/name can be specified " "when using -p , %d found.\n"), progname, argc - optind); return 0; } while (argc > optind) { prid = prid_from_string(argv[optind]); if (prid == -1) { exitcode = 1; fprintf(stderr, _("%s - no such project in %s " "or invalid project number\n"), argv[optind], projects_file); } else project(argv[optind], type); optind++; } return 0; } void project_init(void) { project_cmd.name = "project"; project_cmd.altname = "tree"; project_cmd.cfunc = project_f; project_cmd.args = _("[-c|-s|-C|-d |-p ] project ..."); project_cmd.argmin = 1; project_cmd.argmax = -1; project_cmd.oneline = _("check, setup or clear project quota trees"); project_cmd.help = project_help; project_cmd.flags = CMD_FLAG_FOREIGN_OK; if (expert) add_command(&project_cmd); } xfsprogs-5.3.0/quota/quot.c0000644000175000017500000002111713570057155015543 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "command.h" #include #include #include #include "init.h" #include "quota.h" #include "libfrog/logging.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" typedef struct du { struct du *next; uint64_t blocks; uint64_t blocks30; uint64_t blocks60; uint64_t blocks90; uint64_t nfiles; uint32_t id; } du_t; #define TSIZE 500 static uint64_t sizes[TSIZE]; static uint64_t overflow; #define NDU 60000 #define DUHASH 8209 static du_t du[3][NDU]; static du_t *duhash[3][DUHASH]; static int ndu[3]; /* #usr/grp/prj */ #define NBSTAT 4069 static time_t now; static cmdinfo_t quot_cmd; static void quot_help(void) { printf(_( "\n" " display a summary of filesystem ownership\n" "\n" " -a -- summarise for all local XFS filesystem mount points\n" " -c -- display three columns giving file size in kilobytes, number of files\n" " of that size, and cumulative total of kilobytes in that size or\n" " smaller file. The last row is used as an overflow bucket and is the\n" " total of all files greater than 500 kilobytes.\n" " -v -- display three columns containing the number of kilobytes not\n" " accessed in the last 30, 60, and 90 days.\n" " -g -- display group summary\n" " -p -- display project summary\n" " -u -- display user summary\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n")); } static void quot_bulkstat_add( struct xfs_bulkstat *p, uint flags) { du_t *dp; du_t **hp; uint64_t size; uint32_t i, id; if ((p->bs_mode & S_IFMT) == 0) return; size = howmany((p->bs_blocks * p->bs_blksize), 0x400ULL); if (flags & HISTOGRAM_FLAG) { if (!(S_ISDIR(p->bs_mode) || S_ISREG(p->bs_mode))) return; if (size >= TSIZE) { overflow += size; size = TSIZE - 1; } sizes[(int)size]++; return; } for (i = 0; i < 3; i++) { id = (i == 0) ? p->bs_uid : ((i == 1) ? p->bs_gid : p->bs_projectid); hp = &duhash[i][id % DUHASH]; for (dp = *hp; dp; dp = dp->next) if (dp->id == id) break; if (dp == NULL) { if (ndu[i] >= NDU) return; dp = &du[i][(ndu[i]++)]; dp->next = *hp; *hp = dp; dp->id = id; dp->nfiles = 0; dp->blocks = 0; dp->blocks30 = 0; dp->blocks60 = 0; dp->blocks90 = 0; } dp->blocks += size; if (now - p->bs_atime > 30 * (60*60*24)) dp->blocks30 += size; if (now - p->bs_atime > 60 * (60*60*24)) dp->blocks60 += size; if (now - p->bs_atime > 90 * (60*60*24)) dp->blocks90 += size; dp->nfiles++; } } static void quot_bulkstat_mount( char *fsdir, unsigned int flags) { struct xfs_fd fsxfd = XFS_FD_INIT_EMPTY; struct xfs_bulkstat_req *breq; int i, sts, ret; du_t **dp; /* * Initialize tables between checks; because of the qsort * in report() the hash tables must be rebuilt each time. */ for (sts = 0; sts < TSIZE; sts++) sizes[sts] = 0; overflow = 0; for (i = 0; i < 3; i++) for (dp = duhash[i]; dp < &duhash[i][DUHASH]; dp++) *dp = NULL; ndu[0] = ndu[1] = ndu[2] = 0; ret = -xfd_open(&fsxfd, fsdir, O_RDONLY); if (ret) { xfrog_perror(ret, fsdir); return; } ret = -xfrog_bulkstat_alloc_req(NBSTAT, 0, &breq); if (ret) { xfrog_perror(ret, "calloc"); xfd_close(&fsxfd); return; } while ((sts = -xfrog_bulkstat(&fsxfd, breq)) == 0) { if (breq->hdr.ocount == 0) break; for (i = 0; i < breq->hdr.ocount; i++) quot_bulkstat_add(&breq->bulkstat[i], flags); } if (sts < 0) xfrog_perror(sts, "XFS_IOC_FSBULKSTAT"); free(breq); xfd_close(&fsxfd); } static int qcompare( du_t *p1, du_t *p2) { if (p1->blocks > p2->blocks) return -1; if (p1->blocks < p2->blocks) return 1; if (p1->id > p2->id) return 1; else if (p1->id < p2->id) return -1; return 0; } typedef char *(*idtoname_t)(uint32_t); static void quot_report_mount_any_type( FILE *fp, du_t *dp, int count, idtoname_t names, uint form, uint type, fs_path_t *mount, uint flags) { char *cp; fprintf(fp, _("%s (%s) %s:\n"), mount->fs_name, mount->fs_dir, type_to_string(type)); qsort(dp, count, sizeof(dp[0]), (int (*)(const void *, const void *))qcompare); for (; dp < &dp[count]; dp++) { if (dp->blocks == 0) return; fprintf(fp, "%8llu ", (unsigned long long) dp->blocks); if (form & XFS_INODE_QUOTA) fprintf(fp, "%8llu ", (unsigned long long) dp->nfiles); if (!(flags & NO_LOOKUP_FLAG) && ((cp = (names)(dp->id)) != NULL)) fprintf(fp, "%-8.8s", cp); else fprintf(fp, "#%-7d", dp->id); if (flags & VERBOSE_FLAG) fprintf(fp, " %8llu %8llu %8llu", (unsigned long long) dp->blocks30, (unsigned long long) dp->blocks60, (unsigned long long) dp->blocks90); fputc('\n', fp); } } static void quot_report_mount( FILE *fp, uint form, uint type, fs_path_t *mount, uint flags) { switch (type) { case XFS_GROUP_QUOTA: quot_report_mount_any_type(fp, du[1], ndu[1], gid_to_name, form, type, mount, flags); break; case XFS_PROJ_QUOTA: quot_report_mount_any_type(fp, du[2], ndu[2], prid_to_name, form, type, mount, flags); break; case XFS_USER_QUOTA: quot_report_mount_any_type(fp, du[0], ndu[0], uid_to_name, form, type, mount, flags); } } static void quot_report( FILE *fp, uint form, uint type, char *dir, uint flags) { fs_cursor_t cursor; fs_path_t *mount; now = time(NULL); fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) { quot_bulkstat_mount(mount->fs_dir, flags); quot_report_mount(fp, form, type, mount, flags); } } static void quot_histogram_mount( FILE *fp, fs_path_t *mount, uint flags) { uint64_t t = 0; int i; fprintf(fp, _("%s (%s):\n"), mount->fs_name, mount->fs_dir); for (i = 0; i < TSIZE - 1; i++) if (sizes[i] > 0) { t += sizes[i] * i; fprintf(fp, _("%d\t%llu\t%llu\n"), i, (unsigned long long) sizes[i], (unsigned long long) t); } fprintf(fp, _("%d\t%llu\t%llu\n"), TSIZE - 1, (unsigned long long) sizes[TSIZE - 1], (unsigned long long) (overflow + t)); } static void quot_histogram( FILE *fp, char *dir, uint flags) { fs_cursor_t cursor; fs_path_t *mount; fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) { quot_bulkstat_mount(mount->fs_dir, flags); quot_histogram_mount(fp, mount, flags); } } static void quot_any_type( FILE *fp, uint form, uint type, char *dir, uint flags) { if (flags & HISTOGRAM_FLAG) quot_histogram(fp, dir, flags); else quot_report(fp, form, type, dir, flags); } static int quot_f( int argc, char **argv) { FILE *fp = NULL; char *fname = NULL; int c, flags = 0, type = 0, form = 0; while ((c = getopt(argc, argv, "abcf:ghinpruv")) != EOF) { switch (c) { case 'f': fname = optarg; break; case 'b': form |= XFS_BLOCK_QUOTA; break; case 'i': form |= XFS_INODE_QUOTA; break; case 'r': form |= XFS_RTBLOCK_QUOTA; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; case 'a': flags |= ALL_MOUNTS_FLAG; break; case 'c': flags |= HISTOGRAM_FLAG; break; case 'n': flags |= NO_LOOKUP_FLAG; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage("_cmd); } } if (!form) form = XFS_BLOCK_QUOTA; if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage("_cmd); } if ((fp = fopen_write_secure(fname)) == NULL) return 0; if (argc == optind) { if (flags & ALL_MOUNTS_FLAG) quot_any_type(fp, form, type, NULL, flags); else if (fs_path->fs_flags & FS_MOUNT_POINT) quot_any_type(fp, form, type, fs_path->fs_dir, flags); } else while (argc > optind) { quot_any_type(fp, form, type, argv[optind++], flags); } if (fname) fclose(fp); return 0; } void quot_init(void) { quot_cmd.name = "quot"; quot_cmd.cfunc = quot_f; quot_cmd.argmin = 0; quot_cmd.argmax = -1; quot_cmd.args = _("[-bir] [-g|-p|-u] [-acv] [-f file]"); quot_cmd.oneline = _("summarize filesystem ownership"); quot_cmd.help = quot_help; if (expert) add_command("_cmd); } xfsprogs-5.3.0/quota/quota.c0000644000175000017500000002376713435336037015720 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "command.h" #include #include #include #include "init.h" #include "quota.h" static cmdinfo_t quota_cmd; static void quota_help(void) { printf(_( "\n" " display usage and quota information\n" "\n" " -g -- display group quota information\n" " -p -- display project quota information\n" " -u -- display user quota information\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -v -- increase verbosity in reporting (also dumps zero values)\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n")); } static int quota_mount( FILE *fp, uint32_t id, char *name, uint form, uint type, fs_path_t *mount, uint flags) { fs_disk_quota_t d; char *dev = mount->fs_name; char c[8], h[8], s[8]; uint qflags; int count; xfsquotactl(XFS_QSYNC, dev, type, 0, NULL); if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) return 0; if (!(flags & VERBOSE_FLAG)) { count = 0; if ((form & XFS_BLOCK_QUOTA) && d.d_bcount) count++; if ((form & XFS_INODE_QUOTA) && d.d_icount) count++; if ((form & XFS_RTBLOCK_QUOTA) && d.d_rtbcount) count++; if (!count) return 0; } if (!(flags & NO_HEADER_FLAG)) { fprintf(fp, _("Disk quotas for %s %s (%u)\nFilesystem%s"), type_to_string(type), name, id, (flags & HUMAN_FLAG) ? " " : " "); if (form & XFS_BLOCK_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Blocks Quota Limit Warn/Time ") : _(" Blocks Quota Limit Warn/Time ")); if (form & XFS_INODE_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Files Quota Limit Warn/Time ") : _(" Files Quota Limit Warn/Time ")); if (form & XFS_RTBLOCK_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _("Realtime Quota Limit Warn/Time ") : _(" Realtime Quota Limit Warn/Time ")); fputs("Mounted on\n", fp); } if (flags & HUMAN_FLAG) { count = fprintf(fp, "%-12s", dev); if (count > 13) fprintf(fp, "\n%12s", " "); } else { count = fprintf(fp, "%-19s", dev); if (count > 20) fprintf(fp, "\n%19s", " "); } if (form & XFS_BLOCK_QUOTA) { qflags = (flags & HUMAN_FLAG); if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit) qflags |= LIMIT_FLAG; if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit) qflags |= QUOTA_FLAG; if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %02d %8s ", bbs_to_string(d.d_bcount, c, sizeof(c)), bbs_to_string(d.d_blk_softlimit, s, sizeof(s)), bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)), d.d_bwarns, time_to_string(d.d_btimer, qflags)); else fprintf(fp, " %10llu %10llu %10llu %02d %9s ", (unsigned long long)d.d_bcount >> 1, (unsigned long long)d.d_blk_softlimit >> 1, (unsigned long long)d.d_blk_hardlimit >> 1, d.d_bwarns, time_to_string(d.d_btimer, qflags)); } if (form & XFS_INODE_QUOTA) { qflags = (flags & HUMAN_FLAG); if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit) qflags |= LIMIT_FLAG; if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit) qflags |= QUOTA_FLAG; if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %02d %8s ", num_to_string(d.d_icount, c, sizeof(c)), num_to_string(d.d_ino_softlimit, s, sizeof(s)), num_to_string(d.d_ino_hardlimit, h, sizeof(h)), d.d_iwarns, time_to_string(d.d_itimer, qflags)); else fprintf(fp, " %10llu %10llu %10llu %02d %9s ", (unsigned long long)d.d_icount, (unsigned long long)d.d_ino_softlimit, (unsigned long long)d.d_ino_hardlimit, d.d_iwarns, time_to_string(d.d_itimer, qflags)); } if (form & XFS_RTBLOCK_QUOTA) { qflags = (flags & HUMAN_FLAG); if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit) qflags |= LIMIT_FLAG; if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit) qflags |= QUOTA_FLAG; if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %02d %8s ", bbs_to_string(d.d_rtbcount, c, sizeof(c)), bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)), bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)), d.d_rtbwarns, time_to_string(d.d_rtbtimer, qflags)); else fprintf(fp, " %10llu %10llu %10llu %02d %9s ", (unsigned long long)d.d_rtbcount >> 1, (unsigned long long)d.d_rtb_softlimit >> 1, (unsigned long long)d.d_rtb_hardlimit >> 1, d.d_rtbwarns, time_to_string(d.d_rtbtimer, qflags)); } fprintf(fp, "%s\n", mount->fs_dir); return 1; } static void quota( FILE *fp, uint32_t id, char *name, uint form, uint type, uint flags) { fs_cursor_t cursor; fs_path_t *path; fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor); while ((path = fs_cursor_next_entry(&cursor))) { if (quota_mount(fp, id, name, form, type, path, flags)) flags |= NO_HEADER_FLAG; } } static char * getusername( uid_t uid, int numeric) { static char buffer[32]; if (!numeric) { struct passwd *u = getpwuid(uid); if (u) return u->pw_name; } snprintf(buffer, sizeof(buffer), "#%u", uid); return &buffer[0]; } static void quota_user_type( FILE *fp, char *name, uint form, uint type, uint flags) { struct passwd *u; uid_t id; if (name) { if (isdigits_only(name)) { id = atoi(name); name = getusername(id, flags & NO_LOOKUP_FLAG); } else if ((u = getpwnam(name))) { id = u->pw_uid; name = u->pw_name; } else { exitcode = 1; fprintf(stderr, _("%s: cannot find user %s\n"), progname, name); return; } } else { id = getuid(); name = getusername(id, flags & NO_LOOKUP_FLAG); } quota(fp, id, name, form, type, flags); } static char * getgroupname( gid_t gid, int numeric) { static char buffer[32]; if (!numeric) { struct group *g = getgrgid(gid); if (g) return g->gr_name; } snprintf(buffer, sizeof(buffer), "#%u", gid); return &buffer[0]; } static void quota_group_type( FILE *fp, char *name, uint form, uint type, uint flags) { struct group *g; gid_t gid, *gids = NULL; int i, ngroups, dofree = 0; if (name) { if (isdigits_only(name)) { gid = atoi(name); name = getgroupname(gid, flags & NO_LOOKUP_FLAG); } else { if ((g = getgrnam(name))) { gid = g->gr_gid; name = g->gr_name; } else { exitcode = 1; fprintf(stderr, _("%s: cannot find group %s\n"), progname, name); return; } } gids = &gid; ngroups = 1; } else { if ( ((ngroups = sysconf(_SC_NGROUPS_MAX)) < 0) || ((gids = malloc(ngroups * sizeof(gid_t))) == NULL) || ((ngroups = getgroups(ngroups, gids)) < 0)) { /* something failed. Fall back to 1 group */ free(gids); gid = getgid(); gids = &gid; ngroups = 1; } else { /* It all worked, and we allocated memory */ dofree = 1; } } for (i = 0; i < ngroups; i++, name = NULL) { if (!name) name = getgroupname(gids[i], flags & NO_LOOKUP_FLAG); quota(fp, gids[i], name, form, type, flags); } if (dofree) free(gids); } static char * getprojectname( prid_t prid, int numeric) { static char buffer[32]; if (!numeric) { fs_project_t *p = getprprid(prid); if (p) return p->pr_name; } snprintf(buffer, sizeof(buffer), "#%u", (unsigned int)prid); return &buffer[0]; } static void quota_proj_type( FILE *fp, char *name, uint form, uint type, uint flags) { fs_project_t *p; prid_t id; if (!name) { exitcode = 1; fprintf(stderr, _("%s: must specify a project name/ID\n"), progname); return; } if (isdigits_only(name)) { id = atoi(name); name = getprojectname(id, flags & NO_LOOKUP_FLAG); } else if ((p = getprnam(name))) { id = p->pr_prid; name = p->pr_name; } else { exitcode = 1; fprintf(stderr, _("%s: cannot find project %s\n"), progname, name); return; } quota(fp, id, name, form, type, flags); } static void quota_any_type( FILE *fp, char *name, uint form, uint type, uint flags) { switch (type) { case XFS_USER_QUOTA: quota_user_type(fp, name, form, type, flags); break; case XFS_GROUP_QUOTA: quota_group_type(fp, name, form, type, flags); break; case XFS_PROJ_QUOTA: quota_proj_type(fp, name, form, type, flags); break; } } static int quota_f( int argc, char **argv) { FILE *fp = NULL; char *fname = NULL; int c, flags = 0, type = 0, form = 0; while ((c = getopt(argc, argv, "bf:ghnNipruv")) != EOF) { switch (c) { case 'f': fname = optarg; break; case 'b': form |= XFS_BLOCK_QUOTA; break; case 'i': form |= XFS_INODE_QUOTA; break; case 'r': form |= XFS_RTBLOCK_QUOTA; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; case 'h': flags |= HUMAN_FLAG; break; case 'n': flags |= NO_LOOKUP_FLAG; break; case 'N': flags |= NO_HEADER_FLAG; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage("a_cmd); } } if (!form) form = XFS_BLOCK_QUOTA; if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage("a_cmd); } if ((fp = fopen_write_secure(fname)) == NULL) return 0; if (argc == optind) quota_any_type(fp, NULL, form, type, flags); else while (argc > optind) quota_any_type(fp, argv[optind++], form, type, flags); if (fname) fclose(fp); return 0; } void quota_init(void) { quota_cmd.name = "quota"; quota_cmd.altname = "l"; quota_cmd.cfunc = quota_f; quota_cmd.argmin = 0; quota_cmd.argmax = -1; quota_cmd.args = _("[-bir] [-g|-p|-u] [-hnNv] [-f file] [id|name]..."); quota_cmd.oneline = _("show usage and limits"); quota_cmd.help = quota_help; quota_cmd.flags = CMD_FLAG_FOREIGN_OK; add_command("a_cmd); } xfsprogs-5.3.0/quota/quota.h0000644000175000017500000000446213570057155015715 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "xqm.h" #include "libfrog/paths.h" #include "libfrog/projects.h" #include /* * Different forms of XFS quota */ enum { XFS_BLOCK_QUOTA = 0x1, XFS_INODE_QUOTA = 0x2, XFS_RTBLOCK_QUOTA = 0x4, }; /* * System call definitions mapping to platform-specific quotactl */ extern int xfsquotactl(int __cmd, const char *__device, uint __type, uint __id, void * __addr); enum { XFS_QUOTAON, /* enable accounting/enforcement */ XFS_QUOTAOFF, /* disable accounting/enforcement */ XFS_GETQUOTA, /* get disk limits and usage */ XFS_SETQLIM, /* set disk limits */ XFS_GETQSTAT, /* get quota subsystem status */ XFS_QUOTARM, /* free disk space used by dquots */ XFS_QSYNC, /* flush delayed allocate space */ XFS_GETQSTATV, /* newer version of quota stats */ XFS_GETNEXTQUOTA, /* get disk limits and usage */ }; /* * Utility routines */ extern char *type_to_string(uint __type); extern char *form_to_string(uint __form); extern char *time_to_string(time_t __time, uint __flags); extern char *bbs_to_string(uint64_t __v, char *__c, uint __size); extern char *num_to_string(uint64_t __v, char *__c, uint __size); extern char *pct_to_string(uint64_t __v, uint64_t __t, char *__c, uint __s); extern FILE *fopen_write_secure(char *__filename); /* * Various utility routine flags */ enum { NO_HEADER_FLAG = 0x0001, /* don't print header */ VERBOSE_FLAG = 0x0002, /* increase verbosity */ HUMAN_FLAG = 0x0004, /* human-readable values */ QUOTA_FLAG = 0x0008, /* uid/gid/prid over-quota (soft) */ LIMIT_FLAG = 0x0010, /* uid/gid/prid over-limit (hard) */ ALL_MOUNTS_FLAG = 0x0020, /* iterate over every mounted xfs */ TERSE_FLAG = 0x0040, /* decrease verbosity */ HISTOGRAM_FLAG = 0x0080, /* histogram format output */ DEFAULTS_FLAG = 0x0100, /* use value as a default */ ABSOLUTE_FLAG = 0x0200, /* absolute time, not related to now */ NO_LOOKUP_FLAG = 0x0400, /* skip name lookups, just report ID */ GETNEXTQUOTA_FLAG = 0x0800, /* use getnextquota quotactl */ }; /* * Identifier (uid/gid/prid) cache routines */ #define NMAX 32 extern char *uid_to_name(uint32_t __uid); extern char *gid_to_name(uint32_t __gid); extern char *prid_to_name(uint32_t __prid); extern bool isdigits_only(const char *); xfsprogs-5.3.0/quota/report.c0000644000175000017500000004430113435336037016065 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "command.h" #include #include #include #include #include "init.h" #include "quota.h" static cmdinfo_t dump_cmd; static cmdinfo_t report_cmd; static void dump_help(void) { dump_cmd.args = _("[-g|-p|-u] [-f file]"); dump_cmd.oneline = _("dump quota information for backup utilities"); printf(_( "\n" " create a backup file which contains quota limits information\n" " -g -- dump out group quota limits\n" " -p -- dump out project quota limits\n" " -u -- dump out user quota limits (default)\n" " -f -- write the dump out to the specified file\n" "\n")); } static void report_help(void) { report_cmd.args = _("[-bir] [-gpu] [-ahntlLNU] [-f file]"); report_cmd.oneline = _("report filesystem quota information"); printf(_( "\n" " report used space and inodes, and quota limits, for a filesystem\n" " Example:\n" " 'report -igh'\n" " (reports inode usage for all groups, in an easy-to-read format)\n" " This command is the equivalent of the traditional repquota command, which\n" " prints a summary of the disk usage and quotas for the current filesystem,\n" " or all filesystems.\n" " -a -- report for all mounted filesystems with quota enabled\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the header from the output\n" " -t -- terse output format, hides rows which are all zero\n" " -L -- lower ID bound to report on\n" " -U -- upper ID bound to report on\n" " -l -- look up names for IDs in lower-upper range\n" " -g -- report group usage and quota information\n" " -p -- report project usage and quota information\n" " -u -- report user usage and quota information\n" " -b -- report blocks-used information only\n" " -i -- report inodes-used information only\n" " -r -- report realtime-blocks-used information only\n" "\n")); } static int dump_file( FILE *fp, uint id, uint *oid, uint type, char *dev, int flags) { fs_disk_quota_t d; int cmd; if (flags & GETNEXTQUOTA_FLAG) cmd = XFS_GETNEXTQUOTA; else cmd = XFS_GETQUOTA; /* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA */ if (xfsquotactl(cmd, dev, type, id, (void *)&d) < 0) { if (errno != ENOENT && errno != ENOSYS && errno != ESRCH && cmd == XFS_GETQUOTA) perror("XFS_GETQUOTA"); return 0; } if (oid) { *oid = d.d_id; /* Did kernelspace wrap? */ if (*oid < id) return 0; } if (!d.d_blk_softlimit && !d.d_blk_hardlimit && !d.d_ino_softlimit && !d.d_ino_hardlimit && !d.d_rtb_softlimit && !d.d_rtb_hardlimit) return 1; fprintf(fp, "fs = %s\n", dev); /* this branch is for backward compatibility reasons */ if (d.d_rtb_softlimit || d.d_rtb_hardlimit) fprintf(fp, "%-10d %7llu %7llu %7llu %7llu %7llu %7llu\n", d.d_id, (unsigned long long)d.d_blk_softlimit, (unsigned long long)d.d_blk_hardlimit, (unsigned long long)d.d_ino_softlimit, (unsigned long long)d.d_ino_hardlimit, (unsigned long long)d.d_rtb_softlimit, (unsigned long long)d.d_rtb_hardlimit); else fprintf(fp, "%-10d %7llu %7llu %7llu %7llu\n", d.d_id, (unsigned long long)d.d_blk_softlimit, (unsigned long long)d.d_blk_hardlimit, (unsigned long long)d.d_ino_softlimit, (unsigned long long)d.d_ino_hardlimit); return 1; } static void dump_limits_any_type( FILE *fp, uint type, char *dir, uint lower, uint upper) { fs_path_t *mount; uint id = 0, oid; if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) { exitcode = 1; fprintf(stderr, "%s: cannot find mount point %s\n", progname, dir); return; } /* Range was specified; query everything in it */ if (upper) { for (id = lower; id <= upper; id++) dump_file(fp, id, NULL, type, mount->fs_name, 0); return; } /* Use GETNEXTQUOTA if it's available */ if (dump_file(fp, id, &oid, type, mount->fs_name, GETNEXTQUOTA_FLAG)) { id = oid + 1; while (dump_file(fp, id, &oid, type, mount->fs_name, GETNEXTQUOTA_FLAG)) id = oid + 1; return; } /* Otherwise fall back to iterating over each uid/gid/prjid */ switch (type) { case XFS_GROUP_QUOTA: { struct group *g; setgrent(); while ((g = getgrent()) != NULL) dump_file(fp, g->gr_gid, NULL, type, mount->fs_name, 0); endgrent(); break; } case XFS_PROJ_QUOTA: { struct fs_project *p; setprent(); while ((p = getprent()) != NULL) dump_file(fp, p->pr_prid, NULL, type, mount->fs_name, 0); endprent(); break; } case XFS_USER_QUOTA: { struct passwd *u; setpwent(); while ((u = getpwent()) != NULL) dump_file(fp, u->pw_uid, NULL, type, mount->fs_name, 0); endpwent(); break; } } } static int dump_f( int argc, char **argv) { FILE *fp; char *fname = NULL; uint lower = 0, upper = 0; int c, type = 0; while ((c = getopt(argc, argv, "f:gpuL:U:")) != EOF) { switch(c) { case 'f': fname = optarg; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; case 'L': lower = (uint)atoi(optarg); break; case 'U': upper = (uint)atoi(optarg); break; default: return command_usage(&dump_cmd); } } if (argc != optind) return command_usage(&dump_cmd); if (!type) { type = XFS_USER_QUOTA; } else if (type != XFS_GROUP_QUOTA && type != XFS_PROJ_QUOTA && type != XFS_USER_QUOTA) { return command_usage(&dump_cmd); } if ((fp = fopen_write_secure(fname)) == NULL) return 0; dump_limits_any_type(fp, type, fs_path->fs_dir, lower, upper); if (fname) fclose(fp); return 0; } static void report_header( FILE *fp, uint form, uint type, fs_path_t *mount, int flags) { char *typename = type_to_string(type); char scratch[64]; uint i, count; if (flags & NO_HEADER_FLAG) return; /* line 1 */ fprintf(fp, _("%s quota on %s (%s)\n"), typename, mount->fs_dir, mount->fs_name); /* line 2 */ for (i = 0; i < 10; i++) fputc(' ', fp); if (form & XFS_BLOCK_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? "%13c %s %13c" : "%20c %s %20c", ' ', form_to_string(XFS_BLOCK_QUOTA), ' '); if (form & XFS_INODE_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? "%13c %s %13c" : "%20c %s %20c", ' ', form_to_string(XFS_INODE_QUOTA), ' '); if (form & XFS_RTBLOCK_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? "%9c %s %9c" : "%15c %s %15c", ' ', form_to_string(XFS_RTBLOCK_QUOTA), ' '); fputc('\n', fp); /* line 3 */ snprintf(scratch, sizeof(scratch), "%s ID", typename); fprintf(fp, "%-10s ", scratch); if (form & XFS_BLOCK_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Used Soft Hard Warn/Grace ") : _(" Used Soft Hard Warn/Grace ")); if (form & XFS_INODE_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Used Soft Hard Warn/Grace ") : _(" Used Soft Hard Warn/ Grace ")); if (form & XFS_RTBLOCK_QUOTA) fprintf(fp, (flags & HUMAN_FLAG) ? _(" Used Soft Hard Warn/Grace ") : _(" Used Soft Hard Warn/Grace ")); fputc('\n', fp); /* line 4 */ for (i = 0; i < 10; i++) fputc('-', fp); fputc(' ', fp); count = (flags & HUMAN_FLAG) ? 33 : 50; if (form & XFS_BLOCK_QUOTA) { for (i = 0; i < count; i++) fputc('-', fp); fputc(' ', fp); } if (form & XFS_INODE_QUOTA) { for (i = 0; i < count; i++) fputc('-', fp); fputc(' ', fp); } if (form & XFS_RTBLOCK_QUOTA) { for (i = 0; i < count; i++) fputc('-', fp); fputc(' ', fp); } fputc('\n', fp); } static int report_mount( FILE *fp, uint32_t id, char *name, uint32_t *oid, uint form, uint type, fs_path_t *mount, uint flags) { fs_disk_quota_t d; char *dev = mount->fs_name; char c[8], h[8], s[8]; uint qflags; int count; int cmd; if (flags & GETNEXTQUOTA_FLAG) cmd = XFS_GETNEXTQUOTA; else cmd = XFS_GETQUOTA; /* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA*/ if (xfsquotactl(cmd, dev, type, id, (void *)&d) < 0) { if (errno != ENOENT && errno != ENOSYS && errno != ESRCH && cmd == XFS_GETQUOTA) perror("XFS_GETQUOTA"); return 0; } if (oid) { *oid = d.d_id; /* Did kernelspace wrap? */ if (* oid < id) return 0; } if (flags & TERSE_FLAG) { count = 0; if ((form & XFS_BLOCK_QUOTA) && d.d_bcount) count++; if ((form & XFS_INODE_QUOTA) && d.d_icount) count++; if ((form & XFS_RTBLOCK_QUOTA) && d.d_rtbcount) count++; if (!count) return 0; } if (!(flags & NO_HEADER_FLAG)) report_header(fp, form, type, mount, flags); if (flags & NO_LOOKUP_FLAG) { fprintf(fp, "#%-10u", d.d_id); } else { if (name == NULL) { if (type == XFS_USER_QUOTA) { struct passwd *u = getpwuid(d.d_id); if (u) name = u->pw_name; } else if (type == XFS_GROUP_QUOTA) { struct group *g = getgrgid(d.d_id); if (g) name = g->gr_name; } else if (type == XFS_PROJ_QUOTA) { fs_project_t *p = getprprid(d.d_id); if (p) name = p->pr_name; } } /* If no name is found, print the id #num instead of (null) */ if (name != NULL) fprintf(fp, "%-10s", name); else fprintf(fp, "#%-9u", d.d_id); } if (form & XFS_BLOCK_QUOTA) { qflags = (flags & HUMAN_FLAG); if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit) qflags |= LIMIT_FLAG; if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit) qflags |= QUOTA_FLAG; if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %02d %8s", bbs_to_string(d.d_bcount, c, sizeof(c)), bbs_to_string(d.d_blk_softlimit, s, sizeof(s)), bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)), d.d_bwarns, time_to_string(d.d_btimer, qflags)); else fprintf(fp, " %10llu %10llu %10llu %02d %9s", (unsigned long long)d.d_bcount >> 1, (unsigned long long)d.d_blk_softlimit >> 1, (unsigned long long)d.d_blk_hardlimit >> 1, d.d_bwarns, time_to_string(d.d_btimer, qflags)); } if (form & XFS_INODE_QUOTA) { qflags = (flags & HUMAN_FLAG); if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit) qflags |= LIMIT_FLAG; if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit) qflags |= QUOTA_FLAG; if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %02d %8s", num_to_string(d.d_icount, c, sizeof(c)), num_to_string(d.d_ino_softlimit, s, sizeof(s)), num_to_string(d.d_ino_hardlimit, h, sizeof(h)), d.d_iwarns, time_to_string(d.d_itimer, qflags)); else fprintf(fp, " %10llu %10llu %10llu %02d %9s", (unsigned long long)d.d_icount, (unsigned long long)d.d_ino_softlimit, (unsigned long long)d.d_ino_hardlimit, d.d_iwarns, time_to_string(d.d_itimer, qflags)); } if (form & XFS_RTBLOCK_QUOTA) { qflags = (flags & HUMAN_FLAG); if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit) qflags |= LIMIT_FLAG; if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit) qflags |= QUOTA_FLAG; if (flags & HUMAN_FLAG) fprintf(fp, " %6s %6s %6s %02d %8s", bbs_to_string(d.d_rtbcount, c, sizeof(c)), bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)), bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)), d.d_rtbwarns, time_to_string(d.d_rtbtimer, qflags)); else fprintf(fp, " %10llu %10llu %10llu %02d %9s", (unsigned long long)d.d_rtbcount >> 1, (unsigned long long)d.d_rtb_softlimit >> 1, (unsigned long long)d.d_rtb_hardlimit >> 1, d.d_rtbwarns, time_to_string(d.d_rtbtimer, qflags)); } fputc('\n', fp); return 1; } static void report_user_mount( FILE *fp, uint form, fs_path_t *mount, uint lower, uint upper, uint flags) { struct passwd *u; uint id = 0, oid; if (upper) { /* identifier range specified */ for (id = lower; id <= upper; id++) { if (report_mount(fp, id, NULL, NULL, form, XFS_USER_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } } else if (report_mount(fp, id, NULL, &oid, form, XFS_USER_QUOTA, mount, flags|GETNEXTQUOTA_FLAG)) { id = oid + 1; flags |= GETNEXTQUOTA_FLAG; flags |= NO_HEADER_FLAG; while (report_mount(fp, id, NULL, &oid, form, XFS_USER_QUOTA, mount, flags)) { id = oid + 1; } } else { setpwent(); while ((u = getpwent()) != NULL) { if (report_mount(fp, u->pw_uid, u->pw_name, NULL, form, XFS_USER_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } endpwent(); } if (flags & NO_HEADER_FLAG) fputc('\n', fp); } static void report_group_mount( FILE *fp, uint form, fs_path_t *mount, uint lower, uint upper, uint flags) { struct group *g; uint id = 0, oid; if (upper) { /* identifier range specified */ for (id = lower; id <= upper; id++) { if (report_mount(fp, id, NULL, NULL, form, XFS_GROUP_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } } else if (report_mount(fp, id, NULL, &oid, form, XFS_GROUP_QUOTA, mount, flags|GETNEXTQUOTA_FLAG)) { id = oid + 1; flags |= GETNEXTQUOTA_FLAG; flags |= NO_HEADER_FLAG; while (report_mount(fp, id, NULL, &oid, form, XFS_GROUP_QUOTA, mount, flags)) { id = oid + 1; } } else { setgrent(); while ((g = getgrent()) != NULL) { if (report_mount(fp, g->gr_gid, g->gr_name, NULL, form, XFS_GROUP_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } } if (flags & NO_HEADER_FLAG) fputc('\n', fp); endgrent(); } static void report_project_mount( FILE *fp, uint form, fs_path_t *mount, uint lower, uint upper, uint flags) { fs_project_t *p; uint id = 0, oid; if (upper) { /* identifier range specified */ for (id = lower; id <= upper; id++) { if (report_mount(fp, id, NULL, NULL, form, XFS_PROJ_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } } else if (report_mount(fp, id, NULL, &oid, form, XFS_PROJ_QUOTA, mount, flags|GETNEXTQUOTA_FLAG)) { id = oid + 1; flags |= GETNEXTQUOTA_FLAG; flags |= NO_HEADER_FLAG; while (report_mount(fp, id, NULL, &oid, form, XFS_PROJ_QUOTA, mount, flags)) { id = oid + 1; } } else { if (!getprprid(0)) { /* * Print default project quota, even if projid 0 * isn't defined */ if (report_mount(fp, 0, NULL, NULL, form, XFS_PROJ_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } setprent(); while ((p = getprent()) != NULL) { if (report_mount(fp, p->pr_prid, p->pr_name, NULL, form, XFS_PROJ_QUOTA, mount, flags)) flags |= NO_HEADER_FLAG; } endprent(); } if (flags & NO_HEADER_FLAG) fputc('\n', fp); } static void report_any_type( FILE *fp, uint form, uint type, char *dir, uint lower, uint upper, uint flags) { fs_cursor_t cursor; fs_path_t *mount; if (type & XFS_USER_QUOTA) { fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) { if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN)) continue; if (xfsquotactl(XFS_QSYNC, mount->fs_name, XFS_USER_QUOTA, 0, NULL) < 0 && errno != ENOENT && errno != ENOSYS) perror("XFS_QSYNC user quota"); report_user_mount(fp, form, mount, lower, upper, flags); } } if (type & XFS_GROUP_QUOTA) { fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) { if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN)) continue; if (xfsquotactl(XFS_QSYNC, mount->fs_name, XFS_GROUP_QUOTA, 0, NULL) < 0 && errno != ENOENT && errno != ENOSYS) perror("XFS_QSYNC group quota"); report_group_mount(fp, form, mount, lower, upper, flags); } } if (type & XFS_PROJ_QUOTA) { fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) { if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN)) continue; if (xfsquotactl(XFS_QSYNC, mount->fs_name, XFS_PROJ_QUOTA, 0, NULL) < 0 && errno != ENOENT && errno != ENOSYS) perror("XFS_QSYNC proj quota"); report_project_mount(fp, form, mount, lower, upper, flags); } } } static int report_f( int argc, char **argv) { FILE *fp = NULL; char *fname = NULL; uint lower = 0, upper = 0; bool lookup = false; int c, flags = 0, type = 0, form = 0; while ((c = getopt(argc, argv, "abdf:ghilL:NnprtuU:")) != EOF) { switch (c) { case 'f': fname = optarg; break; case 'b': form |= XFS_BLOCK_QUOTA; break; case 'i': form |= XFS_INODE_QUOTA; break; case 'r': form |= XFS_RTBLOCK_QUOTA; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; case 'a': flags |= ALL_MOUNTS_FLAG; break; case 'h': flags |= HUMAN_FLAG; break; case 'n': flags |= NO_LOOKUP_FLAG; break; case 'N': flags |= NO_HEADER_FLAG; break; case 't': flags |= TERSE_FLAG; break; case 'L': lower = (uint)atoi(optarg); flags |= NO_LOOKUP_FLAG; break; case 'U': upper = (uint)atoi(optarg); flags |= NO_LOOKUP_FLAG; break; case 'l': lookup = true; break; default: return command_usage(&report_cmd); } } if (!form) form = XFS_BLOCK_QUOTA; if (!type) type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA; if (lookup) flags &= ~NO_LOOKUP_FLAG; if ((fp = fopen_write_secure(fname)) == NULL) return 0; if (argc == optind) { if (flags & ALL_MOUNTS_FLAG) report_any_type(fp, form, type, NULL, lower, upper, flags); else if (fs_path && (fs_path->fs_flags & FS_MOUNT_POINT)) report_any_type(fp, form, type, fs_path->fs_dir, lower, upper, flags); } else while (argc > optind) { report_any_type(fp, form, type, argv[optind++], lower, upper, flags); } if (fname) fclose(fp); return 0; } void report_init(void) { dump_cmd.name = "dump"; dump_cmd.cfunc = dump_f; dump_cmd.argmin = 0; dump_cmd.argmax = -1; dump_cmd.args = _("[-g|-p|-u] [-f file]"); dump_cmd.oneline = _("dump quota information for backup utilities"); dump_cmd.help = dump_help; dump_cmd.flags = CMD_FLAG_FOREIGN_OK; report_cmd.name = "report"; report_cmd.altname = "repquota"; report_cmd.cfunc = report_f; report_cmd.argmin = 0; report_cmd.argmax = -1; report_cmd.args = _("[-bir] [-gpu] [-ahnt] [-f file]"); report_cmd.oneline = _("report filesystem quota information"); report_cmd.help = report_help; report_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK; if (expert) { add_command(&dump_cmd); add_command(&report_cmd); } } xfsprogs-5.3.0/quota/state.c0000644000175000017500000003510513435336037015674 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include "command.h" #include "init.h" #include "quota.h" static cmdinfo_t off_cmd; static cmdinfo_t state_cmd; static cmdinfo_t enable_cmd; static cmdinfo_t disable_cmd; static cmdinfo_t remove_cmd; static void off_help(void) { printf(_( "\n" " turn filesystem quota off, both accounting and enforcement\n" "\n" " Example:\n" " 'off -uv' (switch off user quota on the current filesystem)\n" " This command is the equivalent of the traditional quotaoff command,\n" " which disables quota completely on a mounted filesystem.\n" " Note that there is no 'on' command - for XFS filesystems (with the\n" " exception of the root filesystem on IRIX) quota can only be enabled\n" " at mount time, through the use of one of the quota mount options.\n" "\n" " The state command is useful for displaying the current state. Using\n" " the -v (verbose) option with the 'off' command will display the quota\n" " state for the affected filesystem once the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n")); } static void state_help(void) { printf(_( "\n" " query the state of quota on the current filesystem\n" "\n" " This is a verbose status command, reporting whether or not accounting\n" " and/or enforcement are enabled for a filesystem, which inodes are in\n" " use as the quota state inodes, and how many extents and blocks are\n" " presently being used to hold that information.\n" " The quota type is specified via -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n")); } static void enable_help(void) { printf(_( "\n" " enable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and has quota accounting enabled, but not\n" " quota enforcement, enforcement can be enabled with this command.\n" " With the -v (verbose) option, the status of the filesystem will be\n" " reported after the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n")); } static void disable_help(void) { printf(_( "\n" " disable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and is currently enforcing quota, this\n" " provides a mechanism to switch off the enforcement, but continue to\n" " perform used space (and used inodes) accounting.\n" " The affected quota type is -g (groups), -p (projects) or -u (users).\n" "\n")); } static void remove_help(void) { printf(_( "\n" " remove any space being used by the quota subsystem\n" "\n" " Once quota has been switched 'off' on a filesystem, the space that\n" " was allocated to holding quota metadata can be freed via this command.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n")); } static void state_qfilestat( FILE *fp, struct fs_path *mount, uint type, struct fs_qfilestatv *qfs, int accounting, int enforcing) { fprintf(fp, _("%s quota state on %s (%s)\n"), type_to_string(type), mount->fs_dir, mount->fs_name); fprintf(fp, _(" Accounting: %s\n"), accounting ? _("ON") : _("OFF")); fprintf(fp, _(" Enforcement: %s\n"), enforcing ? _("ON") : _("OFF")); if (qfs->qfs_ino != (__u64) -1) fprintf(fp, _(" Inode: #%llu (%llu blocks, %lu extents)\n"), (unsigned long long)qfs->qfs_ino, (unsigned long long)qfs->qfs_nblks, (unsigned long)qfs->qfs_nextents); else fprintf(fp, _(" Inode: N/A\n")); } static void state_timelimit( FILE *fp, uint form, uint32_t timelimit) { fprintf(fp, _("%s grace time: %s\n"), form_to_string(form), time_to_string(timelimit, VERBOSE_FLAG | ABSOLUTE_FLAG)); } /* * fs_quota_stat holds a subset of fs_quota_statv; this copies * the smaller into the larger, leaving any not-present fields * empty. This is so the same reporting function can be used * for both XFS_GETQSTAT and XFS_GETQSTATV results. */ static void state_stat_to_statv( struct fs_quota_stat *s, struct fs_quota_statv *sv) { memset(sv, 0, sizeof(struct fs_quota_statv)); /* shared information */ sv->qs_version = s->qs_version; sv->qs_flags = s->qs_flags; sv->qs_incoredqs = s->qs_incoredqs; sv->qs_btimelimit = s->qs_btimelimit; sv->qs_itimelimit = s->qs_itimelimit; sv->qs_rtbtimelimit = s->qs_rtbtimelimit; sv->qs_bwarnlimit = s->qs_bwarnlimit; sv->qs_iwarnlimit = s->qs_iwarnlimit; /* Always room for uquota */ sv->qs_uquota.qfs_ino = s->qs_uquota.qfs_ino; sv->qs_uquota.qfs_nblks = s->qs_uquota.qfs_nblks; sv->qs_uquota.qfs_nextents = s->qs_uquota.qfs_nextents; /* * If we are here, XFS_GETQSTATV failed and XFS_GETQSTAT passed; * that is a very strong hint that we're on a kernel which predates * the on-disk pquota inode; both were added in v3.12. So, we do * some tricksy determination here. * gs_gquota may hold either group quota inode info, or project * quota if that is used instead; which one it actually holds depends * on the quota flags. (If neither is set, neither is used) */ if (s->qs_flags & XFS_QUOTA_GDQ_ACCT) { /* gs_gquota holds group quota info */ sv->qs_gquota.qfs_ino = s->qs_gquota.qfs_ino; sv->qs_gquota.qfs_nblks = s->qs_gquota.qfs_nblks; sv->qs_gquota.qfs_nextents = s->qs_gquota.qfs_nextents; } else if (s->qs_flags & XFS_QUOTA_PDQ_ACCT) { /* gs_gquota actually holds project quota info */ sv->qs_pquota.qfs_ino = s->qs_gquota.qfs_ino; sv->qs_pquota.qfs_nblks = s->qs_gquota.qfs_nblks; sv->qs_pquota.qfs_nextents = s->qs_gquota.qfs_nextents; } } static void state_quotafile_mount( FILE *fp, uint type, struct fs_path *mount, uint flags) { struct fs_quota_stat s; struct fs_quota_statv sv; char *dev = mount->fs_name; sv.qs_version = FS_QSTATV_VERSION1; if (xfsquotactl(XFS_GETQSTATV, dev, type, 0, (void *)&sv) < 0) { if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)&s) < 0) { if (flags & VERBOSE_FLAG) fprintf(fp, _("%s quota are not enabled on %s\n"), type_to_string(type), dev); return; } state_stat_to_statv(&s, &sv); } if (type & XFS_USER_QUOTA) state_qfilestat(fp, mount, XFS_USER_QUOTA, &sv.qs_uquota, sv.qs_flags & XFS_QUOTA_UDQ_ACCT, sv.qs_flags & XFS_QUOTA_UDQ_ENFD); if (type & XFS_GROUP_QUOTA) state_qfilestat(fp, mount, XFS_GROUP_QUOTA, &sv.qs_gquota, sv.qs_flags & XFS_QUOTA_GDQ_ACCT, sv.qs_flags & XFS_QUOTA_GDQ_ENFD); if (type & XFS_PROJ_QUOTA) state_qfilestat(fp, mount, XFS_PROJ_QUOTA, &sv.qs_pquota, sv.qs_flags & XFS_QUOTA_PDQ_ACCT, sv.qs_flags & XFS_QUOTA_PDQ_ENFD); state_timelimit(fp, XFS_BLOCK_QUOTA, sv.qs_btimelimit); state_timelimit(fp, XFS_INODE_QUOTA, sv.qs_itimelimit); state_timelimit(fp, XFS_RTBLOCK_QUOTA, sv.qs_rtbtimelimit); } static void state_quotafile( FILE *fp, uint type, char *dir, uint flags) { fs_cursor_t cursor; fs_path_t *mount; fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) state_quotafile_mount(fp, type, mount, flags); } static int state_f( int argc, char **argv) { FILE *fp = NULL; char *fname = NULL; int c, flags = 0, type = 0; while ((c = getopt(argc, argv, "af:gpuv")) != EOF) { switch (c) { case 'a': flags |= ALL_MOUNTS_FLAG; break; case 'f': fname = optarg; break; case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage(&state_cmd); } } if (argc != optind) return command_usage(&state_cmd); if ((fp = fopen_write_secure(fname)) == NULL) return 0; if (!type) type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA; if (flags & ALL_MOUNTS_FLAG) state_quotafile(fp, type, NULL, flags); else if (fs_path && fs_path->fs_flags & FS_MOUNT_POINT) state_quotafile(fp, type, fs_path->fs_dir, flags); if (fname) fclose(fp); return 0; } static void enable_enforcement( char *dir, uint type, uint qflags, uint flags) { fs_path_t *mount; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { exitcode = 1; fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } dir = mount->fs_name; if (xfsquotactl(XFS_QUOTAON, dir, type, 0, (void *)&qflags) < 0) perror("XFS_QUOTAON"); else if (flags & VERBOSE_FLAG) state_quotafile_mount(stdout, type, mount, flags); } static void disable_enforcement( char *dir, uint type, uint qflags, uint flags) { fs_path_t *mount; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { exitcode = 1; fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } dir = mount->fs_name; if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0) perror("XFS_QUOTAOFF"); else if (flags & VERBOSE_FLAG) state_quotafile_mount(stdout, type, mount, flags); } static void quotaoff( char *dir, uint type, uint qflags, uint flags) { fs_path_t *mount; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { exitcode = 1; fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } dir = mount->fs_name; if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0) perror("XFS_QUOTAOFF"); else if (flags & VERBOSE_FLAG) state_quotafile_mount(stdout, type, mount, flags); } static int remove_qtype_extents( char *dir, uint type) { int error = 0; if ((error = xfsquotactl(XFS_QUOTARM, dir, type, 0, (void *)&type)) < 0) perror("XFS_QUOTARM"); return error; } static void remove_extents( char *dir, uint type, uint flags) { fs_path_t *mount; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { exitcode = 1; fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } dir = mount->fs_name; if (type & XFS_USER_QUOTA) { if (remove_qtype_extents(dir, XFS_USER_QUOTA) < 0) return; } if (type & XFS_GROUP_QUOTA) { if (remove_qtype_extents(dir, XFS_GROUP_QUOTA) < 0) return; } else if (type & XFS_PROJ_QUOTA) { if (remove_qtype_extents(dir, XFS_PROJ_QUOTA) < 0) return; } if (flags & VERBOSE_FLAG) state_quotafile_mount(stdout, type, mount, flags); } static int enable_f( int argc, char **argv) { int c, flags = 0, qflags = 0, type = 0; while ((c = getopt(argc, argv, "gpuv")) != EOF) { switch (c) { case 'g': type |= XFS_GROUP_QUOTA; qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD; break; case 'p': type |= XFS_PROJ_QUOTA; qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD; break; case 'u': type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage(&enable_cmd); } } if (argc != optind) return command_usage(&enable_cmd); if (!type) { type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD; } if (fs_path->fs_flags & FS_MOUNT_POINT) enable_enforcement(fs_path->fs_dir, type, qflags, flags); return 0; } static int disable_f( int argc, char **argv) { int c, flags = 0, qflags = 0, type = 0; while ((c = getopt(argc, argv, "gpuv")) != EOF) { switch (c) { case 'g': type |= XFS_GROUP_QUOTA; qflags |= XFS_QUOTA_GDQ_ENFD; break; case 'p': type |= XFS_PROJ_QUOTA; qflags |= XFS_QUOTA_PDQ_ENFD; break; case 'u': type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ENFD; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage(&disable_cmd); } } if (argc != optind) return command_usage(&disable_cmd); if (!type) { type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ENFD; } if (fs_path->fs_flags & FS_MOUNT_POINT) disable_enforcement(fs_path->fs_dir, type, qflags, flags); return 0; } static int off_f( int argc, char **argv) { int c, flags = 0, qflags = 0, type = 0; while ((c = getopt(argc, argv, "gpuv")) != EOF) { switch (c) { case 'g': type |= XFS_GROUP_QUOTA; qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD; break; case 'p': type |= XFS_PROJ_QUOTA; qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD; break; case 'u': type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage(&off_cmd); } } if (argc != optind) return command_usage(&off_cmd); if (!type) { type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD; } if (fs_path->fs_flags & FS_MOUNT_POINT) quotaoff(fs_path->fs_dir, type, qflags, flags); return 0; } static int remove_f( int argc, char **argv) { int c, flags = 0, type = 0; while ((c = getopt(argc, argv, "gpuv")) != EOF) { switch (c) { case 'g': type |= XFS_GROUP_QUOTA; break; case 'p': type |= XFS_PROJ_QUOTA; break; case 'u': type |= XFS_USER_QUOTA; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage(&remove_cmd); } } if (argc != optind) return command_usage(&remove_cmd); if (!type) { type |= XFS_USER_QUOTA; } if (fs_path->fs_flags & FS_MOUNT_POINT) remove_extents(fs_path->fs_dir, type, flags); return 0; } void state_init(void) { off_cmd.name = "off"; off_cmd.cfunc = off_f; off_cmd.argmin = 0; off_cmd.argmax = -1; off_cmd.args = _("[-gpu] [-v]"); off_cmd.oneline = _("permanently switch quota off for a path"); off_cmd.help = off_help; state_cmd.name = "state"; state_cmd.cfunc = state_f; state_cmd.argmin = 0; state_cmd.argmax = -1; state_cmd.args = _("[-gpu] [-a] [-v] [-f file]"); state_cmd.oneline = _("get overall quota state information"); state_cmd.help = state_help; state_cmd.flags = CMD_FLAG_FOREIGN_OK; enable_cmd.name = "enable"; enable_cmd.cfunc = enable_f; enable_cmd.argmin = 0; enable_cmd.argmax = -1; enable_cmd.args = _("[-gpu] [-v]"); enable_cmd.oneline = _("enable quota enforcement"); enable_cmd.help = enable_help; disable_cmd.name = "disable"; disable_cmd.cfunc = disable_f; disable_cmd.argmin = 0; disable_cmd.argmax = -1; disable_cmd.args = _("[-gpu] [-v]"); disable_cmd.oneline = _("disable quota enforcement"); disable_cmd.help = disable_help; remove_cmd.name = "remove"; remove_cmd.cfunc = remove_f; remove_cmd.argmin = 0; remove_cmd.argmax = -1; remove_cmd.args = _("[-gpu] [-v]"); remove_cmd.oneline = _("remove quota extents from a filesystem"); remove_cmd.help = remove_help; if (expert) { add_command(&off_cmd); add_command(&state_cmd); add_command(&enable_cmd); add_command(&disable_cmd); add_command(&remove_cmd); } } xfsprogs-5.3.0/quota/util.c0000644000175000017500000002355013435336037015532 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include #include #include #include #include #include "init.h" #include "quota.h" #define SECONDS_IN_A_DAY (24 * 60 * 60) #define SECONDS_IN_A_HOUR (60 * 60) #define SECONDS_IN_A_MINUTE (60) char * time_to_string( time_t origin, uint flags) { static char timestamp[32]; time_t now, timer; uint days, hours, minutes, seconds; if (flags & ABSOLUTE_FLAG) { timer = origin; } else { time(&now); timer = max(origin - now, 0); } /* * If we are in verbose mode, or if less than a day remains, we * will show "X days hh:mm:ss" so the user knows the exact timer status. * * Otherwise, we round down to the nearest day - so we add 30s here * such that setting and reporting a limit in rapid succession will * show the limit which was just set, rather than immediately reporting * one day less. */ if ((timer > SECONDS_IN_A_DAY) && !(flags & VERBOSE_FLAG)) timer += 30; /* seconds */ days = timer / SECONDS_IN_A_DAY; if (days) timer %= SECONDS_IN_A_DAY; hours = timer / SECONDS_IN_A_HOUR; if (hours) timer %= SECONDS_IN_A_HOUR; minutes = timer / SECONDS_IN_A_MINUTE; seconds = timer % SECONDS_IN_A_MINUTE; if (flags & LIMIT_FLAG) { snprintf(timestamp, sizeof(timestamp), (flags & HUMAN_FLAG) ? _("[-none-]") : _("[--none--]")); } else if (origin == 0) { snprintf(timestamp, sizeof(timestamp), (flags & HUMAN_FLAG) ? _("[------]") : _("[--------]")); } else if ((hours == 0 && minutes == 0 && seconds == 0) || (!(flags & VERBOSE_FLAG) && days > 0)) { snprintf(timestamp, sizeof(timestamp), "[%u %s]", days, days == 1 ? _("day") : _("days")); } else if (flags & VERBOSE_FLAG) { snprintf(timestamp, sizeof(timestamp), "[%u %s %02u:%02u:%02u]", days, days == 1 ? _("day") : _("days"), hours, minutes, seconds); } else { /* non-verbose, less than a day remaining */ snprintf(timestamp, sizeof(timestamp), (flags & HUMAN_FLAG) ? "%02u:%02u:%02u" : "[%02u:%02u:%02u]", hours, minutes, seconds); } return timestamp; } static int round_snprintf( char *sp, size_t size, const char *fmt_round, const char *fmt_not_round, uint64_t value, uint64_t divisor) { double v = (double)value / divisor; value /= divisor; if (v == (double)value) return snprintf(sp, size, fmt_round, (uint)value); else return snprintf(sp, size, fmt_not_round, v); } /* Basic blocks (512) bytes are returned from quotactl */ #define BBS_TO_EXABYTES(bbs) ((uint64_t)(bbs)>>51) #define BBS_TO_PETABYTES(bbs) ((uint64_t)(bbs)>>41) #define BBS_TO_TERABYTES(bbs) ((uint64_t)(bbs)>>31) #define BBS_TO_GIGABYTES(bbs) ((uint64_t)(bbs)>>21) #define BBS_TO_MEGABYTES(bbs) ((uint64_t)(bbs)>>11) #define BBS_TO_KILOBYTES(bbs) ((uint64_t)(bbs)>>1) #define BBEXABYTE ((uint64_t)1<<51) #define BBPETABYTE ((uint64_t)1<<41) #define BBTERABYTE ((uint64_t)1<<31) #define BBGIGABYTE ((uint64_t)1<<21) #define BBMEGABYTE ((uint64_t)1<<11) #define BBKILOBYTE ((uint64_t)1<< 1) char * bbs_to_string( uint64_t v, char *sp, uint size) { if (v == 0) snprintf(sp, size, "%4u", (uint)v); else if (BBS_TO_EXABYTES(v)) round_snprintf(sp, size, "%3uE", "%3.1fE", v, BBEXABYTE); else if (BBS_TO_PETABYTES(v)) round_snprintf(sp, size, "%3uP", "%3.1fP", v, BBPETABYTE); else if (BBS_TO_TERABYTES(v)) round_snprintf(sp, size, "%3uT", "%3.1fT", v, BBTERABYTE); else if (BBS_TO_GIGABYTES(v)) round_snprintf(sp, size, "%3uG", "%3.1fG", v, BBGIGABYTE); else if (BBS_TO_MEGABYTES(v)) round_snprintf(sp, size, "%3uM", "%3.1fM", v, BBMEGABYTE); else if (BBS_TO_KILOBYTES(v)) round_snprintf(sp, size, "%3uK", "%3.1fK", v, BBKILOBYTE); else snprintf(sp, size, "%4u", (uint)v << BBSHIFT); /* bytes */ return sp; } #define THOUSAND ((uint64_t)1000) #define MILLION ((uint64_t)1000*1000) #define BILLION ((uint64_t)1000*1000*1000) #define TRILLION ((uint64_t)1000*1000*1000*1000) #define GAZILLION ((uint64_t)1000*1000*1000*1000*1000) #define RIDICULOUS ((uint64_t)1000*1000*1000*1000*1000*1000) #define STOPALREADY ((uint64_t)1000*1000*1000*1000*1000*1000*1000) char * num_to_string( uint64_t v, char *sp, uint size) { if (v == 0) snprintf(sp, size, "%4u", (uint)v); else if (v > STOPALREADY) round_snprintf(sp, size, "%3us", "%3.1fs", v, STOPALREADY); else if (v > RIDICULOUS) round_snprintf(sp, size, "%3ur", "%3.1fr", v, RIDICULOUS); else if (v > GAZILLION) round_snprintf(sp, size, "%3ug", "%3.1fg", v, GAZILLION); else if (v > TRILLION) round_snprintf(sp, size, "%3ut", "%3.1ft", v, TRILLION); else if (v > BILLION) round_snprintf(sp, size, "%3ub", "%3.1fb", v, BILLION); else if (v > MILLION) round_snprintf(sp, size, "%3um", "%3.1fm", v, MILLION); else if (v > THOUSAND) round_snprintf(sp, size, "%3uk", "%3.1fk", v, THOUSAND); else snprintf(sp, size, "%4u", (uint)v); return sp; } char * pct_to_string( uint64_t portion, uint64_t whole, char *buf, uint size) { uint percent; percent = whole ? (uint) (100.0 * portion / whole + 0.5) : 0; if (snprintf(buf, size, "%3u", percent) < 0) return "???"; return buf; } char * form_to_string( uint form) { char *forms[] = { _("Blocks"), _("Inodes"), _("Realtime Blocks") }; if (form & XFS_BLOCK_QUOTA) return forms[0]; if (form & XFS_INODE_QUOTA) return forms[1]; if (form & XFS_RTBLOCK_QUOTA) return forms[2]; return NULL; } char * type_to_string( uint type) { char *types[] = { _("User"), _("Group"), _("Project") }; if (type & XFS_USER_QUOTA) return types[0]; if (type & XFS_GROUP_QUOTA) return types[1]; if (type & XFS_PROJ_QUOTA) return types[2]; return NULL; } /* * Identifier caches - user/group/project names/IDs */ #define NID 4096 #define IDMASK (NID-1) typedef struct { uint32_t id; char name[NMAX+1]; } idcache_t; static idcache_t uidnc[NID]; static idcache_t gidnc[NID]; static idcache_t pidnc[NID]; static int uentriesleft = NID; static int gentriesleft = NID; static int pentriesleft = NID; static idcache_t * getnextpwent( uint32_t id, int byid) { struct passwd *pw; static idcache_t idc; /* /etc/passwd */ if ((pw = byid? getpwuid(id) : getpwent()) == NULL) return NULL; idc.id = pw->pw_uid; strncpy(idc.name, pw->pw_name, NMAX); return &idc; } static idcache_t * getnextgrent( uint32_t id, int byid) { struct group *gr; static idcache_t idc; if ((gr = byid? getgrgid(id) : getgrent()) == NULL) return NULL; idc.id = gr->gr_gid; strncpy(idc.name, gr->gr_name, NMAX); return &idc; } static idcache_t * getnextprent( uint32_t id, int byid) { fs_project_t *pr; static idcache_t idc; if ((pr = byid? getprprid(id) : getprent()) == NULL) return NULL; idc.id = pr->pr_prid; strncpy(idc.name, pr->pr_name, NMAX); return &idc; } char * uid_to_name( uint32_t id) { idcache_t *ncp, *idp; /* Check cache for name first */ ncp = &uidnc[id & IDMASK]; if (ncp->id == id && ncp->name[0]) return ncp->name; if (uentriesleft) { /* * Fill this cache while seaching for a name. * This lets us run through the file serially. */ if (uentriesleft == NID) setpwent(); while (((idp = getnextpwent(id, 0)) != NULL) && uentriesleft) { uentriesleft--; ncp = &uidnc[idp->id & IDMASK]; if (ncp->name[0] == '\0' || idp->id == id) memcpy(ncp, idp, sizeof(idcache_t)); if (idp->id == id) return ncp->name; } endpwent(); uentriesleft = 0; ncp = &uidnc[id & IDMASK]; } /* Not cached - do it the slow way & insert into cache */ if ((idp = getnextpwent(id, 1)) == NULL) return NULL; memcpy(ncp, idp, sizeof(idcache_t)); return ncp->name; } char * gid_to_name( uint32_t id) { idcache_t *ncp, *idp; /* Check cache for name first */ ncp = &gidnc[id & IDMASK]; if (ncp->id == id && ncp->name[0]) return ncp->name; if (gentriesleft) { /* * Fill this cache while seaching for a name. * This lets us run through the file serially. */ if (gentriesleft == NID) setgrent(); while (((idp = getnextgrent(id, 0)) != NULL) && gentriesleft) { gentriesleft--; ncp = &gidnc[idp->id & IDMASK]; if (ncp->name[0] == '\0' || idp->id == id) memcpy(ncp, idp, sizeof(idcache_t)); if (idp->id == id) return ncp->name; } endgrent(); gentriesleft = 0; ncp = &gidnc[id & IDMASK]; } /* Not cached - do it the slow way & insert into cache */ if ((idp = getnextgrent(id, 1)) == NULL) return NULL; memcpy(ncp, idp, sizeof(idcache_t)); return ncp->name; } char * prid_to_name( uint32_t id) { idcache_t *ncp, *idp; /* Check cache for name first */ ncp = &pidnc[id & IDMASK]; if (ncp->id == id && ncp->name[0]) return ncp->name; if (pentriesleft) { /* * Fill this cache while seaching for a name. * This lets us run through the file serially. */ if (pentriesleft == NID) setprent(); while (((idp = getnextprent(id, 0)) != NULL) && pentriesleft) { pentriesleft--; ncp = &pidnc[idp->id & IDMASK]; if (ncp->name[0] == '\0' || idp->id == id) memcpy(ncp, idp, sizeof(idcache_t)); if (idp->id == id) return ncp->name; } endprent(); pentriesleft = 0; ncp = &pidnc[id & IDMASK]; } /* Not cached - do it the slow way & insert into cache */ if ((idp = getnextprent(id, 1)) == NULL) return NULL; memcpy(ncp, idp, sizeof(idcache_t)); return ncp->name; } /* * Utility routine for opening an output file so that it can * be "securely" written to (i.e. without vulnerability to a * symlink attack). * * Returns NULL on failure, stdout on NULL input. */ FILE * fopen_write_secure( char *fname) { FILE *fp; int fd; if (!fname) return stdout; if ((fd = open(fname, O_CREAT|O_WRONLY|O_EXCL, 0600)) < 0) { exitcode = 1; fprintf(stderr, _("%s: open on %s failed: %s\n"), progname, fname, strerror(errno)); return NULL; } if ((fp = fdopen(fd, "w")) == NULL) { exitcode = 1; fprintf(stderr, _("%s: fdopen on %s failed: %s\n"), progname, fname, strerror(errno)); close(fd); return NULL; } return fp; } xfsprogs-5.3.0/release.sh0000755000175000017500000000161113034246041015217 0ustar nathansnathans#!/bin/sh # # Automate generation of a new release # # Need to first update these files: # # VERSION (with new version number) # docs/CHANGES (with changelog and version/date string) # configure.ac (with new version string) # debian/changelog (with new release entry, only for release version) . ./VERSION version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} date=`date +"%-d %B %Y"` echo "Cleaning up" make realclean echo "Updating CHANGES" sed -e "s/${version}.*/${version} (${date})/" doc/CHANGES > doc/CHANGES.tmp && \ mv doc/CHANGES.tmp doc/CHANGES echo "Commiting CHANGES update to git" git commit -a -m "${version} release" echo "Tagging git repository" git tag -a -m "${version} release" v${version} echo "Making source tarball" make dist #echo "Sign the source tarball" #gpg --detach-sign xfsprogs-${version}.tar.gz echo "Done. Please remember to push out tags using \"git push --tags\"" xfsprogs-5.3.0/repair/Makefile0000644000175000017500000000311613435336037016176 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LSRCFILES = README LTCOMMAND = xfs_repair HFILES = agheader.h attr_repair.h avl.h bmap.h btree.h \ da_util.h dinode.h dir2.h err_protos.h globals.h incore.h protos.h \ rt.h progress.h scan.h versions.h prefetch.h rmap.h slab.h threads.h CFILES = agheader.c attr_repair.c avl.c bmap.c btree.c \ da_util.c dino_chunks.c dinode.c dir2.c globals.c incore.c \ incore_bmc.c init.c incore_ext.c incore_ino.c phase1.c \ phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c \ progress.c prefetch.c rmap.c rt.c sb.c scan.c slab.c threads.c \ versions.c xfs_repair.c LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBXCMD) $(LIBFROG) $(LIBUUID) $(LIBRT) \ $(LIBPTHREAD) $(LIBBLKID) LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG) $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static-libtool-libs default: depend $(LTCOMMAND) globals.o: globals.h include $(BUILDRULES) # # Tracing flags: # -DXR_INODE_TRACE inode processing # -DXR_DIR_TRACE directory processing # -DXR_DUP_TRACE duplicate extent processing # -DXR_BCNT_TRACE incore bcnt freespace btree building # -DXR_BLD_FREE_TRACE building on-disk freespace (bcnt/bno) btrees # -DXR_BLD_INO_TRACE building on-disk inode allocation btrees # -DXR_BLD_ADD_EXTENT track phase 5 block extent creation # -DXR_BCKPTR_DBG parent list debugging info # -DXR_PF_TRACE prefetch trace # #CFLAGS += ... install: default $(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/repair/README0000644000175000017500000006675113435336037015434 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 A living document. The basic algorithm. TODO: (D == DONE) 0) Need to bring some sanity into the case of flags that can be set in the secondaries at mkfs time but reset or cleared in the primary later in the filesystem's life. 0) Clear the persistent read-only bit if set. Clear the shared bit if set and the version number is zero. This brings the filesystem back to a known state. 0) make sure that superblock geometry code checks the logstart value against whether or not we have an internal log. If we have an internal log and a logdev, that's ok. (Maybe we just aren't using it). If we have an external log (logstart == 0) but no logdev, that's right out. 0) write secondary superblock search code. Rewrite initial superblock parsing code to be less complicated. Just use variables to indicate primary, secondary, etc., and use a function to get the SB given a specific location or something. 2) For inode alignment, if the SB bit is set and the inode alignment size field in the SB is set, then believe that the fs inodes MUST be aligned and disallow any non-aligned inodes. Likewise, if the SB bit isn't set (or earlier version) and the inode alignment size field is zero, then never set the bit even if the inodes are aligned. Note that the bits and alignment values are replicated in the secondary superblocks. 0) add feature specification options to parse_arguments 0) add logic to add_inode_ref(), add_inode_reached() to detect nlink overflows in cases where the fs (or user had indicated fs) doesn't support new nlinks. 6) check to make sure that the inodes containing btree blocks with # recs < minrecs aren't legit -- e.g. the only descendant of a root block. 7) inode di_size value sanity checking -- should always be less than the biggest filebno offset mentioned in the bmaps. Doesn't have to be equal though since we're allowed to overallocate (it just wastes a little space). This is for both regular files and directories (have to modify the existing directory check). Add tracking of largest offset in bmap scanning code. Compare value against di_size. Should be >= di_size. Alternatively, you could pass the inode into down through the extent record processing layer and make the checks there. Add knowledge of quota inodes. size of quota inode is always zero. We should maintain that. 8) Basic quota stuff. Invariants if quota feature bit is set, the quota inodes if set, should point to disconnected, 0 len inodes. D - if quota inodes exist, the quota bits must be turned on. It's ok for the quota flags to be zeroed but they should be in a legal state (see xfs_quota.h). D - if the quota flags are non-zero, the corresponding quota inodes must exist. quota inodes are never deleted, only their space is freed. if quotas are being downgraded, then check quota inodes at the end of phase 3. If they haven't been cleared yet, clear them. Regardless, then clear sb flags (quota inode fields, quota flags, and quota bit). 5) look at verify_inode_chunk(). it's probably really broken. 9) Complicated quota stuff. Add code to bmap scan code to track used blocks. Add another pair of AVL trees to track user and project quota limits. Set AVL trees up at the beginning of phase 3. Quota inodes can be rebuilt or corrected later if damaged. D - 0) fix directory processing. phase 3, if an entry references a free inode, *don't* mark it used. wait for the rest of phase 3 processing to hit that inode. If it looks like it's in use, we'll mark in use then. If not, we'll clear it and mark the inode map. then in phase 4, you can depend on the inode map. should probably set the parent info in phase 4. So we have a check_dups flag. Maybe we should change the name of check_dir to discover_inodes. During phase 3 (discover_inodes == 1), uncertain inodes are added to list. During phase 4 (discover_inodes == 0), they aren't. And we never mark inodes in use from the directory code. During phase 4, we shouldn't complain about names with a leading '/' since we made those names in phase 3. Have to change dino_chunks.c (parent setting), dinode.c and dir.c. D - 0) make sure we don't screw up filesystems with real-time inodes. remember to initialize real-time map with all blocks XR_E_FREE. D - 4) check contents of symlinks as well as lengths in process_symlinks() in dinode.c. Right now, we only check lengths. D - 1) Feature mismatches -- for quotas and attributes, if the stuff exists in the filesystem, set the superblock version bits. D - 0) rewrite directory leaf block holemap comparison code. probably should just check the leaf block hole info against our incore bitmap. If the hole flag is not set, then we know that there can only be one hole and it has to be between the entry table and the top of heap. If the hole flag is set, then it's ok if the on-disk holemap doesn't describe everything as long as what it does describe doesn't conflict with reality. D - 0) rewrite setting nlinks handling -- for version 1 inodes, set both nlinks and onlinks (zero projid_lo/hi and pad) if we have to change anything. For version 2, I think we're ok. D - 0) Put awareness of quota inode into mark_standalone_inodes. D - 8) redo handling of superblocks with bad version numbers. need to bail out (without harming) fs's that have sbs that are newer than we are. D - 0) How do we handle feature mismatches between fs and superblock? For nlink, check each inode after you know it's good. If onlinks is 0 and nlinks is > 0 and it's a version 2 inode, then it really is a version 2 inode and the nlinks flag in the SB needs to be set. If it's a version 2 inode and the SB agrees but onlink is non-zero, then clear onlink. D - 3) keep cumulative counts of freeblocks, inodes, etc. to set in the superblock at the end of phase 5. Remember that agf freeblock counters don't include blocks used by the non-root levels of the freespace trees but that the sb free block counters include those. D - 0) Do parent setting in directory code (called by phase 3). actually, I put it in process_inode_set and propagated the parent up to it from the process_dinode/process_dir routines. seemed cleaner than pushing the irec down and letting them bang on it. D - 0) If we clear a file in phase 4, make sure that if it's a directory that the parent info is cleared also. D - 0) put inode tree flashover (call to add_ino_backptrs) into phase 5. D - 0) do set/get_inode_parent functions in incore_ino.c. also do is/set/ inode_processed. D - 0) do a versions.c to extract feature info and set global vars from the superblock version number and possibly feature bits D - 0) change longform_dir_entry_check + shortform_dir_entry_check to return a count of how many illegal '/' entries exist. if > 0, then process_dirstack needs to call prune_dir_entry with a hash value of 0 to delete the entries. D - 0) add the "processed" bitfield to the backptrs_t struct that gets attached after phase 4. D- ) Phase 6 !!! D - 0) look at usage of XFS_MAKE_IPTR(). It does the right arithmetic assuming you count your offsets from the beginning of the buffer. D - 0) look at references to XFS_INODES_PER_CHUNK. change the ones that really mean sizeof(uint64_t)*NBBY to something else (like that only defined as a constant INOS_PER_IREC. this isn't as important since XFS_INODES_PER_CHUNK will never chang D - 0) look at junk_zerolen_dir_leaf_entries() to make sure it isn't hosing the freemap since it assumed that bytes between the end of the table and firstused didn't show up in the freemap when they actually do. D - 0) track down XFS_INO_TO_OFFSET() usage. I don't think I'm using it right. (e.g. I think it gives you the offset of an inode into a block but on small block filesystems, I may be reading in inodes in multiblock buffers and working from the start of the buffer plus I'm using it to get offsets into my ino_rec's which may not be a good idea since I use 64-inode ino_rec's whereas the offset macro works off blocksize). D - 0.0) put buffer -> dirblock conversion macros into xfs kernel code D - 0.2) put in sibling pointer checking and path fixup into bmap (long form) scan routines in scan.c D - 0.3) find out if bmap btrees with only root blocks are legal. I'm betting that they're not because they'd be extent inodes instead. If that's the case, rip some code out of process_btinode() Algorithm (XXX means not done yet): Phase 1 -- get a superblock and zero log get a superblock -- either read in primary or find a secondary (ag header), check ag headers To find secondary: Go for brute force and read in the filesystem N meg at a time looking for a superblock. as a slight optimization, we could maybe skip ahead some number of blocks to try and get towards the end of the first ag. After you find a secondary, try and find at least other ags as a verification that the secondary is a good superblock. XXX - Ugh. Have to take growfs'ed filesystems into account. The root superblock geometry info may not be right if recovery hasn't run or it's been trashed. The old ag's may or may not be right since the system could have crashed during growfs or the bwrite() to the superblocks could have failed and the buffer been reused. So we need to check to see if another ag exists beyond the "last" ag to see if a growfs happened. If not, then we know that the geometry info is good and treat the fs as a non-growfs'ed fs. If we do have inconsistencies, then the smaller geometry is the old fs and the larger the new. We can check the new superblocks to see if they're good. If not, then we know the system crashed at or soon after the growfs and we can choose to either accept the new geometry info or trash it and truncate the fs back to the old geometry parameters. Cross-check geometry information in secondary sb's with primary to ensure that it's correct. Use sim code to allow mount filesystems *without* reading in root inode. This sets up the xfs_mount_t structure and allows us to use XFS_* macros that we wouldn't otherwise be able to use. Note, I split phase 1 and 2 into separate pieces because I want to initialize the xfs_repair incore data structures after phase 1. parse superblock version and feature flags and set appropriate global vars to reflect the flags (attributes, quotas, etc.) Workaround for the mkfs "not zeroing the superblock buffer" bug. Determine what field is the last valid non-zero field in the superblock. The trick here is to be able to differentiate the last valid non-zero field in the primary superblock and secondaries because they may not be the same. Fields in the primary can be set as the filesystem gets upgraded but the upgrades won't touch the secondaries. This means that we need to find some number of secondaries and check them. So we do the checking here and the setting in phase2. Phase 2 -- check integrity of allocation group allocation structures zero the log if in no modify mode sanity check ag headers -- superblocks match, agi isn't trashed -- the agf and agfl don't really matter because we can just recreate them later. Zero part of the superblock buffer if necessary Walk the freeblock trees to get an initial idea of what the fs thinks is free. Files that disagree (claim free'd blocks) can be salvaged or deleted. If the btree is internally inconsistent, when in doubt, mark blocks free. If they're used, they'll be stolen back later. don't have to check sibling pointers for each level since we're going to regenerate all the trees anyway. Walk the inode allocation trees and make sure they're ok, otherwise the sim inode routines will probably just barf. mark inode allocation tree blocks and ag header blocks as used blocks. If the trees are corrupted, this phase will generate "uncertain" inode chunks. Those chunks go on a list and will have to verified later. Record the blocks that are used to detect corruption and multiply claimed blocks. These trees will be regenerated later. Mark the blocks containing inodes referenced by uncorrupted inode trees as being used by inodes. The other blocks will get marked when/if the inodes are verified. calculate root and realtime inode numbers from the filesystem geometry, fix up mount structure's incore superblock if they're wrong. ASSUMPTION: at end of phase 2, we've got superblocks and ag headers that are not garbage (some data in them like counters and the freeblock and inode trees may be inconsistent but the header is readable and otherwise makes sense). XXX if in no_modify mode, check for blocks claimed by one freespace btree and not the other Phase 3 -- traverse inodes to make the inodes, bmaps and freespace maps consistent. For each ag, use either the incore inode map or scan the ag for inodes. Let's use the incore inode map, now that we've made one up in phase2. If we lose the maps, we'll locate inodes when we traverse the directory heirarchy. If we lose both, we could scan the disk. Ugh. Maybe make that a command-line option that we support later. ASSUMPTION: we know if the ag allocation btrees are intact (phase 2) First - Walk and clear the ag unlinked lists. We'll process the inodes later. Check and make sure that the unlinked lists reference known inodes. If not, add to the list of uncertain inodes. Second, check the uncertain inode list generated in phase2 and above and get them into the inode tree if they're good. The incore inode cluster tree *always* has good clusters (alignment, etc.) in it. Third, make sure that the root inode is known. If not, and we know the inode number from the superblock, discover that inode and its chunk. Then, walk the incore inode-cluster tree. Maintain an in-core bitmap over the entire fs for block allocation. traverse each inode, make sure inode mode field matches free/allocated bit in the incore inode allocation tree. If there's a mismatch, assume that the inode is in use. - for each in-use inode, traverse each bmap/dir/attribute map or tree. Maintain a map (extent list?) for the current inode. - For each block marked as used, check to see if already known (referenced by another file or directory) and sanity check the contents of the block as well if possible (in the case of meta-blocks). - if the inode claims already used blocks, mark the blocks as multiply claimed (duplicate) and go on. the inode will be cleared in phase 4. - if metablocks are garbaged, clear the inode after traversing what you can of the bmap and proceed to next inode. We don't have to worry about trashing the maps or trees in cleared inodes because the blocks will show up as free in the ag freespace trees that we set up in phase 5. - clear the di_next_unlinked pointer -- all unlinked but active files go bye-bye. - All blocks start out unknown. We need the last state in case we run into a case where we need to step on a block to store filesystem meta-data and it turns out later that it's referenced by some inode's bmap. In that case, the inode loses because we've already trashed the block. This shouldn't happen in the first version unless some inode has a bogus bmap referencing blocks in the ag header but the 4th state will keep us from inadvertently doing something stupid in that case. - If inode is allocated, mark all blocks allocated to the current inode as allocated in the incore freespace bitmap. - If inode is good and a directory, scan through it to find leaf entries and discover any unknown inodes. For shortform, we correct what we can. If the directory is corrupt, we try and fix it in place. If it has zero good entries, then we blast it. All unknown inodes get put onto the uncertain inode list. This is safe because we only put inodes onto the list when we're processing known inodes so the uncertain inode list isn't in use. We fix only one problem -- an entry that has a mathematically invalid inode numbers in them. If that's the case, we replace the inode number with NULLFSINO and we'll fix up the entry in phase 6. That info may conflict with the inode information, but we'll straighten out any inconsistencies there in phase4 when we process the inodes again. Errors involving bogus forward/back links, zero-length entries make the directory get trashed. if an entry references a free inode, ignore that fact for now. wait for the rest of phase 3 processing to hit that inode. If it looks like it's in use, we'll mark in use then. If not, we'll clear it and mark the inode map. then in phase 4, you can depend on the inode map. Entries that point to non-existent or free inodes, and extra blocks in the directory will get fixed in place in a later pass. Entries that point to a quota inode are marked TBD. If the directory internally points to the same block twice, the directory gets blown away. Note that processing uncertain inodes can add more inodes to the uncertain list if they're directories. So we loop until the uncertain list is empty. During inode verification, if the inode blocks are unknown, mark then as in-use by inodes. XXX HEURISTIC -- if we blow an inode away that has space, assume that the freespace btree is now out of wack. If it was ok earlier, it's certain to be wrong now. And the odds of this space free cancelling out the existing error is so small I'm willing to ignore it. Should probably do this via a global var and complain about this later. Assumption: All known inodes are now marked as in-use or free. Any inodes that we haven't found by now are hosed (lost) since we can't reach them via either the inode btrees or via directory entries. Directories are semi-clean. All '.' entries are good. Root '..' entry is good if root inode exists. All entries referencing non-existent inodes, free inodes, etc. XXX verify that either quota inode is 0 or NULLFSINO or if sb quota flag is non zero, verify that quota inode is NULLFSINO or is referencing a used, but disconnected inode. XXX if in no_modify mode, check for unclaimed blocks - Phase 4 - Check for inodes referencing duplicate blocks At this point, all known duplicate blocks are marked in the block map. However, some of the claimed blocks in the bmap may in fact be free because they belong to inodes that have to be cleared either due to being a trashed directory or because it's the first inode to claim a block that was then claimed later. There's a similar problem with meta-data blocks that are referenced by inode bmaps that are going to be freed once the inode (or directory) gets cleared. So at this point, we collect the duplicate blocks into extents and put them into the duplicate extent list. Mark the ag header blocks as in use. We then process each inode twice -- the first time we check to see if the inode claims a duplicate extent and we do NOT set the block bitmap. If the inode claims a duplicate extent, we clear the inode. Since the bitmap hasn't been set, that automatically frees all blocks associated with the cleared inode. If the inode is ok, process it a second time and set the bitmap since we know that this inode will live. The unlinked list gets cleared in every inode at this point as well. We no longer need to preserve it since we've discovered every inode we're going to find from it. verify existence of root inode. if it exists, check for existence of "lost+found". If it exists, mark the entry to be deleted, and clear the inode. All the inodes that were connected to the lost+found will be reconnected later. XXX HEURISTIC -- if we blow an inode away that has space, assume that the freespace btree is now out of wack. If it was ok earlier, it's certain to be wrong now. And the odds of this space free cancelling out the existing error is so small I'm willing to ignore it. Should probably do this via a global var and complain about this later. Clear the quota inodes if the inode btree says that they're not in use. The space freed will get picked up by phase 5. XXX Clear the quota inodes if the filesystem is being downgraded. - Phase 5 - Build inode allocation trees, freespace trees and agfl's for each ag. After this, we should be able to unmount the filesystem and remount it for real. For each ag: (if no in no_modify mode) scan bitmap first to figure out number of extents. calculate space required for all trees. Start with inode trees. Setup the btree cursor which includes the list of preallocated blocks. As a by-product, this will delete the extents required for the inode tree from the incore extent tree. Calculate how many extents will be required to represent the remaining free extent tree on disk (twice, one for bybno and one for bycnt). You have to iterate on this because consuming extents can alter the number of blocks required to represent the remaining extents. If there's slop left over, you can put it in the agfl though. Then, manually build the trees, agi, agfs, and agfls. XXX if in no_modify mode, scan the on-disk inode allocation trees and compare against the incore versions. Don't have to scan the freespace trees because we caught the problems there in phase2 and phase3. But if we cleared any inodes with space during phases 3 or 4, now is the time to complain. XXX - Free duplicate extent lists. ??? Assumptions: at this point, sim code having to do with inode creation/modification/deletion and space allocation work because the inode maps, space maps, and bmaps for all files in the filesystem are good. The only structures that are screwed up are the directory contents, which means that lookup may not work for beans, the root inode which exists but may be completely bogus and the link counts on all inodes which may also be bogus. Free the bitmap, the freespace tree. Flash the incore inode tree over from parent list to having full backpointers. realtime processing, if any -- (Skip to below if running in no_modify mode). Generate the realtime bitmap from the incore realtime extent map and slam the info into the realtime bitmap inode. Generate summary info from the realtime extent map. XXX if in no_modify mode, compare contents of realtime bitmap inode to the incore realtime extent map. generate the summary info from the incore realtime extent map. compare against the contents of the realtime summary inode. complain if bad. reset superblock counters, sync version numbers - Phase 6 - directory traversal -- check reference counts, attach disconnected inodes, fix up bogus directories Assumptions: all on-disk space and inode trees are structurally sound. Incore and on-disk inode trees agree on whether an inode is in use. Directories are structurally sound. All hashvalues are monotonically increasing and interior nodes are correct so lookups work. All legal directory entries point to inodes that are in use and exist. Shortform directories are fine except that the links haven't been checked for conflicts (cycles, ".." being correct, etc.). Longform directories haven't been checked for those problems either PLUS longform directories may still contain entries beginning with '/'. No zero-length entries exist (they've been deleted or converted to '/'). Root directory may or may not exist. orphange may or may not exist. Contents of either may be completely bogus. Entries may point to free or non-existent inodes. At this we point, we may need new incore structures and may be able to trash an old one (like the filesystem block map) If '/' is trashed, then reinitialize it. If no realtime inodes, make them and if necessary, slam the summary info into the realtime summary inode. Ditto with the realtime bitmap inode. Make orphanage (lost+found ???). Traverse each directory from '/' (unless it was created). Check directory structure and each directory entry. If the entry is bogus (points to a non-existent or free inode, for example), mark that entry TBD. Maintain link counts on all inodes. Currently, traversal is depth-first. Mark every inode reached as "reached" (includes bumping up link counts). If a entry points to a directory but the parent (..) disagrees, then blow away the entry. if the directory being pointed to winds up disconnected, it'll be moved to the orphanage (and the link count incremented to account for the link and the reached bit set then). If an entry points to a directory that we've already reached, then some entry is bad and should be blown away. It's easiest to blow away the current entry plus since presumably the parent entry in the reached directory points to another directory, then it's far more likely that the current entry is bogus (otherwise the parent should point at it). If an entry points to a non-existent of free inode, blow the entry away. Every time a good entry is encountered update the link count for the inode that the entry points to. After traversal, scan incore inode map for directories not reached. Go to first one and try and find its root by following .. entries. Once at root, run traversal algorithm. When algorithm terminates, move subtree root inode to the orphanage. Repeat as necessary until all disconnected directories are attached. Move all disconnected inodes to orphanage. - Phase 7: reset reference counts if required. Now traverse the on-disk inodes again, and make sure on-disk reference counts are correct. Reset if necessary. SKIP all unused inodes -- that also makes us skip the orphanage inode which we think is unused but is really used. However, the ref counts on that should be right so that's ok. --- multiple TB xfs_repair modify above to work in a couple of AGs at a time. The bitmaps should span only the current set of AGs. The key it scan the inode bmaps and keep a list of inodes that span multiple AG sets and keep the list in a data structure that's keyed off AG set # as well as inode # and also has a bit to indicate whether or not the inode will be cleared. Then in each AG set, when doing duplicate extent processing, you have to process all multi-AG-set inodes that claim blocks in the current AG set. If there's a conflict, you mark clear the inode in the current AG and you mark the multi-AG inode as "to be cleared". After going through all AGs, you can clear the to-be-cleared multi-AG-set inodes and pull them off the list. When building up the AG freespace trees, you walk the bmaps of all multi-AG-set inodes that are in the AG-set and include blocks claimed in the AG by the inode as used. This probably involves adding a phase 3-0 which would have to check all the inodes to see which ones are multi-AG-set inodes and set up the multi-AG-set inode data structure. Plus the process_dinode routines may have to be altered just a bit to do the right thing if running in tera-byte mode (call out to routines that check the multi-AG-set inodes when appropriate). To make things go faster, phase 3-0 could probably run in parallel. It should be possible to run phases 2-5 in parallel as well once the appropriate synchronization is added to the incore routines and the static directory leaf block bitmap is changed to be on the stack. Phase 7 probably can be in parallel as well. By in parallel, I mean that assuming that an AG-set contains 4 AGs, you could run 4 threads, 1 per AG in parallel to process the AG set. I don't see how phase 6 can be run in parallel though. And running Phase 8 in parallel is just silly. xfsprogs-5.3.0/repair/agheader.c0000644000175000017500000003214613435336037016447 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "globals.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" /* * XXX (dgc): What is the point of all the check and repair here when phase 5 * recreates the AGF/AGI/AGFL completely from scratch? */ static int verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i) { xfs_rfsblock_t agblocks; int retval = 0; /* check common fields */ if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) { retval = XR_AG_AGF; do_warn(_("bad magic # 0x%x for agf %d\n"), be32_to_cpu(agf->agf_magicnum), i); if (!no_modify) agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); } if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) { retval = XR_AG_AGF; do_warn(_("bad version # %d for agf %d\n"), be32_to_cpu(agf->agf_versionnum), i); if (!no_modify) agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); } if (be32_to_cpu(agf->agf_seqno) != i) { retval = XR_AG_AGF; do_warn(_("bad sequence # %d for agf %d\n"), be32_to_cpu(agf->agf_seqno), i); if (!no_modify) agf->agf_seqno = cpu_to_be32(i); } if (be32_to_cpu(agf->agf_length) != mp->m_sb.sb_agblocks) { if (i != mp->m_sb.sb_agcount - 1) { retval = XR_AG_AGF; do_warn(_("bad length %d for agf %d, should be %d\n"), be32_to_cpu(agf->agf_length), i, mp->m_sb.sb_agblocks); if (!no_modify) agf->agf_length = cpu_to_be32(mp->m_sb.sb_agblocks); } else { agblocks = mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i; if (be32_to_cpu(agf->agf_length) != agblocks) { retval = XR_AG_AGF; do_warn( _("bad length %d for agf %d, should be %" PRIu64 "\n"), be32_to_cpu(agf->agf_length), i, agblocks); if (!no_modify) agf->agf_length = cpu_to_be32(agblocks); } } } /* * check first/last AGF fields. if need be, lose the free * space in the AGFL, we'll reclaim it later. */ if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp)) { do_warn(_("flfirst %d in agf %d too large (max = %u)\n"), be32_to_cpu(agf->agf_flfirst), i, libxfs_agfl_size(mp) - 1); if (!no_modify) agf->agf_flfirst = cpu_to_be32(0); } if (be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) { do_warn(_("fllast %d in agf %d too large (max = %u)\n"), be32_to_cpu(agf->agf_fllast), i, libxfs_agfl_size(mp) - 1); if (!no_modify) agf->agf_fllast = cpu_to_be32(0); } /* don't check freespace btrees -- will be checked by caller */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return retval; if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) { char uu[64]; retval = XR_AG_AGF; platform_uuid_unparse(&agf->agf_uuid, uu); do_warn(_("bad uuid %s for agf %d\n"), uu, i); if (!no_modify) platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); } return retval; } static int verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno) { xfs_rfsblock_t agblocks; int retval = 0; /* check common fields */ if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) { retval = XR_AG_AGI; do_warn(_("bad magic # 0x%x for agi %d\n"), be32_to_cpu(agi->agi_magicnum), agno); if (!no_modify) agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); } if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) { retval = XR_AG_AGI; do_warn(_("bad version # %d for agi %d\n"), be32_to_cpu(agi->agi_versionnum), agno); if (!no_modify) agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); } if (be32_to_cpu(agi->agi_seqno) != agno) { retval = XR_AG_AGI; do_warn(_("bad sequence # %d for agi %d\n"), be32_to_cpu(agi->agi_seqno), agno); if (!no_modify) agi->agi_seqno = cpu_to_be32(agno); } if (be32_to_cpu(agi->agi_length) != mp->m_sb.sb_agblocks) { if (agno != mp->m_sb.sb_agcount - 1) { retval = XR_AG_AGI; do_warn(_("bad length # %d for agi %d, should be %d\n"), be32_to_cpu(agi->agi_length), agno, mp->m_sb.sb_agblocks); if (!no_modify) agi->agi_length = cpu_to_be32(mp->m_sb.sb_agblocks); } else { agblocks = mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno; if (be32_to_cpu(agi->agi_length) != agblocks) { retval = XR_AG_AGI; do_warn( _("bad length # %d for agi %d, should be %" PRIu64 "\n"), be32_to_cpu(agi->agi_length), agno, agblocks); if (!no_modify) agi->agi_length = cpu_to_be32(agblocks); } } } /* don't check inode btree -- will be checked by caller */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return retval; if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) { char uu[64]; retval = XR_AG_AGI; platform_uuid_unparse(&agi->agi_uuid, uu); do_warn(_("bad uuid %s for agi %d\n"), uu, agno); if (!no_modify) platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); } return retval; } /* * superblock comparison - compare arbitrary superblock with * filesystem mount-point superblock * * the verified fields include id and geometry. * * the inprogress fields, version numbers, and counters * are allowed to differ as well as all fields after the * counters to cope with the pre-6.5 mkfs non-zeroed * secondary superblock sectors. */ static int compare_sb(xfs_mount_t *mp, xfs_sb_t *sb) { fs_geometry_t fs_geo, sb_geo; get_sb_geometry(&fs_geo, &mp->m_sb); get_sb_geometry(&sb_geo, sb); if (memcmp(&fs_geo, &sb_geo, (char *) &fs_geo.sb_shared_vn - (char *) &fs_geo)) return(XR_SB_GEO_MISMATCH); return(XR_OK); } /* * Possible fields that may have been set at mkfs time, * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog. * The quota inode fields in the secondaries should be zero. * Likewise, the sb_flags and sb_shared_vn should also be * zero and the shared version bit should be cleared for * current mkfs's. * * And everything else in the buffer beyond either sb_width, * sb_dirblklog (v2 dirs), or sb_logsectsize can be zeroed. * * Note: contrary to the name, this routine is called for all * superblocks, not just the secondary superblocks. */ static int secondary_sb_whack( struct xfs_mount *mp, struct xfs_buf *sbuf, struct xfs_sb *sb, xfs_agnumber_t i) { struct xfs_dsb *dsb = XFS_BUF_TO_SBP(sbuf); int do_bzero = 0; int size; char *ip; int rval = 0; uuid_t tmpuuid; rval = do_bzero = 0; /* * Check for garbage beyond the last valid field. * Use field addresses instead so this code will still * work against older filesystems when the superblock * gets rev'ed again with new fields appended. * * size is the size of data which is valid for this sb. */ if (xfs_sb_version_hasmetauuid(sb)) size = offsetof(xfs_sb_t, sb_meta_uuid) + sizeof(sb->sb_meta_uuid); else if (xfs_sb_version_hascrc(sb)) size = offsetof(xfs_sb_t, sb_lsn) + sizeof(sb->sb_lsn); else if (xfs_sb_version_hasmorebits(sb)) size = offsetof(xfs_sb_t, sb_bad_features2) + sizeof(sb->sb_bad_features2); else if (xfs_sb_version_haslogv2(sb)) size = offsetof(xfs_sb_t, sb_logsunit) + sizeof(sb->sb_logsunit); else if (xfs_sb_version_hassector(sb)) size = offsetof(xfs_sb_t, sb_logsectsize) + sizeof(sb->sb_logsectsize); else /* only support dirv2 or more recent */ size = offsetof(xfs_sb_t, sb_dirblklog) + sizeof(sb->sb_dirblklog); /* Check the buffer we read from disk for garbage outside size */ for (ip = (char *)sbuf->b_addr + size; ip < (char *)sbuf->b_addr + mp->m_sb.sb_sectsize; ip++) { if (*ip) { do_bzero = 1; break; } } if (do_bzero) { rval |= XR_AG_SB_SEC; if (!no_modify) { do_warn( _("zeroing unused portion of %s superblock (AG #%u)\n"), !i ? _("primary") : _("secondary"), i); /* * zero both the in-memory sb and the disk buffer, * because the former was read from disk and * may contain newer version fields that shouldn't * be set, and the latter is never updated past * the last field - just zap them both. */ memcpy(&tmpuuid, &sb->sb_meta_uuid, sizeof(uuid_t)); memset((void *)((intptr_t)sb + size), 0, mp->m_sb.sb_sectsize - size); memset((char *)sbuf->b_addr + size, 0, mp->m_sb.sb_sectsize - size); /* Preserve meta_uuid so we don't fail uuid checks */ memcpy(&sb->sb_meta_uuid, &tmpuuid, sizeof(uuid_t)); } else do_warn( _("would zero unused portion of %s superblock (AG #%u)\n"), !i ? _("primary") : _("secondary"), i); } /* * now look for the fields we can manipulate directly. * if we did a zero and that zero could have included * the field in question, just silently reset it. otherwise, * complain. * * for now, just zero the flags field since only * the readonly flag is used */ if (sb->sb_flags) { if (!no_modify) sb->sb_flags = 0; if (!do_bzero) { rval |= XR_AG_SB; do_warn(_("bad flags field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } /* * quota inodes and flags in secondary superblocks are never set by * mkfs. However, they could be set in a secondary if a fs with quotas * was growfs'ed since growfs copies the new primary into the * secondaries. * * Also, the in-core inode flags now have different meaning to the * on-disk flags, and so libxfs_sb_to_disk cannot directly write the * sb_gquotino/sb_pquotino fields without specific sb_qflags being set. * Hence we need to zero those fields directly in the sb buffer here. */ if (sb->sb_inprogress == 1 && sb->sb_uquotino != NULLFSINO) { if (!no_modify) sb->sb_uquotino = 0; if (!do_bzero) { rval |= XR_AG_SB; do_warn( _("non-null user quota inode field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (sb->sb_inprogress == 1 && sb->sb_gquotino != NULLFSINO) { if (!no_modify) { sb->sb_gquotino = 0; dsb->sb_gquotino = 0; } if (!do_bzero) { rval |= XR_AG_SB; do_warn( _("non-null group quota inode field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } /* * Note that sb_pquotino is not considered a valid sb field for pre-v5 * superblocks. If it is anything other than 0 it is considered garbage * data beyond the valid sb and explicitly zeroed above. */ if (xfs_sb_version_has_pquotino(&mp->m_sb) && sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO) { if (!no_modify) { sb->sb_pquotino = 0; dsb->sb_pquotino = 0; } if (!do_bzero) { rval |= XR_AG_SB; do_warn( _("non-null project quota inode field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (sb->sb_inprogress == 1 && sb->sb_qflags) { if (!no_modify) sb->sb_qflags = 0; if (!do_bzero) { rval |= XR_AG_SB; do_warn(_("non-null quota flags in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } /* * if the secondaries agree on a stripe unit/width or inode * alignment, those fields ought to be valid since they are * written at mkfs time (and the corresponding sb version bits * are set). */ if (!xfs_sb_version_hasalign(sb) && sb->sb_inoalignmt != 0) { if (!no_modify) sb->sb_inoalignmt = 0; if (!do_bzero) { rval |= XR_AG_SB; do_warn( _("bad inode alignment field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (!xfs_sb_version_hasdalign(sb) && (sb->sb_unit != 0 || sb->sb_width != 0)) { if (!no_modify) sb->sb_unit = sb->sb_width = 0; if (!do_bzero) { rval |= XR_AG_SB; do_warn( _("bad stripe unit/width fields in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (!xfs_sb_version_hassector(sb) && (sb->sb_sectsize != BBSIZE || sb->sb_sectlog != BBSHIFT || sb->sb_logsectsize != 0 || sb->sb_logsectlog != 0)) { if (!no_modify) { sb->sb_sectsize = BBSIZE; sb->sb_sectlog = BBSHIFT; sb->sb_logsectsize = 0; sb->sb_logsectlog = 0; } if (!do_bzero) { rval |= XR_AG_SB; do_warn( _("bad log/data device sector size fields in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } return(rval); } /* * verify and reset the ag header if required. * * lower 4 bits of rval are set depending on what got modified. * (see agheader.h for more details) * * NOTE -- this routine does not tell the user that it has * altered things. Rather, it is up to the caller to do so * using the bits encoded into the return value. */ int verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb, xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i) { int rval = 0; int status = XR_OK; int status_sb = XR_OK; status = verify_sb(sbuf->b_addr, sb, (i == 0)); if (status != XR_OK) { do_warn(_("bad on-disk superblock %d - %s\n"), i, err_string(status)); } status_sb = compare_sb(mp, sb); if (status_sb != XR_OK) { do_warn(_("primary/secondary superblock %d conflict - %s\n"), i, err_string(status_sb)); } if (status != XR_OK || status_sb != XR_OK) { if (!no_modify) { *sb = mp->m_sb; /* * clear the more transient fields */ sb->sb_inprogress = 1; sb->sb_icount = 0; sb->sb_ifree = 0; sb->sb_fdblocks = 0; sb->sb_frextents = 0; sb->sb_qflags = 0; } rval |= XR_AG_SB; } rval |= secondary_sb_whack(mp, sbuf, sb, i); rval |= verify_set_agf(mp, agf, i); rval |= verify_set_agi(mp, agi, i); return(rval); } xfsprogs-5.3.0/repair/agheader.h0000644000175000017500000000532113435336037016447 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ typedef struct fs_geometry { /* * these types should match the superblock types */ uint32_t sb_blocksize; /* blocksize (bytes) */ xfs_rfsblock_t sb_dblocks; /* # data blocks */ xfs_rfsblock_t sb_rblocks; /* # realtime blocks */ xfs_rtblock_t sb_rextents; /* # realtime extents */ xfs_fsblock_t sb_logstart; /* starting log block # */ xfs_agblock_t sb_rextsize; /* realtime extent size (blocks )*/ xfs_agblock_t sb_agblocks; /* # of blocks per ag */ xfs_agnumber_t sb_agcount; /* # of ags */ xfs_extlen_t sb_rbmblocks; /* # of rt bitmap blocks */ xfs_extlen_t sb_logblocks; /* # of log blocks */ uint16_t sb_sectsize; /* volume sector size (bytes) */ uint16_t sb_inodesize; /* inode size (bytes) */ uint8_t sb_imax_pct; /* max % of fs for inode space */ /* * these don't have to match the superblock types but are placed * before sb_shared_vn because these values don't have to be * checked manually. These variables will be set only on * filesystems with dependably good (fully initialized) * secondary superblock sectors, will be stamped in all * superblocks at mkfs time, and are features that cannot * be downgraded unless all superblocks in the filesystem * are rewritten. */ int sb_extflgbit; /* extent flag feature bit set */ /* * fields after this point have to be checked manually in compare_sb() */ uint8_t sb_shared_vn; /* shared version number */ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ uint32_t sb_unit; /* stripe or raid unit */ uint32_t sb_width; /* stripe or width unit */ /* * these don't have to match, they track superblock properties * that could have been upgraded and/or downgraded during * run-time so that the primary superblock has them but the * secondaries do not. * Plus, they have associated data fields whose data fields may * be corrupt in cases where the filesystem was made on a * pre-6.5 campus alpha mkfs and the feature was enabled on * the filesystem later. */ int sb_ialignbit; /* sb has inode alignment bit set */ int sb_salignbit; /* sb has stripe alignment bit set */ int sb_sharedbit; /* sb has inode alignment bit set */ int sb_fully_zeroed; /* has zeroed secondary sb sectors */ } fs_geometry_t; typedef struct fs_geo_list { struct fs_geo_list *next; int refs; int index; fs_geometry_t geo; } fs_geo_list_t; /* * fields for sb_last_nonzero */ #define XR_SB_COUNTERS 0x0001 #define XR_SB_INOALIGN 0x0002 #define XR_SB_SALIGN 0x0004 /* * what got modified by verify_set_* routines */ #define XR_AG_SB 0x1 #define XR_AG_AGF 0x2 #define XR_AG_AGI 0x4 #define XR_AG_SB_SEC 0x8 xfsprogs-5.3.0/repair/attr_repair.c0000644000175000017500000010644513570057155017230 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "globals.h" #include "err_protos.h" #include "attr_repair.h" #include "dinode.h" #include "bmap.h" #include "protos.h" #include "dir2.h" #include "da_util.h" static int xfs_acl_valid(struct xfs_mount *mp, struct xfs_acl *daclp); static int xfs_mac_valid(xfs_mac_label_t *lp); /* * da node check/verify functions that the attribute tree relies on are first in * the file before the actual attribute code. This used to be shared with the * dir v1 code, but that format is no longer supported yb the userspace * utilities and hence is now specific to the attribute tree implementation. */ typedef unsigned char da_freemap_t; /* * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte) * 1 == used, 0 == free. */ static da_freemap_t * alloc_da_freemap(struct xfs_mount *mp) { return calloc(1, mp->m_sb.sb_blocksize / NBBY); } /* * Set the he range [start, stop) in the directory freemap. * * Returns 1 if there is a conflict or 0 if everything's good. * * Within a char, the lowest bit of the char represents the byte with * the smallest address */ static int set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop) { const da_freemap_t mask = 0x1; int i; if (start > stop) { /* * allow == relation since [x, x) claims 1 byte */ do_warn(_("bad range claimed [%d, %d) in da block\n"), start, stop); return(1); } if (stop > mp->m_sb.sb_blocksize) { do_warn( _("byte range end [%d %d) in da block larger than blocksize %d\n"), start, stop, mp->m_sb.sb_blocksize); return(1); } for (i = start; i < stop; i ++) { if (map[i / NBBY] & (mask << i % NBBY)) { do_warn(_("multiply claimed byte %d in da block\n"), i); return(1); } map[i / NBBY] |= (mask << i % NBBY); } return(0); } /* * For attribute repair, there are 3 formats to worry about. First, is * shortform attributes which reside in the inode. Second is the leaf * form, and lastly the btree. Much of this models after the directory * structure so code resembles the directory repair cases. * For shortform case, if an attribute looks corrupt, it is removed. * If that leaves the shortform down to 0 attributes, it's okay and * will appear to just have a null attribute fork. Some checks are done * for validity of the value field based on what the security needs are. * Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the * security attributes exist. They will be cleared if invalid. * No other values will be checked. The DMF folks do not have current * requirements, but may in the future. * * For leaf block attributes, it requires more processing. One sticky * point is that the attributes can be local (within the leaf) or * remote (outside the leaf in other blocks). Thinking of local only * if you get a bad attribute, and want to delete just one, it's a-okay * if it remains large enough to still be a leaf block attribute. Otherwise, * it may have to be converted to shortform. How to convert this and when * is an issue. This call is happening in Phase3. Phase5 will capture empty * blocks, but Phase6 allows you to use the libxfs library which knows * how to handle attributes in the kernel for converting formats. What we * could do is mark an attribute to be cleared now, but in phase6 somehow * have it cleared for real and then the format changed to shortform if * applicable. Since this requires more work than I anticipate can be * accomplished for the next release, we will instead just say any bad * attribute in the leaf block will make the entire attribute fork be * cleared. The simplest way to do that is to ignore the leaf format, and * call clear_dinode_attr to just make a shortform attribute fork with * zero entries. * * Another issue with handling repair on leaf attributes is the remote * blocks. To make sure that they look good and are not used multiple times * by the attribute fork, some mechanism to keep track of all them is necessary. * Do this in the future, time permitting. For now, note that there is no * check for remote blocks and their allocations. * * For btree formatted attributes, the model can follow directories. That * would mean go down the tree to the leftmost leaf. From there moving down * the links and processing each. They would call back up the tree, to verify * that the tree structure is okay. Any problems will result in the attribute * fork being emptied and put in shortform format. */ /* * This routine just checks what security needs are for attribute values * only called when root flag is set, otherwise these names could exist in * in user attribute land without a conflict. * If value is non-zero, then a remote attribute is being passed in */ static int valuecheck( struct xfs_mount *mp, char *namevalue, char *value, int namelen, int valuelen) { /* for proper alignment issues, get the structs and memmove the values */ xfs_mac_label_t macl; void *valuep; int clearit = 0; if ((namelen == SGI_ACL_FILE_SIZE && strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) || (namelen == SGI_ACL_DEFAULT_SIZE && strncmp(namevalue, SGI_ACL_DEFAULT, SGI_ACL_DEFAULT_SIZE) == 0)) { if (value == NULL) { valuep = malloc(valuelen); if (!valuep) do_error(_("No memory for ACL check!\n")); memcpy(valuep, namevalue + namelen, valuelen); } else valuep = value; if (xfs_acl_valid(mp, valuep) != 0) { clearit = 1; do_warn( _("entry contains illegal value in attribute named SGI_ACL_FILE " "or SGI_ACL_DEFAULT\n")); } if (valuep != value) free(valuep); } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) { if (value == NULL) { memset(&macl, 0, sizeof(xfs_mac_label_t)); memmove(&macl, namevalue+namelen, valuelen); valuep = &macl; } else valuep = value; if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */ /* * if sysconf says MAC enabled, * temp = mac_from_text("msenhigh/mintlow", NULL) * copy it to value, update valuelen, totsize * This causes pushing up or down of all following * attributes, forcing a attribute format change!! * else clearit = 1; */ clearit = 1; do_warn( _("entry contains illegal value in attribute named SGI_MAC_LABEL\n")); } } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) { if ( valuelen != sizeof(xfs_cap_set_t)) { clearit = 1; do_warn( _("entry contains illegal value in attribute named SGI_CAP_FILE\n")); } } return(clearit); } /* * this routine validates the attributes in shortform format. * a non-zero return repair value means certain attributes are bogus * and were cleared if possible. Warnings do not generate error conditions * if you cannot modify the structures. repair is set to 1, if anything * was fixed. */ static int process_shortform_attr( struct xfs_mount *mp, xfs_ino_t ino, xfs_dinode_t *dip, int *repair) { xfs_attr_shortform_t *asf; xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry; int i, junkit; int currentsize, remainingspace; *repair = 0; asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip); /* Assumption: hdr.totsize is less than a leaf block and was checked * by lclinode for valid sizes. Check the count though. */ if (asf->hdr.count == 0) /* then the total size should just be the header length */ if (be16_to_cpu(asf->hdr.totsize) != sizeof(xfs_attr_sf_hdr_t)) { /* whoops there's a discrepancy. Clear the hdr */ if (!no_modify) { do_warn( _("there are no attributes in the fork for inode %" PRIu64 "\n"), ino); asf->hdr.totsize = cpu_to_be16(sizeof(xfs_attr_sf_hdr_t)); *repair = 1; return(1); } else { do_warn( _("would junk the attribute fork since count is 0 for inode %" PRIu64 "\n"), ino); return(1); } } currentsize = sizeof(xfs_attr_sf_hdr_t); remainingspace = be16_to_cpu(asf->hdr.totsize) - currentsize; nextentry = &asf->list[0]; for (i = 0; i < asf->hdr.count; i++) { currententry = nextentry; junkit = 0; /* don't go off the end if the hdr.count was off */ if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) > be16_to_cpu(asf->hdr.totsize)) break; /* get out and reset count and totSize */ /* if the namelen is 0, can't get to the rest of the entries */ if (currententry->namelen == 0) { do_warn(_("zero length name entry in attribute fork,")); if (!no_modify) { do_warn( _(" truncating attributes for inode %" PRIu64 " to %d\n"), ino, i); *repair = 1; break; /* and then update hdr fields */ } else { do_warn( _(" would truncate attributes for inode %" PRIu64 " to %d\n"), ino, i); break; } } else { /* It's okay to have a 0 length valuelen, but do a * rough check to make sure we haven't gone outside of * totsize. */ if (remainingspace < currententry->namelen || ((remainingspace - currententry-> namelen) < currententry->valuelen)) { do_warn( _("name or value attribute lengths are too large,\n")); if (!no_modify) { do_warn( _(" truncating attributes for inode %" PRIu64 " to %d\n"), ino, i); *repair = 1; break; /* and then update hdr fields */ } else { do_warn( _(" would truncate attributes for inode %" PRIu64 " to %d\n"), ino, i); break; } } } /* namecheck checks for null chars in attr names. */ if (!libxfs_attr_namecheck(currententry->nameval, currententry->namelen)) { do_warn( _("entry contains illegal character in shortform attribute name\n")); junkit = 1; } if (currententry->flags & XFS_ATTR_INCOMPLETE) { do_warn( _("entry has INCOMPLETE flag on in shortform attribute\n")); junkit = 1; } /* Only check values for root security attributes */ if (currententry->flags & XFS_ATTR_ROOT) junkit |= valuecheck(mp, (char *)¤tentry->nameval[0], NULL, currententry->namelen, currententry->valuelen); remainingspace = remainingspace - XFS_ATTR_SF_ENTSIZE(currententry); if (junkit) { if (!no_modify) { /* get rid of only this entry */ do_warn( _("removing attribute entry %d for inode %" PRIu64 "\n"), i, ino); tempentry = (xfs_attr_sf_entry_t *) ((intptr_t) currententry + XFS_ATTR_SF_ENTSIZE(currententry)); memmove(currententry,tempentry,remainingspace); asf->hdr.count -= 1; i--; /* no worries, it will wrap back to 0 */ *repair = 1; continue; /* go back up now */ } else { do_warn( _("would remove attribute entry %d for inode %" PRIu64 "\n"), i, ino); } } /* Let's get ready for the next entry... */ nextentry = (xfs_attr_sf_entry_t *)((intptr_t) nextentry + XFS_ATTR_SF_ENTSIZE(currententry)); currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry); } /* end the loop */ if (asf->hdr.count != i) { if (no_modify) { do_warn( _("would have corrected attribute entry count in inode %" PRIu64 " from %d to %d\n"), ino, asf->hdr.count, i); } else { do_warn( _("corrected attribute entry count in inode %" PRIu64 ", was %d, now %d\n"), ino, asf->hdr.count, i); asf->hdr.count = i; *repair = 1; } } /* ASSUMPTION: currentsize <= totsize */ if (be16_to_cpu(asf->hdr.totsize) != currentsize) { if (no_modify) { do_warn( _("would have corrected attribute totsize in inode %" PRIu64 " from %d to %d\n"), ino, be16_to_cpu(asf->hdr.totsize), currentsize); } else { do_warn( _("corrected attribute entry totsize in inode %" PRIu64 ", was %d, now %d\n"), ino, be16_to_cpu(asf->hdr.totsize), currentsize); asf->hdr.totsize = cpu_to_be16(currentsize); *repair = 1; } } return(*repair); } /* This routine brings in blocks from disk one by one and assembles them * in the value buffer. If get_bmapi gets smarter later to return an extent * or list of extents, that would be great. For now, we don't expect too * many blocks per remote value, so one by one is sufficient. */ static int rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap, xfs_dablk_t blocknum, int valuelen, char* value) { xfs_fsblock_t bno; xfs_buf_t *bp; int clearit = 0, i = 0, length = 0, amountdone = 0; int hdrsize = 0; if (xfs_sb_version_hascrc(&mp->m_sb)) hdrsize = sizeof(struct xfs_attr3_rmt_hdr); /* ASSUMPTION: valuelen is a valid number, so use it for looping */ /* Note that valuelen is not a multiple of blocksize */ while (amountdone < valuelen) { bno = blkmap_get(blkmap, blocknum + i); if (bno == NULLFSBLOCK) { do_warn( _("remote block for attributes of inode %" PRIu64 " is missing\n"), ino); clearit = 1; break; } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), XFS_FSB_TO_BB(mp, 1), 0, &xfs_attr3_rmt_buf_ops); if (!bp) { do_warn( _("can't read remote block for attributes of inode %" PRIu64 "\n"), ino); clearit = 1; break; } if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) { do_warn( _("Corrupt remote block for attributes of inode %" PRIu64 "\n"), ino); libxfs_putbuf(bp); clearit = 1; break; } ASSERT(mp->m_sb.sb_blocksize == bp->b_bcount); length = min(bp->b_bcount - hdrsize, valuelen - amountdone); memmove(value, bp->b_addr + hdrsize, length); amountdone += length; value += length; i++; libxfs_putbuf(bp); } return (clearit); } /* The block is read in. The magic number and forward / backward * links are checked by the caller process_leaf_attr. * If any problems occur the routine returns with non-zero. In * this case the next step is to clear the attribute fork, by * changing it to shortform and zeroing it out. Forkoff need not * be changed. */ static int process_leaf_attr_local( struct xfs_mount *mp, xfs_attr_leafblock_t *leaf, int i, xfs_attr_leaf_entry_t *entry, xfs_dahash_t last_hashval, xfs_dablk_t da_bno, xfs_ino_t ino) { xfs_attr_leaf_name_local_t *local; local = xfs_attr3_leaf_name_local(leaf, i); if (local->namelen == 0 || !libxfs_attr_namecheck(local->nameval, local->namelen)) { do_warn( _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"), i, da_bno, ino, local->namelen); return -1; } /* Check on the hash value. Checking order of values * is not necessary, since one wrong clears the whole * fork. If the ordering's wrong, it's caught here or * the kernel code has a bug with transaction logging * or attributes itself. Being paranoid, let's check * ordering anyway in case both the name value and the * hashvalue were wrong but matched. Unlikely, however. */ if (be32_to_cpu(entry->hashval) != libxfs_da_hashname( &local->nameval[0], local->namelen) || be32_to_cpu(entry->hashval) < last_hashval) { do_warn( _("bad hashvalue for attribute entry %d in attr block %u, inode %" PRIu64 "\n"), i, da_bno, ino); return -1; } /* Only check values for root security attributes */ if (entry->flags & XFS_ATTR_ROOT) { if (valuecheck(mp, (char *)&local->nameval[0], NULL, local->namelen, be16_to_cpu(local->valuelen))) { do_warn( _("bad security value for attribute entry %d in attr block %u, inode %" PRIu64 "\n"), i, da_bno, ino); return -1; } } return xfs_attr_leaf_entsize_local(local->namelen, be16_to_cpu(local->valuelen)); } static int process_leaf_attr_remote( xfs_attr_leafblock_t *leaf, int i, xfs_attr_leaf_entry_t *entry, xfs_dahash_t last_hashval, xfs_dablk_t da_bno, xfs_ino_t ino, xfs_mount_t *mp, blkmap_t *blkmap) { xfs_attr_leaf_name_remote_t *remotep; char* value; remotep = xfs_attr3_leaf_name_remote(leaf, i); if (remotep->namelen == 0 || !libxfs_attr_namecheck(remotep->name, remotep->namelen) || be32_to_cpu(entry->hashval) != libxfs_da_hashname((unsigned char *)&remotep->name[0], remotep->namelen) || be32_to_cpu(entry->hashval) < last_hashval || be32_to_cpu(remotep->valueblk) == 0) { do_warn( _("inconsistent remote attribute entry %d in attr block %u, ino %" PRIu64 "\n"), i, da_bno, ino); return -1; } value = malloc(be32_to_cpu(remotep->valuelen)); if (value == NULL) { do_warn( _("cannot malloc enough for remotevalue attribute for inode %" PRIu64 "\n"), ino); do_warn(_("SKIPPING this remote attribute\n")); goto out; } if (rmtval_get(mp, ino, blkmap, be32_to_cpu(remotep->valueblk), be32_to_cpu(remotep->valuelen), value)) { do_warn( _("remote attribute get failed for entry %d, inode %" PRIu64 "\n"), i, ino); goto bad_free_out; } if ((entry->flags & XFS_ATTR_ROOT) && valuecheck(mp, (char *)&remotep->name[0], value, remotep->namelen, be32_to_cpu(remotep->valuelen))) { do_warn( _("remote attribute value check failed for entry %d, inode %" PRIu64 "\n"), i, ino); goto bad_free_out; } free(value); out: return xfs_attr_leaf_entsize_remote(remotep->namelen); bad_free_out: free(value); return -1; } static int process_leaf_attr_block( xfs_mount_t *mp, xfs_attr_leafblock_t *leaf, xfs_dablk_t da_bno, xfs_ino_t ino, blkmap_t *blkmap, xfs_dahash_t last_hashval, xfs_dahash_t *current_hashval, int *repair) { xfs_attr_leaf_entry_t *entry; int i, start, stop, clearit, usedbs, firstb, thissize; da_freemap_t *attr_freemap; struct xfs_attr3_icleaf_hdr leafhdr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); clearit = usedbs = 0; firstb = mp->m_sb.sb_blocksize; stop = xfs_attr3_leaf_hdr_size(leaf); /* does the count look sorta valid? */ if (!leafhdr.count || leafhdr.count * sizeof(xfs_attr_leaf_entry_t) + stop > mp->m_sb.sb_blocksize) { do_warn( _("bad attribute count %d in attr block %u, inode %" PRIu64 "\n"), leafhdr.count, da_bno, ino); return 1; } attr_freemap = alloc_da_freemap(mp); (void) set_da_freemap(mp, attr_freemap, 0, stop); /* go thru each entry checking for problems */ for (i = 0, entry = xfs_attr3_leaf_entryp(leaf); i < leafhdr.count; i++, entry++) { /* check if index is within some boundary. */ if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) { do_warn( _("bad attribute nameidx %d in attr block %u, inode %" PRIu64 "\n"), be16_to_cpu(entry->nameidx), da_bno, ino); clearit = 1; break; } if (entry->flags & XFS_ATTR_INCOMPLETE) { /* we are inconsistent state. get rid of us */ do_warn( _("attribute entry #%d in attr block %u, inode %" PRIu64 " is INCOMPLETE\n"), i, da_bno, ino); clearit = 1; break; } /* mark the entry used */ start = (intptr_t)entry - (intptr_t)leaf; stop = start + sizeof(xfs_attr_leaf_entry_t); if (set_da_freemap(mp, attr_freemap, start, stop)) { do_warn( _("attribute entry %d in attr block %u, inode %" PRIu64 " claims already used space\n"), i, da_bno, ino); clearit = 1; break; /* got an overlap */ } if (entry->flags & XFS_ATTR_LOCAL) thissize = process_leaf_attr_local(mp, leaf, i, entry, last_hashval, da_bno, ino); else thissize = process_leaf_attr_remote(leaf, i, entry, last_hashval, da_bno, ino, mp, blkmap); if (thissize < 0) { clearit = 1; break; } *current_hashval = last_hashval = be32_to_cpu(entry->hashval); if (set_da_freemap(mp, attr_freemap, be16_to_cpu(entry->nameidx), be16_to_cpu(entry->nameidx) + thissize)) { do_warn( _("attribute entry %d in attr block %u, inode %" PRIu64 " claims used space\n"), i, da_bno, ino); clearit = 1; break; /* got an overlap */ } usedbs += thissize; if (be16_to_cpu(entry->nameidx) < firstb) firstb = be16_to_cpu(entry->nameidx); } /* end the loop */ if (!clearit) { /* verify the header information is correct */ /* if the holes flag is set, don't reset first_used unless it's * pointing to used bytes. we're being conservative here * since the block will get compacted anyhow by the kernel. */ if ((leafhdr.holes == 0 && firstb != leafhdr.firstused) || leafhdr.firstused > firstb) { if (!no_modify) { do_warn( _("- resetting first used heap value from %d to %d in " "block %u of attribute fork of inode %" PRIu64 "\n"), leafhdr.firstused, firstb, da_bno, ino); leafhdr.firstused = firstb; *repair = 1; } else { do_warn( _("- would reset first used value from %d to %d in " "block %u of attribute fork of inode %" PRIu64 "\n"), leafhdr.firstused, firstb, da_bno, ino); } } if (usedbs != leafhdr.usedbytes) { if (!no_modify) { do_warn( _("- resetting usedbytes cnt from %d to %d in " "block %u of attribute fork of inode %" PRIu64 "\n"), leafhdr.usedbytes, usedbs, da_bno, ino); leafhdr.usedbytes = usedbs; *repair = 1; } else { do_warn( _("- would reset usedbytes cnt from %d to %d in " "block %u of attribute fork of %" PRIu64 "\n"), leafhdr.usedbytes, usedbs, da_bno, ino); } } /* there's a lot of work in process_leaf_dir_block to go thru * checking for holes and compacting if appropiate. I don't think * attributes need all that, so let's just leave the holes. If * we discover later that this is a good place to do compaction * we can add it then. */ } /* * If we're just going to zap the block, don't pretend like we * repaired it, because repairing the block stops the clear * operation. */ if (clearit) *repair = 0; if (*repair) xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr); free(attr_freemap); return (clearit); /* and repair */ } /* * returns 0 if the attribute fork is ok, 1 if it has to be junked. */ static int process_leaf_attr_level(xfs_mount_t *mp, da_bt_cursor_t *da_cursor) { int repair; xfs_attr_leafblock_t *leaf; xfs_buf_t *bp; xfs_ino_t ino; xfs_fsblock_t dev_bno; xfs_dablk_t da_bno; xfs_dablk_t prev_bno; xfs_dahash_t current_hashval = 0; xfs_dahash_t greatest_hashval; struct xfs_attr3_icleaf_hdr leafhdr; da_bno = da_cursor->level[0].bno; ino = da_cursor->ino; /* * 0 is the root block and no block * pointer can point to the root block of the btree */ if (da_bno == 0) { do_warn( _("btree cycle detected in attribute fork for inode %" PRIu64 "\n"), ino); goto error_out; } prev_bno = 0; do { repair = 0; dev_bno = blkmap_get(da_cursor->blkmap, da_bno); if (dev_bno == NULLFSBLOCK) { do_warn( _("can't map block %u for attribute fork for inode %" PRIu64 "\n"), da_bno, ino); goto error_out; } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno), XFS_FSB_TO_BB(mp, 1), 0, &xfs_attr3_leaf_buf_ops); if (!bp) { do_warn( _("can't read file block %u (fsbno %" PRIu64 ") for attribute fork of inode %" PRIu64 "\n"), da_bno, dev_bno, ino); goto error_out; } leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); /* check magic number for leaf directory btree block */ if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC || leafhdr.magic == XFS_ATTR3_LEAF_MAGIC)) { do_warn( _("bad attribute leaf magic %#x for inode %" PRIu64 "\n"), leafhdr.magic, ino); libxfs_putbuf(bp); goto error_out; } /* * for each block, process the block, verify its path, * then get next block. update cursor values along the way */ if (process_leaf_attr_block(mp, leaf, da_bno, ino, da_cursor->blkmap, current_hashval, &greatest_hashval, &repair)) { libxfs_putbuf(bp); goto error_out; } /* * index can be set to hdr.count so match the * indexes of the interior blocks -- which at the * end of the block will point to 1 after the final * real entry in the block */ da_cursor->level[0].hashval = greatest_hashval; da_cursor->level[0].bp = bp; da_cursor->level[0].bno = da_bno; da_cursor->level[0].index = leafhdr.count; da_cursor->level[0].dirty = repair; if (leafhdr.back != prev_bno) { do_warn( _("bad sibling back pointer for block %u in attribute fork for inode %" PRIu64 "\n"), da_bno, ino); libxfs_putbuf(bp); goto error_out; } prev_bno = da_bno; da_bno = leafhdr.forw; if (da_bno != 0) { if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) { libxfs_putbuf(bp); goto error_out; } } current_hashval = greatest_hashval; /* * If block looks ok but CRC didn't match, make sure to * recompute it. */ if (!no_modify && bp->b_error == -EFSBADCRC) repair++; if (repair && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); } while (da_bno != 0); if (verify_final_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) { /* * verify the final path up (right-hand-side) if still ok */ do_warn( _("bad hash path in attribute fork for inode %" PRIu64 "\n"), da_cursor->ino); goto error_out; } /* releases all buffers holding interior btree blocks */ release_da_cursor(mp, da_cursor, 0); return(0); error_out: /* release all buffers holding interior btree blocks */ err_release_da_cursor(mp, da_cursor, 0); return(1); } /* * a node directory is a true btree -- where the attribute fork * has gotten big enough that it is represented as a non-trivial (e.g. * has more than just a block) btree. * * Note that if we run into any problems, we will trash the attribute fork. * * returns 0 if things are ok, 1 if bad * Note this code has been based off process_node_dir. */ static int process_node_attr( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, blkmap_t *blkmap) { xfs_dablk_t bno; int error = 0; da_bt_cursor_t da_cursor; /* * try again -- traverse down left-side of tree until we hit * the left-most leaf block setting up the btree cursor along * the way. Then walk the leaf blocks left-to-right, calling * a parent-verification routine each time we traverse a block. */ memset(&da_cursor, 0, sizeof(da_bt_cursor_t)); da_cursor.active = 0; da_cursor.ino = ino; da_cursor.dip = dip; da_cursor.greatest_bno = 0; da_cursor.blkmap = blkmap; /* * now process interior node. don't have any buffers held in this path. */ error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK); if (error == 0) return(1); /* 0 means unsuccessful */ /* * now pass cursor and bno into leaf-block processing routine * the leaf dir level routine checks the interior paths * up to the root including the final right-most path. */ return (process_leaf_attr_level(mp, &da_cursor)); } /* check v5 metadata */ static int __check_attr_header( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino) { struct xfs_da3_blkinfo *info = bp->b_addr; if (info->hdr.magic != cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) && info->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC)) return 0; /* verify owner */ if (be64_to_cpu(info->owner) != ino) { do_warn( _("expected owner inode %" PRIu64 ", got %llu, attr block %" PRIu64 "\n"), ino, (unsigned long long)be64_to_cpu(info->owner), bp->b_bn); return 1; } /* verify block number */ if (be64_to_cpu(info->blkno) != bp->b_bn) { do_warn( _("expected block %" PRIu64 ", got %llu, inode %" PRIu64 "attr block\n"), bp->b_bn, (unsigned long long)be64_to_cpu(info->blkno), ino); return 1; } /* verify uuid */ if (platform_uuid_compare(&info->uuid, &mp->m_sb.sb_meta_uuid) != 0) { do_warn( _("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"), ino, bp->b_bn); return 1; } return 0; } /* * Start processing for a leaf or fuller btree. * A leaf directory is one where the attribute fork is too big for * the inode but is small enough to fit into one btree block * outside the inode. This code is modelled after process_leaf_dir_block. * * returns 0 if things are ok, 1 if bad (attributes needs to be junked) * repair is set, if anything was changed, but attributes can live thru it */ static int process_longform_attr( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, blkmap_t *blkmap, int *repair) /* out - 1 if something was fixed */ { xfs_attr_leafblock_t *leaf; xfs_fsblock_t bno; xfs_buf_t *bp; xfs_dahash_t next_hashval; int repairlinks = 0; struct xfs_attr3_icleaf_hdr leafhdr; int error; *repair = 0; bno = blkmap_get(blkmap, 0); if ( bno == NULLFSBLOCK ) { if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS && be16_to_cpu(dip->di_anextents) == 0) return(0); /* the kernel can handle this state */ do_warn( _("block 0 of inode %" PRIu64 " attribute fork is missing\n"), ino); return(1); } /* FIX FOR bug 653709 -- EKN */ if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) { do_warn( _("agno of attribute fork of inode %" PRIu64 " out of regular partition\n"), ino); return(1); } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), XFS_FSB_TO_BB(mp, 1), 0, &xfs_da3_node_buf_ops); if (!bp) { do_warn( _("can't read block 0 of inode %" PRIu64 " attribute fork\n"), ino); return(1); } if (bp->b_error == -EFSBADCRC) (*repair)++; /* is this block sane? */ if (__check_attr_header(mp, bp, ino)) { *repair = 0; libxfs_putbuf(bp); return 1; } /* verify leaf block */ leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); /* check sibling pointers in leaf block or root block 0 before * we have to release the btree block */ if (leafhdr.forw != 0 || leafhdr.back != 0) { if (!no_modify) { do_warn( _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino); repairlinks = 1; leafhdr.forw = 0; leafhdr.back = 0; xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr); } else { do_warn( _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino); } } /* * use magic number to tell us what type of attribute this is. * it's possible to have a node or leaf attribute in either an * extent format or btree format attribute fork. */ switch (leafhdr.magic) { case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */ case XFS_ATTR3_LEAF_MAGIC: if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap, 0, &next_hashval, repair)) { *repair = 0; /* the block is bad. lose the attribute fork. */ libxfs_putbuf(bp); return(1); } *repair = *repair || repairlinks; break; case XFS_DA_NODE_MAGIC: /* btree-form attribute */ case XFS_DA3_NODE_MAGIC: /* must do this now, to release block 0 before the traversal */ if ((*repair || repairlinks) && !no_modify) { *repair = 1; libxfs_writebuf(bp, 0); } else libxfs_putbuf(bp); error = process_node_attr(mp, ino, dip, blkmap); /* + repair */ if (error) *repair = 0; return error; default: do_warn( _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"), be16_to_cpu(leaf->hdr.info.magic), ino); libxfs_putbuf(bp); *repair = 0; return(1); } if (*repair && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); return(0); /* repair may be set */ } static int xfs_acl_from_disk( struct xfs_mount *mp, struct xfs_icacl **aclp, struct xfs_acl *dacl) { struct xfs_icacl *acl; struct xfs_icacl_entry *ace; struct xfs_acl_entry *dace; int count; int i; count = be32_to_cpu(dacl->acl_cnt); if (count > XFS_ACL_MAX_ENTRIES(mp)) { do_warn(_("Too many ACL entries, count %d\n"), count); *aclp = NULL; return EINVAL; } acl = malloc(sizeof(struct xfs_icacl) + count * sizeof(struct xfs_icacl_entry)); if (!acl) { do_warn(_("cannot malloc enough for ACL attribute\n")); do_warn(_("SKIPPING this ACL\n")); *aclp = NULL; return ENOMEM; } acl->acl_cnt = count; for (i = 0; i < count; i++) { ace = &acl->acl_entry[i]; dace = &dacl->acl_entry[i]; ace->ae_tag = be32_to_cpu(dace->ae_tag); ace->ae_id = be32_to_cpu(dace->ae_id); ace->ae_perm = be16_to_cpu(dace->ae_perm); } *aclp = acl; return 0; } /* * returns 1 if attributes got cleared * and 0 if things are ok. */ int process_attributes( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, blkmap_t *blkmap, int *repair) /* returned if we did repair */ { int err; __u8 aformat = dip->di_aformat; #ifdef DEBUG xfs_attr_shortform_t *asf; asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip); #endif if (aformat == XFS_DINODE_FMT_LOCAL) { ASSERT(be16_to_cpu(asf->hdr.totsize) <= XFS_DFORK_ASIZE(dip, mp)); err = process_shortform_attr(mp, ino, dip, repair); } else if (aformat == XFS_DINODE_FMT_EXTENTS || aformat == XFS_DINODE_FMT_BTREE) { err = process_longform_attr(mp, ino, dip, blkmap, repair); /* if err, convert this to shortform and clear it */ /* if repair and no error, it's taken care of */ } else { do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"), aformat, ino); err = 1; } return (err); /* and repair */ } /* * Validate an ACL */ static int xfs_acl_valid( struct xfs_mount *mp, struct xfs_acl *daclp) { struct xfs_icacl *aclp = NULL; struct xfs_icacl_entry *entry, *e; int user = 0, group = 0, other = 0, mask = 0, mask_required = 0; int i, j; if (daclp == NULL) goto acl_invalid; switch (xfs_acl_from_disk(mp, &aclp, daclp)) { case ENOMEM: return 0; case EINVAL: goto acl_invalid; default: break; } for (i = 0; i < aclp->acl_cnt; i++) { entry = &aclp->acl_entry[i]; if (entry->ae_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) goto acl_invalid; switch (entry->ae_tag) { case ACL_USER_OBJ: if (user++) goto acl_invalid; break; case ACL_GROUP_OBJ: if (group++) goto acl_invalid; break; case ACL_OTHER: if (other++) goto acl_invalid; break; case ACL_USER: case ACL_GROUP: for (j = i + 1; j < aclp->acl_cnt; j++) { e = &aclp->acl_entry[j]; if (e->ae_id == entry->ae_id && e->ae_tag == entry->ae_tag) goto acl_invalid; } mask_required++; break; case ACL_MASK: if (mask++) goto acl_invalid; break; default: goto acl_invalid; } } if (!user || !group || !other || (mask_required && !mask)) goto acl_invalid; free(aclp); return 0; acl_invalid: free(aclp); errno = EINVAL; return (-1); } /* * Check a category or division set to ensure that all values are in * ascending order and each division or category appears only once. */ static int __check_setvalue(const unsigned short *list, unsigned short count) { unsigned short i; for (i = 1; i < count ; i++) if (list[i] <= list[i-1]) return -1; return 0; } /* * xfs_mac_valid(lp) * Check the validity of a MAC label. */ static int xfs_mac_valid(xfs_mac_label_t *lp) { if (lp == NULL) return (0); /* * if the total category set and division set is greater than 250 * report error */ if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS) return(0); /* * check whether the msentype value is valid, and do they have * appropriate level, category association. */ switch (lp->ml_msen_type) { case XFS_MSEN_ADMIN_LABEL: case XFS_MSEN_EQUAL_LABEL: case XFS_MSEN_HIGH_LABEL: case XFS_MSEN_MLD_HIGH_LABEL: case XFS_MSEN_LOW_LABEL: case XFS_MSEN_MLD_LOW_LABEL: if (lp->ml_level != 0 || lp->ml_catcount > 0 ) return (0); break; case XFS_MSEN_TCSEC_LABEL: case XFS_MSEN_MLD_LABEL: if (lp->ml_catcount > 0 && __check_setvalue(lp->ml_list, lp->ml_catcount) == -1) return (0); break; case XFS_MSEN_UNKNOWN_LABEL: default: return (0); } /* * check whether the minttype value is valid, and do they have * appropriate grade, division association. */ switch (lp->ml_mint_type) { case XFS_MINT_BIBA_LABEL: if (lp->ml_divcount > 0 && __check_setvalue(lp->ml_list + lp->ml_catcount, lp->ml_divcount) == -1) return(0); break; case XFS_MINT_EQUAL_LABEL: case XFS_MINT_HIGH_LABEL: case XFS_MINT_LOW_LABEL: if (lp->ml_grade != 0 || lp->ml_divcount > 0 ) return(0); break; default: return(0); } return (1); } xfsprogs-5.3.0/repair/attr_repair.h0000644000175000017500000000625513435336037017232 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2004-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XR_ATTRREPAIR_H #define _XR_ATTRREPAIR_H /* * Access Control Lists */ #define ACL_USER_OBJ 0x01 /* owner */ #define ACL_USER 0x02 /* additional users */ #define ACL_GROUP_OBJ 0x04 /* group */ #define ACL_GROUP 0x08 /* additional groups */ #define ACL_MASK 0x10 /* mask entry */ #define ACL_OTHER 0x20 /* other entry */ #define ACL_READ 04 #define ACL_WRITE 02 #define ACL_EXECUTE 01 typedef uint16_t xfs_acl_perm_t; typedef int32_t xfs_acl_type_t; typedef int32_t xfs_acl_tag_t; typedef int32_t xfs_acl_id_t; /* * "icacl" = in-core ACL. There is no equivalent in the XFS kernel code, * so they are magic names just for repair. The "acl" types are what the kernel * code uses for the on-disk format names, so use them here too for the on-disk * ACL format definitions. */ struct xfs_icacl_entry { xfs_acl_tag_t ae_tag; xfs_acl_id_t ae_id; xfs_acl_perm_t ae_perm; }; struct xfs_icacl { int32_t acl_cnt; struct xfs_icacl_entry acl_entry[0]; }; /* * Mandatory Access Control Labels (IRIX) */ #define XFS_MAC_MAX_SETS 250 typedef struct xfs_mac_label { uint8_t ml_msen_type; /* MSEN label type */ uint8_t ml_mint_type; /* MINT label type */ uint8_t ml_level; /* Hierarchical level */ uint8_t ml_grade; /* Hierarchical grade */ uint16_t ml_catcount; /* Category count */ uint16_t ml_divcount; /* Division count */ /* Category set, then Division set */ uint16_t ml_list[XFS_MAC_MAX_SETS]; } xfs_mac_label_t; /* MSEN label type names. Choose an upper case ASCII character. */ #define XFS_MSEN_ADMIN_LABEL 'A' /* Admin: lowavl_back; avlnode_t *forw = np->avl_forw; avlnode_t *nextino = np->avl_nextino; int bal = np->avl_balance; ASSERT(bal != AVL_BALANCE || (!back && !forw) || (back && forw)); ASSERT(bal != AVL_FORW || forw); ASSERT(bal != AVL_BACK || back); if (forw) { ASSERT(AVL_START(tree, np) < AVL_START(tree, forw)); ASSERT(np->avl_forw->avl_parent == np); ASSERT(back || bal == AVL_FORW); } else { ASSERT(bal != AVL_FORW); ASSERT(bal == AVL_BALANCE || back); ASSERT(bal == AVL_BACK || !back); } if (back) { ASSERT(AVL_START(tree, np) > AVL_START(tree, back)); ASSERT(np->avl_back->avl_parent == np); ASSERT(forw || bal == AVL_BACK); } else { ASSERT(bal != AVL_BACK); ASSERT(bal == AVL_BALANCE || forw); ASSERT(bal == AVL_FORW || !forw); } if (nextino == NULL) ASSERT(forw == NULL); else ASSERT(AVL_END(tree, np) <= AVL_START(tree, nextino)); } static void avl_checktree( avltree_desc_t *tree, avlnode_t *root) { avlnode_t *nlast, *nnext, *np; uintptr_t offset = 0; uintptr_t end; nlast = nnext = root; ASSERT(!nnext || nnext->avl_parent == NULL); while (nnext) { avl_checknode(tree, nnext); end = AVL_END(tree, nnext); if (end <= offset) { if ((np = nnext->avl_forw) && np != nlast) { nlast = nnext; nnext = np; } else { nlast = nnext; nnext = nnext->avl_parent; } continue; } nlast = nnext; if (np = nnext->avl_back) { if (AVL_END(tree, np) > offset) { nnext = np; continue; } } np = nnext; nnext = nnext->avl_forw; if (!nnext) nnext = np->avl_parent; offset = end; } } #else /* ! AVL_DEBUG */ #define avl_checktree(t,x) #endif /* AVL_DEBUG */ /* * Reset balance for np up through tree. * ``direction'' is the way that np's balance * is headed after the deletion of one of its children -- * e.g., deleting a avl_forw child sends avl_balance toward AVL_BACK. * Called only when deleting a node from the tree. */ static void retreat( avltree_desc_t *tree, avlnode_t *np, int direction) { avlnode_t **rootp = &tree->avl_root; avlnode_t *parent; avlnode_t *child; avlnode_t *tmp; int bal; do { ASSERT(direction == AVL_BACK || direction == AVL_FORW); if (np->avl_balance == AVL_BALANCE) { np->avl_balance = direction; return; } parent = np->avl_parent; /* * If balance is being restored, no local node * reorganization is necessary, but may be at * a higher node. Reset direction and continue. */ if (direction != np->avl_balance) { np->avl_balance = AVL_BALANCE; if (parent) { if (parent->avl_forw == np) direction = AVL_BACK; else direction = AVL_FORW; np = parent; continue; } return; } /* * Imbalance. If a avl_forw node was removed, direction * (and, by reduction, np->avl_balance) is/was AVL_BACK. */ if (np->avl_balance == AVL_BACK) { ASSERT(direction == AVL_BACK); child = np->avl_back; bal = child->avl_balance; if (bal != AVL_FORW) /* single LL */ { /* * np gets pushed down to lesser child's * avl_forw branch. * * np-> -D +B * / \ / \ * child-> B deleted A -D * / \ / * A C C */ #ifdef AVL_PRINT if (!(tree->avl_flags & AVLF_DUPLICITY)) cmn_err(CE_CONT, "!LL delete b 0x%x c 0x%x\n", np, child); #endif np->avl_back = child->avl_forw; if (child->avl_forw) child->avl_forw->avl_parent = np; child->avl_forw = np; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = child; direction = AVL_BACK; } else { ASSERT(parent->avl_back == np); parent->avl_back = child; direction = AVL_FORW; } } else { ASSERT(*rootp == np); *rootp = child; } np->avl_parent = child; child->avl_parent = parent; if (bal == AVL_BALANCE) { np->avl_balance = AVL_BACK; child->avl_balance = AVL_FORW; return; } else { np->avl_balance = AVL_BALANCE; child->avl_balance = AVL_BALANCE; np = parent; avl_checktree(tree, *rootp); continue; } } /* child->avl_balance == AVL_FORW double LR rotation * * child's avl_forw node gets promoted up, along with * its avl_forw subtree * * np-> -G C * / \ / \ * child-> +B H -B G * / \ \ / / \ * A +C deleted A D H * \ * D */ #ifdef AVL_PRINT if (!(tree->avl_flags & AVLF_DUPLICITY)) cmn_err(CE_CONT, "!LR delete b 0x%x c 0x%x t 0x%x\n", np, child, child->avl_forw); #endif tmp = child->avl_forw; bal = tmp->avl_balance; child->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = child; tmp->avl_back = child; child->avl_parent = tmp; np->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = np; tmp->avl_forw = np; if (bal == AVL_FORW) child->avl_balance = AVL_BACK; else child->avl_balance = AVL_BALANCE; if (bal == AVL_BACK) np->avl_balance = AVL_FORW; else np->avl_balance = AVL_BALANCE; goto next; } ASSERT(np->avl_balance == AVL_FORW && direction == AVL_FORW); child = np->avl_forw; bal = child->avl_balance; if (bal != AVL_BACK) /* single RR */ { /* * np gets pushed down to greater child's * avl_back branch. * * np-> +B -D * / \ / \ * deleted D <-child +B E * / \ \ * C E C */ #ifdef AVL_PRINT if (!(tree->avl_flags & AVLF_DUPLICITY)) cmn_err(CE_CONT, "!RR delete b 0x%x c 0x%x\n", np, child); #endif np->avl_forw = child->avl_back; if (child->avl_back) child->avl_back->avl_parent = np; child->avl_back = np; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = child; direction = AVL_BACK; } else { ASSERT(parent->avl_back == np); parent->avl_back = child; direction = AVL_FORW; } } else { ASSERT(*rootp == np); *rootp = child; } np->avl_parent = child; child->avl_parent = parent; if (bal == AVL_BALANCE) { np->avl_balance = AVL_FORW; child->avl_balance = AVL_BACK; return; } else { np->avl_balance = AVL_BALANCE; child->avl_balance = AVL_BALANCE; np = parent; avl_checktree(tree, *rootp); continue; } } /* child->avl_balance == AVL_BACK double RL rotation */ #ifdef AVL_PRINT if (!(tree->avl_flags & AVLF_DUPLICITY)) cmn_err(CE_CONT, "!RL delete b 0x%x c 0x%x t 0x%x\n", np, child, child->avl_back); #endif tmp = child->avl_back; bal = tmp->avl_balance; child->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = child; tmp->avl_forw = child; child->avl_parent = tmp; np->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = np; tmp->avl_back = np; if (bal == AVL_BACK) child->avl_balance = AVL_FORW; else child->avl_balance = AVL_BALANCE; if (bal == AVL_FORW) np->avl_balance = AVL_BACK; else np->avl_balance = AVL_BALANCE; next: np->avl_parent = tmp; tmp->avl_balance = AVL_BALANCE; tmp->avl_parent = parent; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = tmp; direction = AVL_BACK; } else { ASSERT(parent->avl_back == np); parent->avl_back = tmp; direction = AVL_FORW; } } else { ASSERT(*rootp == np); *rootp = tmp; return; } np = parent; avl_checktree(tree, *rootp); } while (np); } /* * Remove node from tree. * avl_delete does the local tree manipulations, * calls retreat() to rebalance tree up to its root. */ void avl_delete( avltree_desc_t *tree, avlnode_t *np) { avlnode_t *forw = np->avl_forw; avlnode_t *back = np->avl_back; avlnode_t *parent = np->avl_parent; avlnode_t *nnext; if (np->avl_back) { /* * a left child exits, then greatest left descendent's nextino * is pointing to np; make it point to np->nextino. */ nnext = np->avl_back; while (nnext) { if (!nnext->avl_forw) break; /* can't find anything bigger */ nnext = nnext->avl_forw; } } else if (np->avl_parent) { /* * find nearest ancestor with lesser value. That ancestor's * nextino is pointing to np; make it point to np->nextino */ nnext = np->avl_parent; while (nnext) { if (AVL_END(tree, nnext) <= AVL_END(tree, np)) break; nnext = nnext->avl_parent; } } else nnext = NULL; if (nnext) { ASSERT(nnext->avl_nextino == np); nnext->avl_nextino = np->avl_nextino; /* * Something preceeds np; np cannot be firstino. */ ASSERT(tree->avl_firstino != np); } else { /* * Nothing preceeding np; after deletion, np's nextino * is firstino of tree. */ ASSERT(tree->avl_firstino == np); tree->avl_firstino = np->avl_nextino; } /* * Degenerate cases... */ if (forw == NULL) { forw = back; goto attach; } if (back == NULL) { attach: if (forw) forw->avl_parent = parent; if (parent) { if (parent->avl_forw == np) { parent->avl_forw = forw; retreat(tree, parent, AVL_BACK); } else { ASSERT(parent->avl_back == np); parent->avl_back = forw; retreat(tree, parent, AVL_FORW); } } else { ASSERT(tree->avl_root == np); tree->avl_root = forw; } avl_checktree(tree, tree->avl_root); return; } /* * Harder case: children on both sides. * If back's avl_forw pointer is null, just have back * inherit np's avl_forw tree, remove np from the tree * and adjust balance counters starting at back. * * np-> xI xH (befor retreat()) * / \ / \ * back-> H J G J * / / \ / \ * G ? ? ? ? * / \ * ? ? */ if ((forw = back->avl_forw) == NULL) { /* * AVL_FORW retreat below will set back's * balance to AVL_BACK. */ back->avl_balance = np->avl_balance; back->avl_forw = forw = np->avl_forw; forw->avl_parent = back; back->avl_parent = parent; if (parent) { if (parent->avl_forw == np) parent->avl_forw = back; else { ASSERT(parent->avl_back == np); parent->avl_back = back; } } else { ASSERT(tree->avl_root == np); tree->avl_root = back; } /* * back is taking np's place in the tree, and * has therefore lost a avl_back node (itself). */ retreat(tree, back, AVL_FORW); avl_checktree(tree, tree->avl_root); return; } /* * Hardest case: children on both sides, and back's * avl_forw pointer isn't null. Find the immediately * inferior buffer by following back's avl_forw line * to the end, then have it inherit np's avl_forw tree. * * np-> xI xH * / \ / \ * G J back-> G J (before retreat()) * / \ / \ * F ?... F ?1 * / \ * ? H <-forw * / * ?1 */ while ((back = forw->avl_forw)) forw = back; /* * Will be adjusted by retreat() below. */ forw->avl_balance = np->avl_balance; /* * forw inherits np's avl_forw... */ forw->avl_forw = np->avl_forw; np->avl_forw->avl_parent = forw; /* * ... forw's parent gets forw's avl_back... */ back = forw->avl_parent; back->avl_forw = forw->avl_back; if (forw->avl_back) forw->avl_back->avl_parent = back; /* * ... forw gets np's avl_back... */ forw->avl_back = np->avl_back; np->avl_back->avl_parent = forw; /* * ... and forw gets np's parent. */ forw->avl_parent = parent; if (parent) { if (parent->avl_forw == np) parent->avl_forw = forw; else parent->avl_back = forw; } else { ASSERT(tree->avl_root == np); tree->avl_root = forw; } /* * What used to be forw's parent is the starting * point for rebalancing. It has lost a avl_forw node. */ retreat(tree, back, AVL_BACK); avl_checktree(tree, tree->avl_root); } /* * avl_findanyrange: * * Given range r [start, end), find any range which is contained in r. * if checklen is non-zero, then only ranges of non-zero length are * considered in finding a match. */ avlnode_t * avl_findanyrange( avltree_desc_t *tree, uintptr_t start, uintptr_t end, int checklen) { avlnode_t *np = tree->avl_root; /* np = avl_findadjacent(tree, start, AVL_SUCCEED); */ while (np) { if (start < AVL_START(tree, np)) { if (np->avl_back) { np = np->avl_back; continue; } /* if we were to add node with start, would * have a growth of AVL_BACK */ /* if succeeding node is needed, this is it. */ break; } if (start >= AVL_END(tree, np)) { if (np->avl_forw) { np = np->avl_forw; continue; } /* if we were to add node with start, would * have a growth of AVL_FORW; */ /* we are looking for a succeeding node; * this is nextino. */ np = np->avl_nextino; break; } /* AVL_START(tree, np) <= start < AVL_END(tree, np) */ break; } if (np) { if (checklen == AVL_INCLUDE_ZEROLEN) { if (end <= AVL_START(tree, np)) { /* something follows start, but is * is entierly after the range (end) */ return(NULL); } /* np may stradle [start, end) */ return(np); } /* * find non-zero length region */ while (np && (AVL_END(tree, np) - AVL_START(tree, np) == 0) && (AVL_START(tree, np) < end)) np = np->avl_nextino; if ((np == NULL) || (AVL_START(tree, np) >= end)) return NULL; return(np); } /* * nothing succeeds start, all existing ranges are before start. */ return NULL; } /* * Returns a pointer to node which contains exact value. */ avlnode_t * avl_find( avltree_desc_t *tree, uintptr_t value) { avlnode_t *np = tree->avl_root; uintptr_t nvalue; while (np) { nvalue = AVL_START(tree, np); if (value < nvalue) { np = np->avl_back; continue; } if (value == nvalue) { return np; } np = np->avl_forw; } return NULL; } /* * Balance buffer AVL tree after attaching a new node to root. * Called only by avl_insert. */ static void avl_balance( avlnode_t **rootp, avlnode_t *np, int growth) { /* * At this point, np points to the node to which * a new node has been attached. All that remains is to * propagate avl_balance up the tree. */ for ( ; ; ) { avlnode_t *parent = np->avl_parent; avlnode_t *child; CERT(growth == AVL_BACK || growth == AVL_FORW); /* * If the buffer was already balanced, set avl_balance * to the new direction. Continue if there is a * parent after setting growth to reflect np's * relation to its parent. */ if (np->avl_balance == AVL_BALANCE) { np->avl_balance = growth; if (parent) { if (parent->avl_forw == np) growth = AVL_FORW; else { ASSERT(parent->avl_back == np); growth = AVL_BACK; } np = parent; continue; } break; } if (growth != np->avl_balance) { /* * Subtree is now balanced -- no net effect * in the size of the subtree, so leave. */ np->avl_balance = AVL_BALANCE; break; } if (growth == AVL_BACK) { child = np->avl_back; CERT(np->avl_balance == AVL_BACK && child); if (child->avl_balance == AVL_BACK) { /* single LL */ /* * ``A'' just got inserted; * np points to ``E'', child to ``C'', * and it is already AVL_BACK -- * child will get promoted to top of subtree. np-> -E C / \ / \ child-> -C F -B E / \ / / \ -B D A D F / A Note that child->avl_parent and avl_balance get set in common code. */ np->avl_parent = child; np->avl_balance = AVL_BALANCE; np->avl_back = child->avl_forw; if (child->avl_forw) child->avl_forw->avl_parent = np; child->avl_forw = np; } else { /* * double LR * * child's avl_forw node gets promoted to * the top of the subtree. np-> -E C / \ / \ child-> +B F -B E / \ / / \ A +C A D F \ D */ avlnode_t *tmp = child->avl_forw; CERT(child->avl_balance == AVL_FORW && tmp); child->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = child; tmp->avl_back = child; child->avl_parent = tmp; np->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = np; tmp->avl_forw = np; np->avl_parent = tmp; if (tmp->avl_balance == AVL_BACK) np->avl_balance = AVL_FORW; else np->avl_balance = AVL_BALANCE; if (tmp->avl_balance == AVL_FORW) child->avl_balance = AVL_BACK; else child->avl_balance = AVL_BALANCE; /* * Set child to point to tmp since it is * now the top of the subtree, and will * get attached to the subtree parent in * the common code below. */ child = tmp; } } else /* growth == AVL_BACK */ { /* * This code is the mirror image of AVL_FORW above. */ child = np->avl_forw; CERT(np->avl_balance == AVL_FORW && child); if (child->avl_balance == AVL_FORW) { /* single RR */ np->avl_parent = child; np->avl_balance = AVL_BALANCE; np->avl_forw = child->avl_back; if (child->avl_back) child->avl_back->avl_parent = np; child->avl_back = np; } else { /* * double RL */ avlnode_t *tmp = child->avl_back; ASSERT(child->avl_balance == AVL_BACK && tmp); child->avl_back = tmp->avl_forw; if (tmp->avl_forw) tmp->avl_forw->avl_parent = child; tmp->avl_forw = child; child->avl_parent = tmp; np->avl_forw = tmp->avl_back; if (tmp->avl_back) tmp->avl_back->avl_parent = np; tmp->avl_back = np; np->avl_parent = tmp; if (tmp->avl_balance == AVL_FORW) np->avl_balance = AVL_BACK; else np->avl_balance = AVL_BALANCE; if (tmp->avl_balance == AVL_BACK) child->avl_balance = AVL_FORW; else child->avl_balance = AVL_BALANCE; child = tmp; } } child->avl_parent = parent; child->avl_balance = AVL_BALANCE; if (parent) { if (parent->avl_back == np) parent->avl_back = child; else parent->avl_forw = child; } else { ASSERT(*rootp == np); *rootp = child; } break; } } static avlnode_t * avl_insert_find_growth( avltree_desc_t *tree, uintptr_t start, /* range start at start, */ uintptr_t end, /* exclusive */ int *growthp) /* OUT */ { avlnode_t *root = tree->avl_root; avlnode_t *np; np = root; ASSERT(np); /* caller ensures that there is atleast one node in tree */ for ( ; ; ) { CERT(np->avl_parent || root == np); CERT(!np->avl_parent || root != np); CERT(!(np->avl_back) || np->avl_back->avl_parent == np); CERT(!(np->avl_forw) || np->avl_forw->avl_parent == np); CERT(np->avl_balance != AVL_FORW || np->avl_forw); CERT(np->avl_balance != AVL_BACK || np->avl_back); CERT(np->avl_balance != AVL_BALANCE || np->avl_back == NULL || np->avl_forw); CERT(np->avl_balance != AVL_BALANCE || np->avl_forw == NULL || np->avl_back); if (AVL_START(tree, np) >= end) { if (np->avl_back) { np = np->avl_back; continue; } *growthp = AVL_BACK; break; } if (AVL_END(tree, np) <= start) { if (np->avl_forw) { np = np->avl_forw; continue; } *growthp = AVL_FORW; break; } /* found exact match -- let caller decide if it is an error */ return(NULL); } return(np); } static void avl_insert_grow( avltree_desc_t *tree, avlnode_t *parent, avlnode_t *newnode, int growth) { avlnode_t *nnext; uintptr_t start = AVL_START(tree, newnode); if (growth == AVL_BACK) { parent->avl_back = newnode; /* * we are growing to the left; previous in-order to newnode is * closest ancestor with lesser value. Before this * insertion, this ancestor will be pointing to * newnode's parent. After insertion, next in-order to newnode * is the parent. */ newnode->avl_nextino = parent; nnext = parent; while (nnext) { if (AVL_END(tree, nnext) <= start) break; nnext = nnext->avl_parent; } if (nnext) { /* * nnext will be null if newnode is * the least element, and hence very first in the list. */ ASSERT(nnext->avl_nextino == parent); nnext->avl_nextino = newnode; } } else { parent->avl_forw = newnode; newnode->avl_nextino = parent->avl_nextino; parent->avl_nextino = newnode; } } avlnode_t * avl_insert( avltree_desc_t *tree, avlnode_t *newnode) { avlnode_t *np; uintptr_t start = AVL_START(tree, newnode); uintptr_t end = AVL_END(tree, newnode); int growth; ASSERT(newnode); ASSERT(start <= end); /* * Clean all pointers for sanity; some will be reset as necessary. */ newnode->avl_nextino = NULL; newnode->avl_parent = NULL; newnode->avl_forw = NULL; newnode->avl_back = NULL; newnode->avl_balance = AVL_BALANCE; if ((np = tree->avl_root) == NULL) { /* degenerate case... */ tree->avl_root = newnode; tree->avl_firstino = newnode; return newnode; } if ((np = avl_insert_find_growth(tree, start, end, &growth)) == NULL) { if (start != end) { /* non-zero length range */ fprintf(stderr, _("avl_insert: Warning! duplicate range [%llu,%llu]\n"), (unsigned long long)start, (unsigned long long)end); } return(NULL); } avl_insert_grow(tree, np, newnode, growth); if (growth == AVL_BACK) { /* * Growing to left. if np was firstino, newnode will be firstino */ if (tree->avl_firstino == np) tree->avl_firstino = newnode; } #ifdef notneeded else if (growth == AVL_FORW) /* * Cannot possibly be firstino; there is somebody to our left. */ ; #endif newnode->avl_parent = np; CERT(np->avl_forw == newnode || np->avl_back == newnode); avl_balance(&tree->avl_root, np, growth); avl_checktree(tree, tree->avl_root); return newnode; } /* * * avl_insert_immediate(tree, afterp, newnode): * insert newnode immediately into tree immediately after afterp. * after insertion, newnode is right child of afterp. */ void avl_insert_immediate( avltree_desc_t *tree, avlnode_t *afterp, avlnode_t *newnode) { /* * Clean all pointers for sanity; some will be reset as necessary. */ newnode->avl_nextino = NULL; newnode->avl_parent = NULL; newnode->avl_forw = NULL; newnode->avl_back = NULL; newnode->avl_balance = AVL_BALANCE; if (afterp == NULL) { tree->avl_root = newnode; tree->avl_firstino = newnode; return; } ASSERT(afterp->avl_forw == NULL); avl_insert_grow(tree, afterp, newnode, AVL_FORW); /* grow to right */ CERT(afterp->avl_forw == newnode); avl_balance(&tree->avl_root, afterp, AVL_FORW); avl_checktree(tree, tree->avl_root); } /* * Returns first in order node */ avlnode_t * avl_firstino(avlnode_t *root) { avlnode_t *np; if ((np = root) == NULL) return NULL; while (np->avl_back) np = np->avl_back; return np; } /* * Returns last in order node */ avlnode_t * avl_lastino(avlnode_t *root) { avlnode_t *np; if ((np = root) == NULL) return NULL; while (np->avl_forw) np = np->avl_forw; return np; } void avl_init_tree(avltree_desc_t *tree, avlops_t *ops) { tree->avl_root = NULL; tree->avl_firstino = NULL; tree->avl_ops = ops; } #ifdef AVL_DEBUG static void avl_printnode(avltree_desc_t *tree, avlnode_t *np, int nl) { printf("[%d-%d]%c", AVL_START(tree, np), (AVL_END(tree, np) - 1), nl ? '\n' : ' '); } #endif #ifdef STAND_ALONE_DEBUG struct avl_debug_node { avlnode_t avl_node; xfs_off_t avl_start; unsigned int avl_size; } avlops_t avl_debug_ops = { avl_debug_start, avl_debug_end, } static uintptr_t avl_debug_start(avlnode_t *node) { return (uintptr_t)(struct avl_debug_node *)node->avl_start; } static uintptr_t avl_debug_end(avlnode_t *node) { return (uintptr_t) ((struct avl_debug_node *)node->avl_start + (struct avl_debug_node *)node->avl_size); } avl_debug_node freenodes[100]; avl_debug_node *freehead = &freenodes[0]; static avlnode_t * alloc_avl_debug_node() { freehead->avl_balance = AVL_BALANCE; freehead->avl_parent = freehead->avl_forw = freehead->avl_back = NULL; return(freehead++); } static void avl_print(avltree_desc_t *tree, avlnode_t *root, int depth) { int i; if (!root) return; if (root->avl_forw) avl_print(tree, root->avl_forw, depth+5); for (i = 0; i < depth; i++) putchar((int) ' '); avl_printnode(tree, root,1); if (root->avl_back) avl_print(tree, root->avl_back, depth+5); } main() { int i, j; avlnode_t *np; avltree_desc_t tree; char linebuf[256], cmd[256]; avl_init_tree(&tree, &avl_debug_ops); for (i = 100; i > 0; i = i - 10) { np = alloc__debug_avlnode(); ASSERT(np); np->avl_start = i; np->avl_size = 10; avl_insert(&tree, np); } avl_print(&tree, tree.avl_root, 0); for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino) avl_printnode(&tree, np, 0); printf("\n"); while (1) { printf(_("Command [fpdir] : ")); fgets(linebuf, 256, stdin); if (feof(stdin)) break; cmd[0] = NULL; if (sscanf(linebuf, "%[fpdir]%d", cmd, &i) != 2) continue; switch (cmd[0]) { case 'd': case 'f': printf(_("end of range ? ")); fgets(linebuf, 256, stdin); j = atoi(linebuf); if (i == j) j = i+1; np = avl_findinrange(&tree,i,j); if (np) { avl_printnode(&tree, np, 1); if (cmd[0] == 'd') avl_delete(&tree, np); } else printf(_("Cannot find %d\n"), i); break; case 'p': avl_print(&tree, tree.avl_root, 0); for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino) avl_printnode(&tree, np, 0); printf("\n"); break; case 'i': np = alloc_avlnode(); ASSERT(np); np->avl_start = i; printf(_("size of range ? ")); fgets(linebuf, 256, stdin); j = atoi(linebuf); np->avl_size = j; avl_insert(&tree, np); break; case 'r': { avlnode_t *b, *e, *t; int checklen; printf(_("End of range ? ")); fgets(linebuf, 256, stdin); j = atoi(linebuf); printf(_("checklen 0/1 ? ")); fgets(linebuf, 256, stdin); checklen = atoi(linebuf); b = avl_findanyrange(&tree, i, j, checklen); if (b) { printf(_("Found something\n")); t = b; while (t) { if (t != b && AVL_START(&tree, t) >= j) break; avl_printnode(&tree, t, 0); t = t->avl_nextino; } printf("\n"); } } } } } #endif /* * Given a tree, find value; will find return range enclosing value, * or range immediately succeeding value, * or range immediately preceeding value. */ avlnode_t * avl_findadjacent( avltree_desc_t *tree, uintptr_t value, int dir) { avlnode_t *np = tree->avl_root; while (np) { if (value < AVL_START(tree, np)) { if (np->avl_back) { np = np->avl_back; continue; } /* if we were to add node with value, would * have a growth of AVL_BACK */ if (dir == AVL_SUCCEED) { /* if succeeding node is needed, this is it. */ return(np); } if (dir == AVL_PRECEED) { /* * find nearest ancestor with lesser value. */ np = np->avl_parent; while (np) { if (AVL_END(tree, np) <= value) break; np = np->avl_parent; } return(np); } ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); break; } if (value >= AVL_END(tree, np)) { if (np->avl_forw) { np = np->avl_forw; continue; } /* if we were to add node with value, would * have a growth of AVL_FORW; */ if (dir == AVL_SUCCEED) { /* we are looking for a succeeding node; * this is nextino. */ return(np->avl_nextino); } if (dir == AVL_PRECEED) { /* looking for a preceeding node; this is it. */ return(np); } ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); } /* AVL_START(tree, np) <= value < AVL_END(tree, np) */ return(np); } return NULL; } /* * avl_findranges: * * Given range r [start, end), find all ranges in tree which are contained * in r. At return, startp and endp point to first and last of * a chain of elements which describe the contained ranges. Elements * in startp ... endp are in sort order, and can be accessed by * using avl_nextino. */ void avl_findranges( avltree_desc_t *tree, uintptr_t start, uintptr_t end, avlnode_t **startp, avlnode_t **endp) { avlnode_t *np; np = avl_findadjacent(tree, start, AVL_SUCCEED); if (np == NULL /* nothing succeding start */ || (np && (end <= AVL_START(tree, np)))) /* something follows start, but... is entirely after end */ { *startp = NULL; *endp = NULL; return; } *startp = np; /* see if end is in this region itself */ if (end <= AVL_END(tree, np) || np->avl_nextino == NULL || (np->avl_nextino && (end <= AVL_START(tree, np->avl_nextino)))) { *endp = np; return; } /* have to munge for end */ /* * note: have to look for (end - 1), since * findadjacent will look for exact value, and does not * care about the fact that end is actually one more * than the value actually being looked for; thus feed it one less. */ *endp = avl_findadjacent(tree, (end-1), AVL_PRECEED); ASSERT(*endp); } xfsprogs-5.3.0/repair/avl.h0000644000175000017500000000500313435336037015466 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef __SYS_AVL_H__ #define __SYS_AVL_H__ typedef struct avlnode { struct avlnode *avl_forw; /* pointer to right child (> parent) */ struct avlnode *avl_back; /* pointer to left child (< parent) */ struct avlnode *avl_parent; /* parent pointer */ struct avlnode *avl_nextino; /* next in-order; NULL terminated list*/ char avl_balance; /* tree balance */ } avlnode_t; /* * avl-tree operations */ typedef struct avlops { uintptr_t (*avl_start)(avlnode_t *); uintptr_t (*avl_end)(avlnode_t *); } avlops_t; #define AVL_START(tree, n) (*(tree)->avl_ops->avl_start)(n) #define AVL_END(tree, n) (*(tree)->avl_ops->avl_end)(n) /* * tree descriptor: * root points to the root of the tree. * firstino points to the first in the ordered list. */ typedef struct avltree_desc { avlnode_t *avl_root; avlnode_t *avl_firstino; avlops_t *avl_ops; short avl_flags; } avltree_desc_t; /* possible values for avl_balance */ #define AVL_BACK 1 #define AVL_BALANCE 0 #define AVL_FORW 2 /* possible values for avl_flags */ #define AVLF_DUPLICITY 0x0001 /* no warnings on insert dups */ /* * 'Exported' avl tree routines */ avlnode_t *avl_insert( avltree_desc_t *tree, avlnode_t *newnode); void avl_delete( avltree_desc_t *tree, avlnode_t *np); void avl_insert_immediate( avltree_desc_t *tree, avlnode_t *afterp, avlnode_t *newnode); void avl_init_tree( avltree_desc_t *tree, avlops_t *ops); static inline avlnode_t * avl_findrange( avltree_desc_t *tree, uintptr_t value) { avlnode_t *np = tree->avl_root; while (np) { if (value < AVL_START(tree, np)) { np = np->avl_back; continue; } if (value >= AVL_END(tree, np)) { np = np->avl_forw; continue; } ASSERT(AVL_START(tree, np) <= value && value < AVL_END(tree, np)); return np; } return NULL; } avlnode_t * avl_find( avltree_desc_t *tree, uintptr_t value); avlnode_t * avl_findanyrange( avltree_desc_t *tree, uintptr_t start, uintptr_t end, int checklen); avlnode_t * avl_findadjacent( avltree_desc_t *tree, uintptr_t value, int dir); void avl_findranges( avltree_desc_t *tree, uintptr_t start, uintptr_t end, avlnode_t **startp, avlnode_t **endp); avlnode_t * avl_firstino( avlnode_t *root); avlnode_t * avl_lastino( avlnode_t *root); #define AVL_PRECEED 0x1 #define AVL_SUCCEED 0x2 #define AVL_INCLUDE_ZEROLEN 0x0000 #define AVL_EXCLUDE_ZEROLEN 0x0001 #endif /* __SYS_AVL_H__ */ xfsprogs-5.3.0/repair/bmap.c0000644000175000017500000002064413435336037015626 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005,2008 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "err_protos.h" #include "bmap.h" /* * Track the logical to physical block mapping for inodes. * * Repair only processes one inode at a given time per thread, and the * block map does not have to outlive the processing of a single inode. * * The combination of those factors means we can use pthreads thread-local * storage to store the block map, and we can re-use the allocation over * and over again. */ pthread_key_t dblkmap_key; pthread_key_t ablkmap_key; blkmap_t * blkmap_alloc( xfs_extnum_t nex, int whichfork) { pthread_key_t key; blkmap_t *blkmap; ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK); if (nex < 1) nex = 1; #if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */ if (nex > BLKMAP_NEXTS_MAX) { do_warn( _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n" "If this is not a corruption, then you will need a 64 bit system\n" "to repair this filesystem.\n"), nex); return NULL; } #endif key = whichfork ? ablkmap_key : dblkmap_key; blkmap = pthread_getspecific(key); if (!blkmap || blkmap->naexts < nex) { blkmap = realloc(blkmap, BLKMAP_SIZE(nex)); if (!blkmap) { do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"), BLKMAP_SIZE(nex)); return NULL; } pthread_setspecific(key, blkmap); blkmap->naexts = nex; } blkmap->nexts = 0; return blkmap; } /* * Free a block map. * * If the map is a large, uncommon size (say for hundreds of thousands of * extents) then free it to release the memory. This prevents us from pinning * large tracts of memory due to corrupted fork values or one-off fragmented * files. Otherwise we have nothing to do but keep the memory around for the * next inode. * When the thread is done, it should do an unconditional, final free. */ void blkmap_free( blkmap_t *blkmap) { if (!blkmap) return; /* consider more than 100k extents rare */ if (blkmap->naexts < 100 * 1024) return; if (blkmap == pthread_getspecific(dblkmap_key)) pthread_setspecific(dblkmap_key, NULL); else pthread_setspecific(ablkmap_key, NULL); free(blkmap); } void blkmap_free_final(void) { blkmap_t *blkmap; blkmap = pthread_getspecific(dblkmap_key); pthread_setspecific(dblkmap_key, NULL); free(blkmap); blkmap = pthread_getspecific(ablkmap_key); pthread_setspecific(ablkmap_key, NULL); free(blkmap); } /* * Get one entry from a block map. */ xfs_fsblock_t blkmap_get( blkmap_t *blkmap, xfs_fileoff_t o) { bmap_ext_t *ext = blkmap->exts; int i; for (i = 0; i < blkmap->nexts; i++, ext++) { if (o >= ext->startoff && o < ext->startoff + ext->blockcount) return ext->startblock + (o - ext->startoff); } return NULLFSBLOCK; } /* * Get a chunk of entries from a block map - only used for reading dirv2 blocks */ int blkmap_getn( blkmap_t *blkmap, xfs_fileoff_t o, xfs_filblks_t nb, bmap_ext_t **bmpp, bmap_ext_t *bmpp_single) { bmap_ext_t *bmp = NULL; bmap_ext_t *ext; int i; int nex; if (nb == 1) { /* * in the common case, when mp->m_dirblkfsbs == 1, * avoid additional malloc/free overhead */ bmpp_single->startblock = blkmap_get(blkmap, o); goto single_ext; } ext = blkmap->exts; nex = 0; for (i = 0; i < blkmap->nexts; i++, ext++) { if (ext->startoff >= o + nb) break; if (ext->startoff + ext->blockcount <= o) continue; /* * if all the requested blocks are in one extent (also common), * use the bmpp_single option as well */ if (!bmp && o >= ext->startoff && o + nb <= ext->startoff + ext->blockcount) { bmpp_single->startblock = ext->startblock + (o - ext->startoff); goto single_ext; } /* * rare case - multiple extents for a single dir block */ if (!bmp) bmp = malloc(nb * sizeof(bmap_ext_t)); if (!bmp) do_error(_("blkmap_getn malloc failed (%" PRIu64 " bytes)\n"), nb * sizeof(bmap_ext_t)); bmp[nex].startblock = ext->startblock + (o - ext->startoff); bmp[nex].blockcount = min(nb, ext->blockcount - (bmp[nex].startblock - ext->startblock)); o += bmp[nex].blockcount; nb -= bmp[nex].blockcount; nex++; } *bmpp = bmp; return nex; single_ext: bmpp_single->blockcount = nb; bmpp_single->startoff = 0; /* not even used by caller! */ *bmpp = bmpp_single; return (bmpp_single->startblock != NULLFSBLOCK) ? 1 : 0; } /* * Return the last offset in a block map. */ xfs_fileoff_t blkmap_last_off( blkmap_t *blkmap) { bmap_ext_t *ext; if (!blkmap->nexts) return NULLFILEOFF; ext = blkmap->exts + blkmap->nexts - 1; return ext->startoff + ext->blockcount; } /** * blkmap_next_off - Return next logical block offset in a block map. * @blkmap: blockmap to use * @o: current file logical block number * @t: current extent index into blockmap (in/out) * * Given a logical block offset in a file, return the next mapped logical offset * The map index "t" tracks the current extent number in the block map, and * is updated automatically if the returned offset resides within the next * mapped extent. * * If the blockmap contains no extents, or no more logical offsets are mapped, * or the extent index exceeds the number of extents in the map, * return NULLFILEOFF. * * If offset o is beyond extent index t, the first offset in the next extent * after extent t will be returned. * * Intended to be called starting with offset 0, index 0, and iterated. */ xfs_fileoff_t blkmap_next_off( blkmap_t *blkmap, xfs_fileoff_t o, int *t) { bmap_ext_t *ext; if (!blkmap->nexts) return NULLFILEOFF; if (o == NULLFILEOFF) { *t = 0; return blkmap->exts[0].startoff; } if (*t >= blkmap->nexts) return NULLFILEOFF; ext = blkmap->exts + *t; if (o < ext->startoff + ext->blockcount - 1) return o + 1; if (*t == blkmap->nexts - 1) return NULLFILEOFF; (*t)++; return ext[1].startoff; } /* * Make a block map larger. */ static blkmap_t * blkmap_grow( blkmap_t *blkmap) { pthread_key_t key = dblkmap_key; blkmap_t *new_blkmap; int new_naexts; /* reduce the number of reallocations for large files */ if (blkmap->naexts < 1000) new_naexts = blkmap->naexts + 4; else if (blkmap->naexts < 10000) new_naexts = blkmap->naexts + 100; else new_naexts = blkmap->naexts + 1000; if (pthread_getspecific(key) != blkmap) { key = ablkmap_key; ASSERT(pthread_getspecific(key) == blkmap); } #if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */ if (new_naexts > BLKMAP_NEXTS_MAX) { do_error( _("Number of extents requested in blkmap_grow (%d) overflows 32 bits.\n" "You need a 64 bit system to repair this filesystem.\n"), new_naexts); return NULL; } #endif if (new_naexts <= 0) { do_error( _("Number of extents requested in blkmap_grow (%d) overflowed the\n" "maximum number of supported extents (%d).\n"), new_naexts, BLKMAP_NEXTS_MAX); return NULL; } new_blkmap = realloc(blkmap, BLKMAP_SIZE(new_naexts)); if (!new_blkmap) { do_error(_("realloc failed in blkmap_grow\n")); return NULL; } new_blkmap->naexts = new_naexts; pthread_setspecific(key, new_blkmap); return new_blkmap; } /* * Set an extent into a block map. * * If this function fails, it leaves the blkmapp untouched so the caller can * handle the error and free the blkmap appropriately. */ int blkmap_set_ext( blkmap_t **blkmapp, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c) { blkmap_t *blkmap = *blkmapp; xfs_extnum_t i; if (blkmap->nexts == blkmap->naexts) { blkmap = blkmap_grow(blkmap); if (!blkmap) return ENOMEM; *blkmapp = blkmap; } ASSERT(blkmap->nexts < blkmap->naexts); if (blkmap->nexts == 0) { i = 0; goto insert; } /* * The most common insert pattern comes from an ascending offset order * bmapbt scan. In this case, the extent being added will end up at the * end of the array. Hence do a reverse order search for the insertion * point so we don't needlessly scan the entire array on every * insertion. * * Also, use "plus 1" indexing for the loop counter so when we break out * of the loop we are at the correct index for insertion. */ for (i = blkmap->nexts; i > 0; i--) { if (blkmap->exts[i - 1].startoff < o) break; } /* make space for the new extent */ memmove(blkmap->exts + i + 1, blkmap->exts + i, sizeof(bmap_ext_t) * (blkmap->nexts - i)); insert: blkmap->exts[i].startoff = o; blkmap->exts[i].startblock = b; blkmap->exts[i].blockcount = c; blkmap->nexts++; return 0; } xfsprogs-5.3.0/repair/bmap.h0000644000175000017500000000314413435336037015627 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XFS_REPAIR_BMAP_H #define _XFS_REPAIR_BMAP_H /* * Extent descriptor. */ typedef struct bmap_ext { xfs_fileoff_t startoff; xfs_fsblock_t startblock; xfs_filblks_t blockcount; } bmap_ext_t; /* * Block map. */ typedef struct blkmap { int naexts; int nexts; bmap_ext_t exts[1]; } blkmap_t; #define BLKMAP_SIZE(n) \ (offsetof(blkmap_t, exts) + (sizeof(bmap_ext_t) * (n))) /* * For 32 bit platforms, we are limited to extent arrays of 2^31 bytes, which * limits the number of extents in an inode we can check. If we don't limit the * valid range, we can overflow the BLKMAP_SIZE() calculation and allocate less * memory than we think we needed, and hence walk off the end of the array and * corrupt memory. */ #if BITS_PER_LONG == 32 #define BLKMAP_NEXTS_MAX ((INT_MAX / sizeof(bmap_ext_t)) - 1) #else #define BLKMAP_NEXTS_MAX INT_MAX #endif extern pthread_key_t dblkmap_key; extern pthread_key_t ablkmap_key; blkmap_t *blkmap_alloc(xfs_extnum_t nex, int whichfork); void blkmap_free(blkmap_t *blkmap); void blkmap_free_final(void); int blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c); xfs_fsblock_t blkmap_get(blkmap_t *blkmap, xfs_fileoff_t o); int blkmap_getn(blkmap_t *blkmap, xfs_fileoff_t o, xfs_filblks_t nb, bmap_ext_t **bmpp, bmap_ext_t *bmpp_single); xfs_fileoff_t blkmap_last_off(blkmap_t *blkmap); xfs_fileoff_t blkmap_next_off(blkmap_t *blkmap, xfs_fileoff_t o, int *t); #endif /* _XFS_REPAIR_BMAP_H */ xfsprogs-5.3.0/repair/btree.c0000644000175000017500000006205713435336037016014 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2007, Silicon Graphics, Inc. Barry Naujok * All Rights Reserved. */ #include "libxfs.h" #include "btree.h" /* * Maximum number of keys per node. Must be greater than 2 for the code * to work. */ #define BTREE_KEY_MAX 7 #define BTREE_KEY_MIN (BTREE_KEY_MAX / 2) #define BTREE_PTR_MAX (BTREE_KEY_MAX + 1) struct btree_node { unsigned long num_keys; unsigned long keys[BTREE_KEY_MAX]; struct btree_node *ptrs[BTREE_PTR_MAX]; }; struct btree_cursor { struct btree_node *node; int index; }; struct btree_root { struct btree_node *root_node; struct btree_cursor *cursor; /* track path to end leaf */ int height; /* lookup cache */ int keys_valid; /* set if the cache is valid */ unsigned long cur_key; unsigned long next_key; void *next_value; unsigned long prev_key; void *prev_value; #ifdef BTREE_STATS struct btree_stats { unsigned long num_items; unsigned long max_items; int alloced; int cache_hits; int cache_misses; int lookup; int find; int key_update; int value_update; int insert; int delete; int inc_height; int dec_height; int shift_prev; int shift_next; int split; int merge_prev; int merge_next; int balance_prev; int balance_next; } stats; #endif }; static struct btree_node * btree_node_alloc(void) { return calloc(1, sizeof(struct btree_node)); } static void btree_node_free( struct btree_node *node) { free(node); } static void btree_free_nodes( struct btree_node *node, int level) { int i; if (level) for (i = 0; i <= node->num_keys; i++) btree_free_nodes(node->ptrs[i], level - 1); btree_node_free(node); } static void __btree_init( struct btree_root *root) { memset(root, 0, sizeof(struct btree_root)); root->height = 1; root->cursor = calloc(1, sizeof(struct btree_cursor)); root->root_node = btree_node_alloc(); ASSERT(root->root_node); #ifdef BTREE_STATS root->stats.max_items = 1; root->stats.alloced += 1; #endif } static void __btree_free( struct btree_root *root) { btree_free_nodes(root->root_node, root->height - 1); free(root->cursor); root->height = 0; root->cursor = NULL; root->root_node = NULL; } void btree_init( struct btree_root **root) { *root = calloc(1, sizeof(struct btree_root)); __btree_init(*root); } void btree_clear( struct btree_root *root) { __btree_free(root); __btree_init(root); } void btree_destroy( struct btree_root *root) { __btree_free(root); free(root); } int btree_is_empty( struct btree_root *root) { return root->root_node->num_keys == 0; } static inline void btree_invalidate_cursor( struct btree_root *root) { root->cursor[0].node = NULL; root->keys_valid = 0; } static inline unsigned long btree_key_of_cursor( struct btree_cursor *cursor, int height) { while (cursor->node->num_keys == cursor->index && --height > 0) cursor++; return cursor->node->keys[cursor->index]; } static void * btree_get_prev( struct btree_root *root, unsigned long *key) { struct btree_cursor *cur = root->cursor; int level = 0; struct btree_node *node; if (cur->index > 0) { if (key) *key = cur->node->keys[cur->index - 1]; return cur->node->ptrs[cur->index - 1]; } /* else need to go up and back down the tree to find the previous */ do { if (cur->index) break; cur++; } while (++level < root->height); if (level == root->height) return NULL; /* the key is in the current level */ if (key) *key = cur->node->keys[cur->index - 1]; /* descend back down the right side to get the pointer */ node = cur->node->ptrs[cur->index - 1]; while (level--) node = node->ptrs[node->num_keys]; return node; } static void * btree_get_next( struct btree_root *root, unsigned long *key) { struct btree_cursor *cur = root->cursor; int level = 0; struct btree_node *node; while (cur->index == cur->node->num_keys) { if (++level == root->height) return NULL; cur++; } if (level == 0) { if (key) { cur->index++; *key = btree_key_of_cursor(cur, root->height); cur->index--; } return cur->node->ptrs[cur->index + 1]; } node = cur->node->ptrs[cur->index + 1]; while (--level > 0) node = node->ptrs[0]; if (key) *key = node->keys[0]; return node->ptrs[0]; } /* * Lookup/Search functions */ static int btree_do_search( struct btree_root *root, unsigned long key) { unsigned long k = 0; struct btree_cursor *cur = root->cursor + root->height; struct btree_node *node = root->root_node; int height = root->height; int key_found = 0; int i; while (--height >= 0) { cur--; for (i = 0; i < node->num_keys; i++) if (node->keys[i] >= key) { k = node->keys[i]; key_found = 1; break; } cur->node = node; cur->index = i; node = node->ptrs[i]; } root->keys_valid = key_found; if (!key_found) return 0; root->cur_key = k; root->next_value = NULL; /* do on-demand next value lookup */ root->prev_value = btree_get_prev(root, &root->prev_key); return 1; } static int btree_search( struct btree_root *root, unsigned long key) { if (root->keys_valid && key <= root->cur_key && (!root->prev_value || key > root->prev_key)) { #ifdef BTREE_STATS root->stats.cache_hits++; #endif return 1; } #ifdef BTREE_STATS root->stats.cache_misses++; #endif return btree_do_search(root, key); } void * btree_find( struct btree_root *root, unsigned long key, unsigned long *actual_key) { #ifdef BTREE_STATS root->stats.find += 1; #endif if (!btree_search(root, key)) return NULL; if (actual_key) *actual_key = root->cur_key; return root->cursor->node->ptrs[root->cursor->index]; } void * btree_lookup( struct btree_root *root, unsigned long key) { #ifdef BTREE_STATS root->stats.lookup += 1; #endif if (!btree_search(root, key) || root->cur_key != key) return NULL; return root->cursor->node->ptrs[root->cursor->index]; } void * btree_peek_prev( struct btree_root *root, unsigned long *key) { if (!root->keys_valid) return NULL; if (key) *key = root->prev_key; return root->prev_value; } void * btree_peek_next( struct btree_root *root, unsigned long *key) { if (!root->keys_valid) return NULL; if (!root->next_value) root->next_value = btree_get_next(root, &root->next_key); if (key) *key = root->next_key; return root->next_value; } static void * btree_move_cursor_to_next( struct btree_root *root, unsigned long *key) { struct btree_cursor *cur = root->cursor; int level = 0; while (cur->index == cur->node->num_keys) { if (++level == root->height) return NULL; cur++; } cur->index++; if (level == 0) { if (key) *key = btree_key_of_cursor(cur, root->height); return cur->node->ptrs[cur->index]; } while (--level >= 0) { root->cursor[level].node = cur->node->ptrs[cur->index]; root->cursor[level].index = 0; cur--; } if (key) *key = cur->node->keys[0]; return cur->node->ptrs[0]; } void * btree_lookup_next( struct btree_root *root, unsigned long *key) { void *value; if (!root->keys_valid) return NULL; root->prev_key = root->cur_key; root->prev_value = root->cursor->node->ptrs[root->cursor->index]; value = btree_move_cursor_to_next(root, &root->cur_key); if (!value) { btree_invalidate_cursor(root); return NULL; } root->next_value = NULL; /* on-demand next value fetch */ if (key) *key = root->cur_key; return value; } static void * btree_move_cursor_to_prev( struct btree_root *root, unsigned long *key) { struct btree_cursor *cur = root->cursor; int level = 0; while (cur->index == 0) { if (++level == root->height) return NULL; cur++; } cur->index--; if (key) /* the key is in the current level */ *key = cur->node->keys[cur->index]; while (level > 0) { level--; root->cursor[level].node = cur->node->ptrs[cur->index]; root->cursor[level].index = root->cursor[level].node->num_keys; cur--; } return cur->node->ptrs[cur->index]; } void * btree_lookup_prev( struct btree_root *root, unsigned long *key) { void *value; if (!root->keys_valid) return NULL; value = btree_move_cursor_to_prev(root, &root->cur_key); if (!value) return NULL; root->prev_value = btree_get_prev(root, &root->prev_key); root->next_value = NULL; /* on-demand next value fetch */ if (key) *key = root->cur_key; return value; } /* Update functions */ static inline void btree_update_node_key( struct btree_root *root, struct btree_cursor *cursor, int level, unsigned long new_key) { int i; #ifdef BTREE_STATS root->stats.key_update += 1; #endif cursor += level; for (i = level; i < root->height; i++) { if (cursor->index < cursor->node->num_keys) { cursor->node->keys[cursor->index] = new_key; break; } cursor++; } } int btree_update_key( struct btree_root *root, unsigned long old_key, unsigned long new_key) { if (!btree_search(root, old_key) || root->cur_key != old_key) return ENOENT; if (root->next_value && new_key >= root->next_key) return EINVAL; if (root->prev_value && new_key <= root->prev_key) return EINVAL; btree_update_node_key(root, root->cursor, 0, new_key); root->cur_key = new_key; return 0; } int btree_update_value( struct btree_root *root, unsigned long key, void *new_value) { if (!new_value) return EINVAL; if (!btree_search(root, key) || root->cur_key != key) return ENOENT; #ifdef BTREE_STATS root->stats.value_update += 1; #endif root->cursor->node->ptrs[root->cursor->index] = new_value; return 0; } /* * Cursor modification functions - used for inserting and deleting */ static struct btree_cursor * btree_copy_cursor_prev( struct btree_root *root, struct btree_cursor *dest_cursor, int level) { struct btree_cursor *src_cur = root->cursor + level; struct btree_cursor *dst_cur; int l = level; int i; if (level >= root->height) return NULL; while (src_cur->index == 0) { if (++l >= root->height) return NULL; src_cur++; } for (i = l; i < root->height; i++) dest_cursor[i] = *src_cur++; dst_cur = dest_cursor + l; dst_cur->index--; while (l-- >= level) { dest_cursor[l].node = dst_cur->node->ptrs[dst_cur->index]; dest_cursor[l].index = dest_cursor[l].node->num_keys; dst_cur--; } return dest_cursor; } static struct btree_cursor * btree_copy_cursor_next( struct btree_root *root, struct btree_cursor *dest_cursor, int level) { struct btree_cursor *src_cur = root->cursor + level; struct btree_cursor *dst_cur; int l = level; int i; if (level >= root->height) return NULL; while (src_cur->index == src_cur->node->num_keys) { if (++l >= root->height) return NULL; src_cur++; } for (i = l; i < root->height; i++) dest_cursor[i] = *src_cur++; dst_cur = dest_cursor + l; dst_cur->index++; while (l-- >= level) { dest_cursor[l].node = dst_cur->node->ptrs[dst_cur->index]; dest_cursor[l].index = 0; dst_cur--; } return dest_cursor; } /* * Shift functions * * Tries to move items in the current leaf to its sibling if it has space. * Used in both insert and delete functions. * Returns the number of items shifted. */ static int btree_shift_to_prev( struct btree_root *root, int level, struct btree_cursor *prev_cursor, int num_children) { struct btree_node *node; struct btree_node *prev_node; int num_remain; /* # of keys left in "node" */ unsigned long key; int i; if (!prev_cursor || !num_children) return 0; prev_node = prev_cursor[level].node; node = root->cursor[level].node; ASSERT(num_children > 0 && num_children <= node->num_keys + 1); if ((prev_node->num_keys + num_children) > BTREE_KEY_MAX) return 0; #ifdef BTREE_STATS root->stats.shift_prev += 1; #endif num_remain = node->num_keys - num_children; ASSERT(num_remain == -1 || num_remain >= BTREE_KEY_MIN); /* shift parent keys around */ level++; if (num_remain > 0) key = node->keys[num_children - 1]; else key = btree_key_of_cursor(root->cursor + level, root->height - level); while (prev_cursor[level].index == prev_cursor[level].node->num_keys) { level++; ASSERT(level < root->height); } prev_node->keys[prev_node->num_keys] = prev_cursor[level].node->keys[prev_cursor[level].index]; prev_cursor[level].node->keys[prev_cursor[level].index] = key; /* copy pointers and keys to the end of the prev node */ for (i = 0; i < num_children - 1; i++) { prev_node->keys[prev_node->num_keys + 1 + i] = node->keys[i]; prev_node->ptrs[prev_node->num_keys + 1 + i] = node->ptrs[i]; } prev_node->ptrs[prev_node->num_keys + 1 + i] = node->ptrs[i]; prev_node->num_keys += num_children; /* move remaining pointers/keys to start of node */ if (num_remain >= 0) { for (i = 0; i < num_remain; i++) { node->keys[i] = node->keys[num_children + i]; node->ptrs[i] = node->ptrs[num_children + i]; } node->ptrs[i] = node->ptrs[num_children + i]; node->num_keys = num_remain; } else node->num_keys = 0; return num_children; } static int btree_shift_to_next( struct btree_root *root, int level, struct btree_cursor *next_cursor, int num_children) { struct btree_node *node; struct btree_node *next_node; int num_remain; /* # of children left in node */ int i; if (!next_cursor || !num_children) return 0; node = root->cursor[level].node; next_node = next_cursor[level].node; ASSERT(num_children > 0 && num_children <= node->num_keys + 1); if ((next_node->num_keys + num_children) > BTREE_KEY_MAX) return 0; num_remain = node->num_keys + 1 - num_children; ASSERT(num_remain == 0 || num_remain > BTREE_KEY_MIN); #ifdef BTREE_STATS root->stats.shift_next += 1; #endif /* make space for "num_children" items at beginning of next-leaf */ i = next_node->num_keys; next_node->ptrs[num_children + i] = next_node->ptrs[i]; while (--i >= 0) { next_node->keys[num_children + i] = next_node->keys[i]; next_node->ptrs[num_children + i] = next_node->ptrs[i]; } /* update keys in parent and next node from parent */ do { level++; ASSERT(level < root->height); } while (root->cursor[level].index == root->cursor[level].node->num_keys); next_node->keys[num_children - 1] = root->cursor[level].node->keys[root->cursor[level].index]; root->cursor[level].node->keys[root->cursor[level].index] = node->keys[node->num_keys - num_children]; /* copy last "num_children" items from node into start of next-node */ for (i = 0; i < num_children - 1; i++) { next_node->keys[i] = node->keys[num_remain + i]; next_node->ptrs[i] = node->ptrs[num_remain + i]; } next_node->ptrs[i] = node->ptrs[num_remain + i]; next_node->num_keys += num_children; if (num_remain > 0) node->num_keys -= num_children; else node->num_keys = 0; return num_children; } /* * Insertion functions */ static struct btree_node * btree_increase_height( struct btree_root *root) { struct btree_node *new_root; struct btree_cursor *new_cursor; new_cursor = realloc(root->cursor, (root->height + 1) * sizeof(struct btree_cursor)); if (!new_cursor) return NULL; root->cursor = new_cursor; new_root = btree_node_alloc(); if (!new_root) return NULL; #ifdef BTREE_STATS root->stats.alloced += 1; root->stats.inc_height += 1; root->stats.max_items *= BTREE_PTR_MAX; #endif new_root->ptrs[0] = root->root_node; root->root_node = new_root; root->cursor[root->height].node = new_root; root->cursor[root->height].index = 0; root->height++; return new_root; } static int btree_insert_item( struct btree_root *root, int level, unsigned long key, void *value); static struct btree_node * btree_split( struct btree_root *root, int level, unsigned long key, int *index) { struct btree_node *node = root->cursor[level].node; struct btree_node *new_node; int i; new_node = btree_node_alloc(); if (!new_node) return NULL; if (btree_insert_item(root, level + 1, node->keys[BTREE_KEY_MIN], new_node) != 0) { btree_node_free(new_node); return NULL; } #ifdef BTREE_STATS root->stats.alloced += 1; root->stats.split += 1; #endif for (i = 0; i < BTREE_KEY_MAX - BTREE_KEY_MIN - 1; i++) { new_node->keys[i] = node->keys[BTREE_KEY_MIN + 1 + i]; new_node->ptrs[i] = node->ptrs[BTREE_KEY_MIN + 1 + i]; } new_node->ptrs[i] = node->ptrs[BTREE_KEY_MIN + 1 + i]; new_node->num_keys = BTREE_KEY_MAX - BTREE_KEY_MIN - 1; node->num_keys = BTREE_KEY_MIN; if (key < node->keys[BTREE_KEY_MIN]) return node; /* index doesn't change */ /* insertion point is in new node... */ *index -= BTREE_KEY_MIN + 1; return new_node; } static int btree_insert_shift_to_prev( struct btree_root *root, int level, int *index) { struct btree_cursor tmp_cursor[root->height]; int n; if (*index <= 0) return -1; if (!btree_copy_cursor_prev(root, tmp_cursor, level + 1)) return -1; n = min(*index, (BTREE_PTR_MAX - tmp_cursor[level].node->num_keys) / 2); if (!n || !btree_shift_to_prev(root, level, tmp_cursor, n)) return -1; *index -= n; return 0; } static int btree_insert_shift_to_next( struct btree_root *root, int level, int *index) { struct btree_cursor tmp_cursor[root->height]; int n; if (*index >= BTREE_KEY_MAX) return -1; if (!btree_copy_cursor_next(root, tmp_cursor, level + 1)) return -1; n = min(BTREE_KEY_MAX - *index, (BTREE_PTR_MAX - tmp_cursor[level].node->num_keys) / 2); if (!n || !btree_shift_to_next(root, level, tmp_cursor, n)) return -1; return 0; } static int btree_insert_item( struct btree_root *root, int level, unsigned long key, void *value) { struct btree_node *node = root->cursor[level].node; int index = root->cursor[level].index; int i; if (node->num_keys == BTREE_KEY_MAX) { if (btree_insert_shift_to_prev(root, level, &index) == 0) goto insert; if (btree_insert_shift_to_next(root, level, &index) == 0) goto insert; if (level == root->height - 1) { if (!btree_increase_height(root)) return ENOMEM; } node = btree_split(root, level, key, &index); if (!node) return ENOMEM; } insert: ASSERT(index <= node->num_keys); i = node->num_keys; node->ptrs[i + 1] = node->ptrs[i]; while (--i >= index) { node->keys[i + 1] = node->keys[i]; node->ptrs[i + 1] = node->ptrs[i]; } node->num_keys++; node->keys[index] = key; if (level == 0) node->ptrs[index] = value; else node->ptrs[index + 1] = value; return 0; } int btree_insert( struct btree_root *root, unsigned long key, void *value) { int result; if (!value) return EINVAL; if (btree_search(root, key) && root->cur_key == key) return EEXIST; #ifdef BTREE_STATS root->stats.insert += 1; root->stats.num_items += 1; #endif result = btree_insert_item(root, 0, key, value); btree_invalidate_cursor(root); return result; } /* * Deletion functions * * Rather more complicated as deletions has 4 ways to go once a node * ends up with less than the minimum number of keys: * - move remainder to previous node * - move remainder to next node * (both will involve a parent deletion which may recurse) * - balance by moving some items from previous node * - balance by moving some items from next node */ static void btree_decrease_height( struct btree_root *root) { struct btree_node *old_root = root->root_node; ASSERT(old_root->num_keys == 0); #ifdef BTREE_STATS root->stats.alloced -= 1; root->stats.dec_height += 1; root->stats.max_items /= BTREE_PTR_MAX; #endif root->root_node = old_root->ptrs[0]; btree_node_free(old_root); root->height--; } static int btree_merge_with_prev( struct btree_root *root, int level, struct btree_cursor *prev_cursor) { if (!prev_cursor) return 0; if (!btree_shift_to_prev(root, level, prev_cursor, root->cursor[level].node->num_keys + 1)) return 0; #ifdef BTREE_STATS root->stats.merge_prev += 1; #endif return 1; } static int btree_merge_with_next( struct btree_root *root, int level, struct btree_cursor *next_cursor) { if (!next_cursor) return 0; if (!btree_shift_to_next(root, level, next_cursor, root->cursor[level].node->num_keys + 1)) return 0; #ifdef BTREE_STATS root->stats.merge_next += 1; #endif return 1; } static int btree_balance_with_prev( struct btree_root *root, int level, struct btree_cursor *prev_cursor) { struct btree_cursor *root_cursor = root->cursor; if (!prev_cursor) return 0; ASSERT(prev_cursor[level].node->num_keys > BTREE_KEY_MIN); #ifdef BTREE_STATS root->stats.balance_prev += 1; #endif /* * Move some nodes from the prev node into the current node. * As the shift operation is a right shift and is relative to * the root cursor, make the root cursor the prev cursor and * pass in the root cursor as the next cursor. */ root->cursor = prev_cursor; if (!btree_shift_to_next(root, level, root_cursor, (prev_cursor[level].node->num_keys + 1 - BTREE_KEY_MIN) / 2)) abort(); root->cursor = root_cursor; return 1; } static int btree_balance_with_next( struct btree_root *root, int level, struct btree_cursor *next_cursor) { struct btree_cursor *root_cursor = root->cursor; if (!next_cursor) return 0; assert(next_cursor[level].node->num_keys > BTREE_KEY_MIN); #ifdef btree_stats root->stats.balance_next += 1; #endif /* * move some nodes from the next node into the current node. * as the shift operation is a left shift and is relative to * the root cursor, make the root cursor the next cursor and * pass in the root cursor as the prev cursor. */ root->cursor = next_cursor; if (!btree_shift_to_prev(root, level, root_cursor, (next_cursor[level].node->num_keys + 1 - BTREE_KEY_MIN) / 2)) abort(); root->cursor = root_cursor; return 1; } static void btree_delete_key( struct btree_root *root, int level); /* * btree_delete_node: * * Return 0 if it's done or 1 if the next level needs to be collapsed */ static void btree_delete_node( struct btree_root *root, int level) { struct btree_cursor prev_cursor[root->height]; struct btree_cursor next_cursor[root->height]; struct btree_cursor *pc; struct btree_cursor *nc; /* * the node has underflowed, grab or merge keys/items from a * neighbouring node. */ if (level == root->height - 1) { if (level > 0 && root->root_node->num_keys == 0) btree_decrease_height(root); return; } pc = btree_copy_cursor_prev(root, prev_cursor, level + 1); if (!btree_merge_with_prev(root, level, pc)) { nc = btree_copy_cursor_next(root, next_cursor, level + 1); if (!btree_merge_with_next(root, level, nc)) { /* merging failed, try redistrubution */ if (!btree_balance_with_prev(root, level, pc) && !btree_balance_with_next(root, level, nc)) abort(); return; /* when balancing, then the node isn't freed */ } } #ifdef BTREE_STATS root->stats.alloced -= 1; #endif btree_node_free(root->cursor[level].node); btree_delete_key(root, level + 1); } static void btree_delete_key( struct btree_root *root, int level) { struct btree_node *node = root->cursor[level].node; int index = root->cursor[level].index; node->num_keys--; if (index <= node->num_keys) { /* * if not deleting the last item, shift higher items down * to cover the item being deleted */ while (index < node->num_keys) { node->keys[index] = node->keys[index + 1]; node->ptrs[index] = node->ptrs[index + 1]; index++; } node->ptrs[index] = node->ptrs[index + 1]; } else { /* * else update the associated parent key as the last key * in the leaf has changed */ btree_update_node_key(root, root->cursor, level + 1, node->keys[node->num_keys]); } /* * if node underflows, either merge with sibling or rebalance * with sibling. */ if (node->num_keys < BTREE_KEY_MIN) btree_delete_node(root, level); } void * btree_delete( struct btree_root *root, unsigned long key) { void *value; value = btree_lookup(root, key); if (!value) return NULL; #ifdef BTREE_STATS root->stats.delete += 1; root->stats.num_items -= 1; #endif btree_delete_key(root, 0); btree_invalidate_cursor(root); return value; } #ifdef BTREE_STATS void btree_print_stats( struct btree_root *root, FILE *f) { unsigned long max_items = root->stats.max_items * (root->root_node->num_keys + 1); fprintf(f, "\tnum_items = %lu, max_items = %lu (%lu%%)\n", root->stats.num_items, max_items, root->stats.num_items * 100 / max_items); fprintf(f, "\talloced = %d nodes, %lu bytes, %lu bytes per item\n", root->stats.alloced, root->stats.alloced * sizeof(struct btree_node), root->stats.alloced * sizeof(struct btree_node) / root->stats.num_items); fprintf(f, "\tlookup = %d\n", root->stats.lookup); fprintf(f, "\tfind = %d\n", root->stats.find); fprintf(f, "\tcache_hits = %d\n", root->stats.cache_hits); fprintf(f, "\tcache_misses = %d\n", root->stats.cache_misses); fprintf(f, "\tkey_update = %d\n", root->stats.key_update); fprintf(f, "\tvalue_update = %d\n", root->stats.value_update); fprintf(f, "\tinsert = %d\n", root->stats.insert); fprintf(f, "\tshift_prev = %d\n", root->stats.shift_prev); fprintf(f, "\tshift_next = %d\n", root->stats.shift_next); fprintf(f, "\tsplit = %d\n", root->stats.split); fprintf(f, "\tinc_height = %d\n", root->stats.inc_height); fprintf(f, "\tdelete = %d\n", root->stats.delete); fprintf(f, "\tmerge_prev = %d\n", root->stats.merge_prev); fprintf(f, "\tmerge_next = %d\n", root->stats.merge_next); fprintf(f, "\tbalance_prev = %d\n", root->stats.balance_prev); fprintf(f, "\tbalance_next = %d\n", root->stats.balance_next); fprintf(f, "\tdec_height = %d\n", root->stats.dec_height); } #endif xfsprogs-5.3.0/repair/btree.h0000644000175000017500000000240313435336037016006 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2007 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _BTREE_H #define _BTREE_H struct btree_root; void btree_init( struct btree_root **root); void btree_destroy( struct btree_root *root); int btree_is_empty( struct btree_root *root); void * btree_lookup( struct btree_root *root, unsigned long key); void * btree_find( struct btree_root *root, unsigned long key, unsigned long *actual_key); void * btree_peek_prev( struct btree_root *root, unsigned long *key); void * btree_peek_next( struct btree_root *root, unsigned long *key); void * btree_lookup_next( struct btree_root *root, unsigned long *key); void * btree_lookup_prev( struct btree_root *root, unsigned long *key); int btree_insert( struct btree_root *root, unsigned long key, void *value); void * btree_delete( struct btree_root *root, unsigned long key); int btree_update_key( struct btree_root *root, unsigned long old_key, unsigned long new_key); int btree_update_value( struct btree_root *root, unsigned long key, void *new_value); void btree_clear( struct btree_root *root); #ifdef BTREE_STATS void btree_print_stats( struct btree_root *root, FILE *f); #endif #endif /* _BTREE_H */ xfsprogs-5.3.0/repair/da_util.c0000644000175000017500000004430513570057155016331 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 Red Hat, Inc. * All Rights Reserved. */ /* Various utilities for repair of directory and attribute metadata */ #include "libxfs.h" #include "globals.h" #include "err_protos.h" #include "bmap.h" #include "da_util.h" /* * the cursor gets passed up and down the da btree processing * routines. The interior block processing routines use the * cursor to determine if the pointers to and from the preceding * and succeeding sibling blocks are ok and whether the values in * the current block are consistent with the entries in the parent * nodes. When a block is traversed, a parent-verification routine * is called to verify if the next logical entry in the next level up * is consistent with the greatest hashval in the next block of the * current level. The verification routine is itself recursive and * calls itself if it has to traverse an interior block to get * the next logical entry. The routine recurses upwards through * the tree until it finds a block where it can simply step to * the next entry. The hashval in that entry should be equal to * the hashval being passed to it (the greatest hashval in the block * that the entry points to). If that isn't true, then the tree * is blown and we need to trash it, salvage and trash it, or fix it. * Currently, we just trash it. */ /* * Multibuffer handling. * V2 directory blocks can be noncontiguous, needing multiple buffers. * attr blocks are single blocks; this code handles that as well. */ struct xfs_buf * da_read_buf( xfs_mount_t *mp, int nex, bmap_ext_t *bmp, const struct xfs_buf_ops *ops) { #define MAP_ARRAY_SZ 4 struct xfs_buf_map map_array[MAP_ARRAY_SZ]; struct xfs_buf_map *map; struct xfs_buf *bp; int i; if (nex > MAP_ARRAY_SZ) { map = calloc(nex, sizeof(*map)); if (map == NULL) { do_error(_("couldn't malloc dir2 buffer list\n")); exit(1); } } else { /* common case avoids calloc/free */ map = map_array; } for (i = 0; i < nex; i++) { map[i].bm_bn = XFS_FSB_TO_DADDR(mp, bmp[i].startblock); map[i].bm_len = XFS_FSB_TO_BB(mp, bmp[i].blockcount); } bp = libxfs_readbuf_map(mp->m_dev, map, nex, 0, ops); if (map != map_array) free(map); return bp; } #define FORKNAME(type) (type == XFS_DATA_FORK ? _("directory") : _("attribute")) /* * walk tree from root to the left-most leaf block reading in * blocks and setting up cursor. passes back file block number of the * left-most leaf block if successful (bno). returns 1 if successful, * 0 if unsuccessful. */ int traverse_int_dablock( xfs_mount_t *mp, da_bt_cursor_t *da_cursor, xfs_dablk_t *rbno, int whichfork) { bmap_ext_t *bmp; xfs_dablk_t bno; struct xfs_buf *bp; int i; int nex; xfs_da_intnode_t *node; bmap_ext_t lbmp; struct xfs_da_geometry *geo; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; if (whichfork == XFS_DATA_FORK) { geo = mp->m_dir_geo; bno = geo->leafblk; } else { geo = mp->m_attr_geo; bno = 0; } /* * traverse down left-side of tree until we hit the * left-most leaf block setting up the btree cursor along * the way. */ i = -1; node = NULL; da_cursor->active = 0; do { /* * read in each block along the way and set up cursor */ nex = blkmap_getn(da_cursor->blkmap, bno, geo->fsbcount, &bmp, &lbmp); if (nex == 0) goto error_out; bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops); if (bmp != &lbmp) free(bmp); if (!bp) { do_warn( _("can't read %s block %u for inode %" PRIu64 "\n"), FORKNAME(whichfork), bno, da_cursor->ino); goto error_out; } node = bp->b_addr; M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node); if (whichfork == XFS_DATA_FORK && (nodehdr.magic == XFS_DIR2_LEAFN_MAGIC || nodehdr.magic == XFS_DIR3_LEAFN_MAGIC)) { if (i != -1) { do_warn( _("found non-root LEAFN node in inode %" PRIu64 " bno = %u\n"), da_cursor->ino, bno); } *rbno = 0; libxfs_putbuf(bp); return 1; } if (nodehdr.magic != XFS_DA_NODE_MAGIC && nodehdr.magic != XFS_DA3_NODE_MAGIC) { do_warn( _("bad %s magic number 0x%x in inode %" PRIu64 " bno = %u\n"), FORKNAME(whichfork), nodehdr.magic, da_cursor->ino, bno); libxfs_putbuf(bp); goto error_out; } /* corrupt node; rebuild the dir. */ if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) { libxfs_putbuf(bp); do_warn( _("corrupt %s tree block %u for inode %" PRIu64 "\n"), FORKNAME(whichfork), bno, da_cursor->ino); goto error_out; } btree = M_DIROPS(mp)->node_tree_p(node); if (nodehdr.count > geo->node_ents) { do_warn( _("bad %s record count in inode %" PRIu64 ", count = %d, max = %d\n"), FORKNAME(whichfork), da_cursor->ino, nodehdr.count, geo->node_ents); libxfs_putbuf(bp); goto error_out; } /* * maintain level counter */ if (i == -1) { i = da_cursor->active = nodehdr.level; if (i < 1 || i >= XFS_DA_NODE_MAXDEPTH) { do_warn( _("bad header depth for directory inode %" PRIu64 "\n"), da_cursor->ino); libxfs_putbuf(bp); i = -1; goto error_out; } } else { if (nodehdr.level == i - 1) { i--; } else { do_warn( _("bad %s btree for inode %" PRIu64 "\n"), FORKNAME(whichfork), da_cursor->ino); libxfs_putbuf(bp); goto error_out; } } da_cursor->level[i].hashval = be32_to_cpu(btree[0].hashval); da_cursor->level[i].bp = bp; da_cursor->level[i].bno = bno; da_cursor->level[i].index = 0; /* * set up new bno for next level down */ bno = be32_to_cpu(btree[0].before); } while (node != NULL && i > 1); /* * now return block number and get out */ *rbno = da_cursor->level[0].bno = bno; return 1; error_out: while (i > 1 && i <= da_cursor->active) { libxfs_putbuf(da_cursor->level[i].bp); i++; } return 0; } /* * blow out buffer for this level and all the rest above as well * if error == 0, we are not expecting to encounter any unreleased * buffers (e.g. if we do, it's a mistake). if error == 1, we're * in an error-handling case so unreleased buffers may exist. */ static void release_da_cursor_int( xfs_mount_t *mp, da_bt_cursor_t *cursor, int prev_level, int error) { int level = prev_level + 1; if (cursor->level[level].bp != NULL) { if (!error) { do_warn(_("release_da_cursor_int got unexpected " "non-null bp, dabno = %u\n"), cursor->level[level].bno); } ASSERT(error != 0); libxfs_putbuf(cursor->level[level].bp); cursor->level[level].bp = NULL; } if (level < cursor->active) release_da_cursor_int(mp, cursor, level, error); return; } void release_da_cursor( xfs_mount_t *mp, da_bt_cursor_t *cursor, int prev_level) { release_da_cursor_int(mp, cursor, prev_level, 0); } void err_release_da_cursor( xfs_mount_t *mp, da_bt_cursor_t *cursor, int prev_level) { release_da_cursor_int(mp, cursor, prev_level, 1); } /* * make sure that all entries in all blocks along the right side of * of the tree are used and hashval's are consistent. level is the * level of the descendent block. returns 0 if good (even if it had * to be fixed up), and 1 if bad. The right edge of the tree is * technically a block boundary. This routine should be used then * instead of verify_da_path(). */ int verify_final_da_path( xfs_mount_t *mp, da_bt_cursor_t *cursor, const int p_level, int whichfork) { xfs_da_intnode_t *node; xfs_dahash_t hashval; int bad = 0; int entry; int this_level = p_level + 1; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; #ifdef XR_DIR_TRACE fprintf(stderr, "in verify_final_da_path, this_level = %d\n", this_level); #endif /* * the index should point to the next "unprocessed" entry * in the block which should be the final (rightmost) entry */ entry = cursor->level[this_level].index; node = cursor->level[this_level].bp->b_addr; btree = M_DIROPS(mp)->node_tree_p(node); M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node); /* * check internal block consistency on this level -- ensure * that all entries are used, encountered and expected hashvals * match, etc. */ if (entry != nodehdr.count - 1) { do_warn( _("%s block used/count inconsistency - %d/%hu\n"), FORKNAME(whichfork), entry, nodehdr.count); bad++; } /* * hash values monotonically increasing ??? */ if (cursor->level[this_level].hashval >= be32_to_cpu(btree[entry].hashval)) { do_warn( _("%s block hashvalue inconsistency, expected > %u / saw %u\n"), FORKNAME(whichfork), cursor->level[this_level].hashval, be32_to_cpu(btree[entry].hashval)); bad++; } if (nodehdr.forw != 0) { do_warn( _("bad %s forward block pointer, expected 0, saw %u\n"), FORKNAME(whichfork), nodehdr.forw); bad++; } if (bad) { do_warn(_("bad %s block in inode %" PRIu64 "\n"), FORKNAME(whichfork), cursor->ino); return 1; } /* * keep track of greatest block # -- that gets * us the length of the directory/attribute */ if (cursor->level[this_level].bno > cursor->greatest_bno) cursor->greatest_bno = cursor->level[this_level].bno; /* * ok, now check descendant block number against this level */ if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) { #ifdef XR_DIR_TRACE fprintf(stderr, "bad %s btree pointer, child bno should " "be %d, block bno is %d, hashval is %u\n", FORKNAME(whichfork), be16_to_cpu(btree[entry].before), cursor->level[p_level].bno, cursor->level[p_level].hashval); fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n"); #endif return 1; } if (cursor->level[p_level].hashval != be32_to_cpu(btree[entry].hashval)) { if (!no_modify) { do_warn( _("correcting bad hashval in non-leaf %s block\n" "\tin (level %d) in inode %" PRIu64 ".\n"), FORKNAME(whichfork), this_level, cursor->ino); btree[entry].hashval = cpu_to_be32( cursor->level[p_level].hashval); cursor->level[this_level].dirty++; } else { do_warn( _("would correct bad hashval in non-leaf %s block\n" "\tin (level %d) in inode %" PRIu64 ".\n"), FORKNAME(whichfork), this_level, cursor->ino); } } /* * Note: squirrel hashval away _before_ releasing the * buffer, preventing a use-after-free problem. */ hashval = be32_to_cpu(btree[entry].hashval); /* * release/write buffer */ ASSERT(cursor->level[this_level].dirty == 0 || (cursor->level[this_level].dirty && !no_modify)); if (cursor->level[this_level].dirty && !no_modify) libxfs_writebuf(cursor->level[this_level].bp, 0); else libxfs_putbuf(cursor->level[this_level].bp); cursor->level[this_level].bp = NULL; /* * bail out if this is the root block (top of tree) */ if (this_level >= cursor->active) { #ifdef XR_DIR_TRACE fprintf(stderr, "verify_final_da_path returns 0 (ok)\n"); #endif return 0; } /* * set hashvalue to correctly reflect the now-validated * last entry in this block and continue upwards validation */ cursor->level[this_level].hashval = hashval; return verify_final_da_path(mp, cursor, this_level, whichfork); } /* * Verifies the path from a descendant block up to the root. * Should be called when the descendant level traversal hits * a block boundary before crossing the boundary (reading in a new * block). * * the directory/attr btrees work differently to the other fs btrees. * each interior block contains records that are * pairs. The bno is a file bno, not a filesystem bno. The last * hashvalue in the block will be . BUT unlike * the freespace btrees, the *last* value in each block gets * propagated up the tree instead of the first value in each block. * that is, the interior records point to child blocks and the *greatest* * hash value contained by the child block is the one the block above * uses as the key for the child block. * * level is the level of the descendent block. returns 0 if good, * and 1 if bad. The descendant block may be a leaf block. * * the invariant here is that the values in the cursor for the * levels beneath this level (this_level) and the cursor index * for this level *must* be valid. * * that is, the hashval/bno info is accurate for all * DESCENDANTS and match what the node[index] information * for the current index in the cursor for this level. * * the index values in the cursor for the descendant level * are allowed to be off by one as they will reflect the * next entry at those levels to be processed. * * the hashvalue for the current level can't be set until * we hit the last entry in the block so, it's garbage * until set by this routine. * * bno and bp for the current block/level are always valid * since they have to be set so we can get a buffer for the * block. */ int verify_da_path( xfs_mount_t *mp, da_bt_cursor_t *cursor, const int p_level, int whichfork) { xfs_da_intnode_t *node; xfs_da_intnode_t *newnode; xfs_dablk_t dabno; struct xfs_buf *bp; int bad; int entry; int this_level = p_level + 1; bmap_ext_t *bmp; int nex; bmap_ext_t lbmp; struct xfs_da_geometry *geo; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; if (whichfork == XFS_DATA_FORK) geo = mp->m_dir_geo; else geo = mp->m_attr_geo; /* No buffer at this level, tree is corrupt. */ if (cursor->level[this_level].bp == NULL) return 1; /* * index is currently set to point to the entry that * should be processed now in this level. */ entry = cursor->level[this_level].index; node = cursor->level[this_level].bp->b_addr; btree = M_DIROPS(mp)->node_tree_p(node); M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node); /* No entries in this node? Tree is corrupt. */ if (nodehdr.count == 0) return 1; /* * if this block is out of entries, validate this * block and move on to the next block. * and update cursor value for said level */ if (entry >= nodehdr.count) { /* * update the hash value for this level before * validating it. bno value should be ok since * it was set when the block was first read in. */ cursor->level[this_level].hashval = be32_to_cpu(btree[entry - 1].hashval); /* * keep track of greatest block # -- that gets * us the length of the directory */ if (cursor->level[this_level].bno > cursor->greatest_bno) cursor->greatest_bno = cursor->level[this_level].bno; /* * validate the path for the current used-up block * before we trash it */ if (verify_da_path(mp, cursor, this_level, whichfork)) return 1; /* * ok, now get the next buffer and check sibling pointers */ dabno = nodehdr.forw; ASSERT(dabno != 0); nex = blkmap_getn(cursor->blkmap, dabno, geo->fsbcount, &bmp, &lbmp); if (nex == 0) { do_warn( _("can't get map info for %s block %u of inode %" PRIu64 "\n"), FORKNAME(whichfork), dabno, cursor->ino); return 1; } bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops); if (bmp != &lbmp) free(bmp); if (!bp) { do_warn( _("can't read %s block %u for inode %" PRIu64 "\n"), FORKNAME(whichfork), dabno, cursor->ino); return 1; } newnode = bp->b_addr; btree = M_DIROPS(mp)->node_tree_p(newnode); M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, newnode); /* * verify magic number and back pointer, sanity-check * entry count, verify level */ bad = 0; if (nodehdr.magic != XFS_DA_NODE_MAGIC && nodehdr.magic != XFS_DA3_NODE_MAGIC) { do_warn( _("bad magic number %x in %s block %u for inode %" PRIu64 "\n"), nodehdr.magic, FORKNAME(whichfork), dabno, cursor->ino); bad++; } if (nodehdr.back != cursor->level[this_level].bno) { do_warn( _("bad back pointer in %s block %u for inode %" PRIu64 "\n"), FORKNAME(whichfork), dabno, cursor->ino); bad++; } if (nodehdr.count > geo->node_ents) { do_warn( _("entry count %d too large in %s block %u for inode %" PRIu64 "\n"), nodehdr.count, FORKNAME(whichfork), dabno, cursor->ino); bad++; } if (nodehdr.level != this_level) { do_warn( _("bad level %d in %s block %u for inode %" PRIu64 "\n"), nodehdr.level, FORKNAME(whichfork), dabno, cursor->ino); bad++; } if (bad) { #ifdef XR_DIR_TRACE fprintf(stderr, "verify_da_path returns 1 (bad) #4\n"); #endif libxfs_putbuf(bp); return 1; } /* * update cursor, write out the *current* level if * required. don't write out the descendant level */ ASSERT(cursor->level[this_level].dirty == 0 || (cursor->level[this_level].dirty && !no_modify)); /* * If block looks ok but CRC didn't match, make sure to * recompute it. */ if (!no_modify && cursor->level[this_level].bp->b_error == -EFSBADCRC) cursor->level[this_level].dirty = 1; if (cursor->level[this_level].dirty && !no_modify) libxfs_writebuf(cursor->level[this_level].bp, 0); else libxfs_putbuf(cursor->level[this_level].bp); /* switch cursor to point at the new buffer we just read */ cursor->level[this_level].bp = bp; cursor->level[this_level].dirty = 0; cursor->level[this_level].bno = dabno; cursor->level[this_level].hashval = be32_to_cpu(btree[0].hashval); entry = cursor->level[this_level].index = 0; } /* * ditto for block numbers */ if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) { #ifdef XR_DIR_TRACE fprintf(stderr, "bad %s btree pointer, child bno " "should be %d, block bno is %d, hashval is %u\n", FORKNAME(whichfork), be32_to_cpu(btree[entry].before), cursor->level[p_level].bno, cursor->level[p_level].hashval); fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n"); #endif return 1; } /* * ok, now validate last hashvalue in the descendant * block against the hashval in the current entry */ if (cursor->level[p_level].hashval != be32_to_cpu(btree[entry].hashval)) { if (!no_modify) { do_warn( _("correcting bad hashval in interior %s block\n" "\tin (level %d) in inode %" PRIu64 ".\n"), FORKNAME(whichfork), this_level, cursor->ino); btree[entry].hashval = cpu_to_be32( cursor->level[p_level].hashval); cursor->level[this_level].dirty++; } else { do_warn( _("would correct bad hashval in interior %s block\n" "\tin (level %d) in inode %" PRIu64 ".\n"), FORKNAME(whichfork), this_level, cursor->ino); } } /* * increment index for this level to point to next entry * (which should point to the next descendant block) */ cursor->level[this_level].index++; #ifdef XR_DIR_TRACE fprintf(stderr, "verify_da_path returns 0 (ok)\n"); #endif return 0; } xfsprogs-5.3.0/repair/da_util.h0000644000175000017500000000240013570057155016324 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 Red Hat, Inc. * All Rights Reserved. */ #ifndef _XR_DA_UTIL_H #define _XR_DA_UTIL_H struct da_level_state { xfs_buf_t *bp; /* block bp */ xfs_dablk_t bno; /* file block number */ xfs_dahash_t hashval; /* last verified hashval */ int index; /* current index in block */ int dirty; /* is buffer dirty ? (1 == yes) */ }; typedef struct da_bt_cursor { int active; /* highest level in tree (# levels-1) */ xfs_ino_t ino; xfs_dablk_t greatest_bno; xfs_dinode_t *dip; struct da_level_state level[XFS_DA_NODE_MAXDEPTH]; struct blkmap *blkmap; } da_bt_cursor_t; struct xfs_buf * da_read_buf( xfs_mount_t *mp, int nex, bmap_ext_t *bmp, const struct xfs_buf_ops *ops); void release_da_cursor( xfs_mount_t *mp, da_bt_cursor_t *cursor, int prev_level); void err_release_da_cursor( xfs_mount_t *mp, da_bt_cursor_t *cursor, int prev_level); int traverse_int_dablock( xfs_mount_t *mp, da_bt_cursor_t *da_cursor, xfs_dablk_t *rbno, int whichfork); int verify_da_path( xfs_mount_t *mp, da_bt_cursor_t *cursor, const int p_level, int whichfork); int verify_final_da_path( xfs_mount_t *mp, da_bt_cursor_t *cursor, const int p_level, int whichfork); #endif /* _XR_DA_UTIL_H */ xfsprogs-5.3.0/repair/dino_chunks.c0000644000175000017500000010031713570057155017210 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "versions.h" #include "prefetch.h" #include "progress.h" /* * validates inode block or chunk, returns # of good inodes * the dinodes are verified using verify_uncertain_dinode() which * means only the basic inode info is checked, no fork checks. */ static int check_aginode_block(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) { xfs_dinode_t *dino_p; int i; int cnt = 0; xfs_buf_t *bp; /* * it's ok to read these possible inode blocks in one at * a time because they don't belong to known inodes (if * they did, we'd know about them courtesy of the incore inode * tree and we wouldn't be here and we stale the buffers out * so no one else will overlap them. */ bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1), 0, NULL); if (!bp) { do_warn(_("cannot read agbno (%u/%u), disk block %" PRId64 "\n"), agno, agbno, XFS_AGB_TO_DADDR(mp, agno, agbno)); return(0); } for (i = 0; i < mp->m_sb.sb_inopblock; i++) { dino_p = xfs_make_iptr(mp, bp, i); if (!verify_uncertain_dinode(mp, dino_p, agno, XFS_OFFBNO_TO_AGINO(mp, agbno, i))) cnt++; } if (cnt) bp->b_ops = &xfs_inode_buf_ops; libxfs_putbuf(bp); return(cnt); } /* * tries to establish if the inode really exists in a valid * inode chunk. returns number of new inodes if things are good * and 0 if bad. start is the start of the discovered inode chunk. * routine assumes that ino is a legal inode number * (verified by verify_inum()). If the inode chunk turns out * to be good, this routine will put the inode chunk into * the good inode chunk tree if required. * * the verify_(ag)inode* family of routines are utility * routines called by check_uncertain_aginodes() and * process_uncertain_aginodes(). */ static int verify_inode_chunk(xfs_mount_t *mp, xfs_ino_t ino, xfs_ino_t *start_ino) { xfs_agnumber_t agno; xfs_agino_t agino; xfs_agino_t start_agino; xfs_agblock_t agbno; xfs_agblock_t start_agbno = 0; xfs_agblock_t end_agbno; xfs_agblock_t max_agbno; xfs_agblock_t cur_agbno; xfs_agblock_t chunk_start_agbno; xfs_agblock_t chunk_stop_agbno; ino_tree_node_t *irec_before_p = NULL; ino_tree_node_t *irec_after_p = NULL; ino_tree_node_t *irec_p; ino_tree_node_t *irec_next_p; int irec_cnt; int ino_cnt = 0; int num_blks; int i; int j; int state; xfs_extlen_t blen; struct xfs_ino_geometry *igeo = M_IGEO(mp); agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_INO_TO_AGBNO(mp, ino); *start_ino = NULLFSINO; ASSERT(igeo->ialloc_blks > 0); if (agno == mp->m_sb.sb_agcount - 1) max_agbno = mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno; else max_agbno = mp->m_sb.sb_agblocks; /* * is the inode beyond the end of the AG? */ if (agbno >= max_agbno) return(0); /* * check for the easy case, inodes per block >= XFS_INODES_PER_CHUNK * (multiple chunks per block) */ if (igeo->ialloc_blks == 1) { if (agbno > max_agbno) return 0; if (check_aginode_block(mp, agno, agino) == 0) return 0; pthread_mutex_lock(&ag_locks[agno].lock); state = get_bmap(agno, agbno); switch (state) { case XR_E_INO: do_warn( _("uncertain inode block %d/%d already known\n"), agno, agbno); break; case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: set_bmap(agno, agbno, XR_E_INO); break; case XR_E_MULT: case XR_E_INUSE: case XR_E_INUSE_FS: case XR_E_FS_MAP: /* * if block is already claimed, forget it. */ do_warn( _("inode block %d/%d multiply claimed, (state %d)\n"), agno, agbno, state); set_bmap(agno, agbno, XR_E_MULT); pthread_mutex_unlock(&ag_locks[agno].lock); return(0); default: do_warn( _("inode block %d/%d bad state, (state %d)\n"), agno, agbno, state); set_bmap(agno, agbno, XR_E_INO); break; } pthread_mutex_unlock(&ag_locks[agno].lock); start_agino = XFS_AGB_TO_AGINO(mp, agbno); *start_ino = XFS_AGINO_TO_INO(mp, agno, start_agino); /* * put new inode record(s) into inode tree */ for (j = 0; j < chunks_pblock; j++) { if ((irec_p = find_inode_rec(mp, agno, start_agino)) == NULL) { irec_p = set_inode_free_alloc(mp, agno, start_agino); for (i = 1; i < XFS_INODES_PER_CHUNK; i++) set_inode_free(irec_p, i); } if (start_agino <= agino && agino < start_agino + XFS_INODES_PER_CHUNK) set_inode_used(irec_p, agino - start_agino); start_agino += XFS_INODES_PER_CHUNK; ino_cnt += XFS_INODES_PER_CHUNK; } return(ino_cnt); } else if (fs_aligned_inodes) { /* * next easy case -- aligned inode filesystem. * just check out the chunk */ start_agbno = rounddown(XFS_INO_TO_AGBNO(mp, ino), fs_ino_alignment); end_agbno = start_agbno + igeo->ialloc_blks; /* * if this fs has aligned inodes but the end of the * chunk is beyond the end of the ag, this is a bad * chunk */ if (end_agbno > max_agbno) return(0); /* * check out all blocks in chunk */ ino_cnt = 0; for (cur_agbno = start_agbno; cur_agbno < end_agbno; cur_agbno++) { ino_cnt += check_aginode_block(mp, agno, cur_agbno); } /* * if we lose either 2 blocks worth of inodes or >25% of * the chunk, just forget it. */ if (ino_cnt < XFS_INODES_PER_CHUNK - 2 * mp->m_sb.sb_inopblock || ino_cnt < XFS_INODES_PER_CHUNK - 16) return(0); /* * ok, put the record into the tree, if no conflict. */ if (find_uncertain_inode_rec(agno, XFS_AGB_TO_AGINO(mp, start_agbno))) return(0); start_agino = XFS_AGB_TO_AGINO(mp, start_agbno); *start_ino = XFS_AGINO_TO_INO(mp, agno, start_agino); irec_p = set_inode_free_alloc(mp, agno, XFS_AGB_TO_AGINO(mp, start_agbno)); for (i = 1; i < XFS_INODES_PER_CHUNK; i++) set_inode_free(irec_p, i); ASSERT(start_agino <= agino && start_agino + XFS_INODES_PER_CHUNK > agino); set_inode_used(irec_p, agino - start_agino); return(XFS_INODES_PER_CHUNK); } /* * hard case -- pre-6.3 filesystem. * set default start/end agbnos and ensure agbnos are legal. * we're setting a range [start_agbno, end_agbno) such that * a discovered inode chunk completely within that range * would include the inode passed into us. */ if (igeo->ialloc_blks > 1) { if (agino > igeo->ialloc_inos) start_agbno = agbno - igeo->ialloc_blks + 1; else start_agbno = 1; } end_agbno = agbno + igeo->ialloc_blks; if (end_agbno > max_agbno) end_agbno = max_agbno; /* * search tree for known inodes within +/- 1 inode chunk range */ irec_before_p = irec_after_p = NULL; find_inode_rec_range(mp, agno, XFS_AGB_TO_AGINO(mp, start_agbno), XFS_OFFBNO_TO_AGINO(mp, end_agbno, mp->m_sb.sb_inopblock - 1), &irec_before_p, &irec_after_p); /* * if we have known inode chunks in our search range, establish * their start and end-points to tighten our search range. range * is [start, end) -- e.g. max/end agbno is one beyond the * last block to be examined. the avl routines work this way. */ if (irec_before_p) { /* * only one inode record in the range, move one boundary in */ if (irec_before_p == irec_after_p) { if (irec_before_p->ino_startnum < agino) start_agbno = XFS_AGINO_TO_AGBNO(mp, irec_before_p->ino_startnum + XFS_INODES_PER_CHUNK); else end_agbno = XFS_AGINO_TO_AGBNO(mp, irec_before_p->ino_startnum); } /* * find the start of the gap in the search range (which * should contain our unknown inode). if the only irec * within +/- 1 chunks starts after the inode we're * looking for, skip this stuff since the end_agbno * of the range has already been trimmed in to not * include that irec. */ if (irec_before_p->ino_startnum < agino) { irec_p = irec_before_p; irec_next_p = next_ino_rec(irec_p); while(irec_next_p != NULL && irec_p->ino_startnum + XFS_INODES_PER_CHUNK == irec_next_p->ino_startnum) { irec_p = irec_next_p; irec_next_p = next_ino_rec(irec_next_p); } start_agbno = XFS_AGINO_TO_AGBNO(mp, irec_p->ino_startnum) + igeo->ialloc_blks; /* * we know that the inode we're trying to verify isn't * in an inode chunk so the next ino_rec marks the end * of the gap -- is it within the search range? */ if (irec_next_p != NULL && agino + igeo->ialloc_inos >= irec_next_p->ino_startnum) end_agbno = XFS_AGINO_TO_AGBNO(mp, irec_next_p->ino_startnum); } ASSERT(start_agbno < end_agbno); } /* * if the gap is too small to contain a chunk, we lose. * this means that inode chunks known to be good surround * the inode in question and that the space between them * is too small for a legal inode chunk */ if (end_agbno - start_agbno < igeo->ialloc_blks) return(0); /* * now grunge around the disk, start at the inode block and * go in each direction until you hit a non-inode block or * run into a range boundary. A non-inode block is block * with *no* good inodes in it. Unfortunately, we can't * co-opt bad blocks into inode chunks (which might take * care of disk blocks that turn into zeroes) because the * filesystem could very well allocate two inode chunks * with a one block file in between and we'd zap the file. * We're better off just losing the rest of the * inode chunk instead. */ for (cur_agbno = agbno; cur_agbno >= start_agbno; cur_agbno--) { /* * if the block has no inodes, it's a bad block so * break out now without decrementing cur_agbno so * chunk start blockno will be set to the last good block */ if (!(irec_cnt = check_aginode_block(mp, agno, cur_agbno))) break; ino_cnt += irec_cnt; } chunk_start_agbno = cur_agbno + 1; for (cur_agbno = agbno + 1; cur_agbno < end_agbno; cur_agbno++) { /* * if the block has no inodes, it's a bad block so * break out now without incrementing cur_agbno so * chunk start blockno will be set to the block * immediately after the last good block. */ if (!(irec_cnt = check_aginode_block(mp, agno, cur_agbno))) break; ino_cnt += irec_cnt; } chunk_stop_agbno = cur_agbno; num_blks = chunk_stop_agbno - chunk_start_agbno; if (num_blks < igeo->ialloc_blks || ino_cnt == 0) return 0; /* * XXX - later - if the entire range is selected and they're all * good inodes, keep searching in either direction. * until you the range of inodes end, then split into chunks * for now, just take one chunk's worth starting at the lowest * possible point and hopefully we'll pick the rest up later. * * XXX - if we were going to fix up an inode chunk for * any good inodes in the chunk, this is where we would * do it. For now, keep it simple and lose the rest of * the chunk */ if (num_blks % igeo->ialloc_blks != 0) { num_blks = rounddown(num_blks, igeo->ialloc_blks); chunk_stop_agbno = chunk_start_agbno + num_blks; } /* * ok, we've got a candidate inode chunk. now we have to * verify that we aren't trying to use blocks that are already * in use. If so, mark them as multiply claimed since odds * are very low that we found this chunk by stumbling across * user data -- we're probably here as a result of a directory * entry or an iunlinked pointer */ pthread_mutex_lock(&ag_locks[agno].lock); for (cur_agbno = chunk_start_agbno; cur_agbno < chunk_stop_agbno; cur_agbno += blen) { state = get_bmap_ext(agno, cur_agbno, chunk_stop_agbno, &blen); switch (state) { case XR_E_MULT: case XR_E_INUSE: case XR_E_INUSE_FS: case XR_E_FS_MAP: do_warn( _("inode block %d/%d multiply claimed, (state %d)\n"), agno, cur_agbno, state); set_bmap_ext(agno, cur_agbno, blen, XR_E_MULT); pthread_mutex_unlock(&ag_locks[agno].lock); return 0; case XR_E_INO: do_error( _("uncertain inode block overlap, agbno = %d, ino = %" PRIu64 "\n"), agbno, ino); break; default: break; } } pthread_mutex_unlock(&ag_locks[agno].lock); /* * ok, chunk is good. put the record into the tree if required, * and fill in the bitmap. All inodes will be marked as "free" * except for the one that led us to discover the chunk. That's * ok because we'll override the free setting later if the * contents of the inode indicate it's in use. */ start_agino = XFS_AGB_TO_AGINO(mp, chunk_start_agbno); *start_ino = XFS_AGINO_TO_INO(mp, agno, start_agino); ASSERT(find_inode_rec(mp, agno, start_agino) == NULL); irec_p = set_inode_free_alloc(mp, agno, start_agino); for (i = 1; i < XFS_INODES_PER_CHUNK; i++) set_inode_free(irec_p, i); ASSERT(start_agino <= agino && start_agino + XFS_INODES_PER_CHUNK > agino); set_inode_used(irec_p, agino - start_agino); pthread_mutex_lock(&ag_locks[agno].lock); for (cur_agbno = chunk_start_agbno; cur_agbno < chunk_stop_agbno; cur_agbno += blen) { state = get_bmap_ext(agno, cur_agbno, chunk_stop_agbno, &blen); switch (state) { case XR_E_INO: do_error( _("uncertain inode block %" PRIu64 " already known\n"), XFS_AGB_TO_FSB(mp, agno, cur_agbno)); break; case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: set_bmap_ext(agno, cur_agbno, blen, XR_E_INO); break; case XR_E_MULT: case XR_E_INUSE: case XR_E_INUSE_FS: case XR_E_FS_MAP: do_error( _("inode block %d/%d multiply claimed, (state %d)\n"), agno, cur_agbno, state); break; default: do_warn( _("inode block %d/%d bad state, (state %d)\n"), agno, cur_agbno, state); set_bmap_ext(agno, cur_agbno, blen, XR_E_INO); break; } } pthread_mutex_unlock(&ag_locks[agno].lock); return(ino_cnt); } /* * same as above only for ag inode chunks */ static int verify_aginode_chunk(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t agino, xfs_agino_t *agino_start) { xfs_ino_t ino; int res; res = verify_inode_chunk(mp, XFS_AGINO_TO_INO(mp, agno, agino), &ino); if (res) *agino_start = XFS_INO_TO_AGINO(mp, ino); else *agino_start = NULLAGINO; return(res); } /* * this does the same as the two above only it returns a pointer * to the inode record in the good inode tree */ static ino_tree_node_t * verify_aginode_chunk_irec(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t agino) { xfs_agino_t start_agino; ino_tree_node_t *irec = NULL; if (verify_aginode_chunk(mp, agno, agino, &start_agino)) irec = find_inode_rec(mp, agno, start_agino); return(irec); } /* * Set the state of an inode block during inode chunk processing. The block is * expected to be in the free or inode state. If free, it transitions to the * inode state. Warn if the block is in neither expected state as this indicates * multiply claimed blocks. */ static void process_inode_agbno_state( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) { int state; pthread_mutex_lock(&ag_locks[agno].lock); state = get_bmap(agno, agbno); switch (state) { case XR_E_INO: /* already marked */ break; case XR_E_UNKNOWN: case XR_E_FREE: case XR_E_FREE1: set_bmap(agno, agbno, XR_E_INO); break; case XR_E_BAD_STATE: do_error(_("bad state in block map %d\n"), state); break; default: set_bmap(agno, agbno, XR_E_MULT); do_warn( _("inode block %" PRIu64 " multiply claimed, state was %d\n"), XFS_AGB_TO_FSB(mp, agno, agbno), state); break; } pthread_mutex_unlock(&ag_locks[agno].lock); } /* * processes an inode allocation chunk/block, returns 1 on I/O errors, * 0 otherwise * * *bogus is set to 1 if the entire set of inodes is bad. */ static int process_inode_chunk( xfs_mount_t *mp, xfs_agnumber_t agno, int num_inos, ino_tree_node_t *first_irec, int ino_discovery, int check_dups, int extra_attr_check, int *bogus) { xfs_ino_t parent; ino_tree_node_t *ino_rec; xfs_buf_t **bplist; xfs_dinode_t *dino; int icnt; int status; int is_used; int ino_dirty; int irec_offset; int ibuf_offset; xfs_agino_t agino; xfs_agblock_t agbno; xfs_ino_t ino; int dirty = 0; int isa_dir = 0; int cluster_count; int bp_index; int cluster_offset; struct xfs_ino_geometry *igeo = M_IGEO(mp); ASSERT(first_irec != NULL); ASSERT(XFS_AGINO_TO_OFFSET(mp, first_irec->ino_startnum) == 0); *bogus = 0; ASSERT(igeo->ialloc_blks > 0); cluster_count = XFS_INODES_PER_CHUNK / M_IGEO(mp)->inodes_per_cluster; if (cluster_count == 0) cluster_count = 1; /* * get all blocks required to read in this chunk (may wind up * having to process more chunks in a multi-chunk per block fs) */ agbno = XFS_AGINO_TO_AGBNO(mp, first_irec->ino_startnum); /* * set up first irec */ ino_rec = first_irec; irec_offset = 0; bplist = malloc(cluster_count * sizeof(xfs_buf_t *)); if (bplist == NULL) do_error(_("failed to allocate %zd bytes of memory\n"), cluster_count * sizeof(xfs_buf_t *)); for (bp_index = 0; bp_index < cluster_count; bp_index++) { /* * Skip the cluster buffer if the first inode is sparse. The * remaining inodes in the cluster share the same state as * sparse inodes occur at cluster granularity. */ if (is_inode_sparse(ino_rec, irec_offset)) { pftrace("skip sparse inode, startnum 0x%x idx %d", ino_rec->ino_startnum, irec_offset); bplist[bp_index] = NULL; goto next_readbuf; } pftrace("about to read off %llu in AG %d", XFS_AGB_TO_DADDR(mp, agno, agbno), agno); bplist[bp_index] = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster), 0, &xfs_inode_buf_ops); if (!bplist[bp_index]) { do_warn(_("cannot read inode %" PRIu64 ", disk block %" PRId64 ", cnt %d\n"), XFS_AGINO_TO_INO(mp, agno, first_irec->ino_startnum), XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster)); while (bp_index > 0) { bp_index--; libxfs_putbuf(bplist[bp_index]); } free(bplist); return(1); } pftrace("readbuf %p (%llu, %d) in AG %d", bplist[bp_index], (long long)XFS_BUF_ADDR(bplist[bp_index]), bplist[bp_index]->b_bcount, agno); bplist[bp_index]->b_ops = &xfs_inode_buf_ops; next_readbuf: irec_offset += mp->m_sb.sb_inopblock * M_IGEO(mp)->blocks_per_cluster; agbno += M_IGEO(mp)->blocks_per_cluster; } agbno = XFS_AGINO_TO_AGBNO(mp, first_irec->ino_startnum); /* * initialize counters */ irec_offset = 0; ibuf_offset = 0; cluster_offset = 0; icnt = 0; status = 0; bp_index = 0; /* * verify inode chunk if necessary */ if (ino_discovery) { for (;;) { agino = irec_offset + ino_rec->ino_startnum; /* no buffers for sparse clusters */ if (bplist[bp_index]) { /* make inode pointer */ dino = xfs_make_iptr(mp, bplist[bp_index], cluster_offset); /* * we always think that the root and realtime * inodes are verified even though we may have * to reset them later to keep from losing the * chunk that they're in */ if (verify_dinode(mp, dino, agno, agino) == 0 || (agno == 0 && (mp->m_sb.sb_rootino == agino || mp->m_sb.sb_rsumino == agino || mp->m_sb.sb_rbmino == agino))) status++; } irec_offset++; icnt++; cluster_offset++; if (icnt == igeo->ialloc_inos && irec_offset == XFS_INODES_PER_CHUNK) { /* * done! - finished up irec and block * simultaneously */ break; } else if (irec_offset == XFS_INODES_PER_CHUNK) { /* * get new irec (multiple chunks per block fs) */ ino_rec = next_ino_rec(ino_rec); ASSERT(ino_rec->ino_startnum == agino + 1); irec_offset = 0; } if (cluster_offset == M_IGEO(mp)->inodes_per_cluster) { bp_index++; cluster_offset = 0; } } /* * if chunk/block is bad, blow it off. the inode records * will be deleted by the caller if appropriate. */ if (!status) { *bogus = 1; for (bp_index = 0; bp_index < cluster_count; bp_index++) if (bplist[bp_index]) libxfs_putbuf(bplist[bp_index]); free(bplist); return(0); } /* * reset irec and counters */ ino_rec = first_irec; irec_offset = 0; cluster_offset = 0; bp_index = 0; icnt = 0; status = 0; } /* * mark block as an inode block in the incore bitmap */ if (!is_inode_sparse(ino_rec, irec_offset)) process_inode_agbno_state(mp, agno, agbno); for (;;) { agino = irec_offset + ino_rec->ino_startnum; ino = XFS_AGINO_TO_INO(mp, agno, agino); if (is_inode_sparse(ino_rec, irec_offset)) goto process_next; /* make inode pointer */ dino = xfs_make_iptr(mp, bplist[bp_index], cluster_offset); is_used = 3; ino_dirty = 0; parent = 0; status = process_dinode(mp, dino, agno, agino, is_inode_free(ino_rec, irec_offset), &ino_dirty, &is_used,ino_discovery, check_dups, extra_attr_check, &isa_dir, &parent); ASSERT(is_used != 3); if (ino_dirty) { dirty = 1; libxfs_dinode_calc_crc(mp, dino); } /* * XXX - if we want to try and keep * track of whether we need to bang on * the inode maps (instead of just * blindly reconstructing them like * we do now, this is where to start. */ if (is_used) { if (is_inode_free(ino_rec, irec_offset)) { if (verbose || no_modify) { do_warn( _("imap claims in-use inode %" PRIu64 " is free, "), ino); } if (verbose || !no_modify) do_warn(_("correcting imap\n")); else do_warn(_("would correct imap\n")); } set_inode_used(ino_rec, irec_offset); /* * store the on-disk file type for comparing in * phase 6. */ set_inode_ftype(ino_rec, irec_offset, libxfs_mode_to_ftype(be16_to_cpu(dino->di_mode))); /* * store on-disk nlink count for comparing in phase 7 */ set_inode_disk_nlinks(ino_rec, irec_offset, dino->di_version > 1 ? be32_to_cpu(dino->di_nlink) : be16_to_cpu(dino->di_onlink)); } else { set_inode_free(ino_rec, irec_offset); } /* * if we lose the root inode, or it turns into * a non-directory, that allows us to double-check * later whether or not we need to reinitialize it. */ if (isa_dir) { set_inode_isadir(ino_rec, irec_offset); /* * we always set the parent but * we may as well wait until * phase 4 (no inode discovery) * because the parent info will * be solid then. */ if (!ino_discovery) { ASSERT(parent != 0); set_inode_parent(ino_rec, irec_offset, parent); ASSERT(parent == get_inode_parent(ino_rec, irec_offset)); } } else { clear_inode_isadir(ino_rec, irec_offset); } if (status) { if (mp->m_sb.sb_rootino == ino) { need_root_inode = 1; if (!no_modify) { do_warn( _("cleared root inode %" PRIu64 "\n"), ino); } else { do_warn( _("would clear root inode %" PRIu64 "\n"), ino); } } else if (mp->m_sb.sb_rbmino == ino) { need_rbmino = 1; if (!no_modify) { do_warn( _("cleared realtime bitmap inode %" PRIu64 "\n"), ino); } else { do_warn( _("would clear realtime bitmap inode %" PRIu64 "\n"), ino); } } else if (mp->m_sb.sb_rsumino == ino) { need_rsumino = 1; if (!no_modify) { do_warn( _("cleared realtime summary inode %" PRIu64 "\n"), ino); } else { do_warn( _("would clear realtime summary inode %" PRIu64 "\n"), ino); } } else if (!no_modify) { do_warn(_("cleared inode %" PRIu64 "\n"), ino); } else { do_warn(_("would have cleared inode %" PRIu64 "\n"), ino); } clear_inode_was_rl(ino_rec, irec_offset); } process_next: irec_offset++; ibuf_offset++; icnt++; cluster_offset++; if (icnt == igeo->ialloc_inos && irec_offset == XFS_INODES_PER_CHUNK) { /* * done! - finished up irec and block simultaneously */ for (bp_index = 0; bp_index < cluster_count; bp_index++) { if (!bplist[bp_index]) continue; pftrace("put/writebuf %p (%llu) in AG %d", bplist[bp_index], (long long) XFS_BUF_ADDR(bplist[bp_index]), agno); if (dirty && !no_modify) libxfs_writebuf(bplist[bp_index], 0); else libxfs_putbuf(bplist[bp_index]); } free(bplist); break; } else if (ibuf_offset == mp->m_sb.sb_inopblock) { /* * mark block as an inode block in the incore bitmap * and reset inode buffer offset counter */ ibuf_offset = 0; agbno++; if (!is_inode_sparse(ino_rec, irec_offset)) process_inode_agbno_state(mp, agno, agbno); } else if (irec_offset == XFS_INODES_PER_CHUNK) { /* * get new irec (multiple chunks per block fs) */ ino_rec = next_ino_rec(ino_rec); ASSERT(ino_rec->ino_startnum == agino + 1); irec_offset = 0; } if (cluster_offset == M_IGEO(mp)->inodes_per_cluster) { bp_index++; cluster_offset = 0; } } return(0); } /* * check all inodes mentioned in the ag's incore inode maps. * the map may be incomplete. If so, we'll catch the missing * inodes (hopefully) when we traverse the directory tree. * check_dirs is set to 1 if directory inodes should be * processed for internal consistency, parent setting and * discovery of unknown inodes. this only happens * in phase 3. check_dups is set to 1 if we're looking for * inodes that reference duplicate blocks so we can trash * the inode right then and there. this is set only in * phase 4 after we've run through and set the bitmap once. */ void process_aginodes( xfs_mount_t *mp, prefetch_args_t *pf_args, xfs_agnumber_t agno, int ino_discovery, int check_dups, int extra_attr_check) { int num_inos, bogus; ino_tree_node_t *ino_rec, *first_ino_rec, *prev_ino_rec; struct xfs_ino_geometry *igeo = M_IGEO(mp); #ifdef XR_PF_TRACE int count; #endif first_ino_rec = ino_rec = findfirst_inode_rec(agno); while (ino_rec != NULL) { /* * paranoia - step through inode records until we step * through a full allocation of inodes. this could * be an issue in big-block filesystems where a block * can hold more than one inode chunk. make sure to * grab the record corresponding to the beginning of * the next block before we call the processing routines. */ num_inos = XFS_INODES_PER_CHUNK; while (num_inos < igeo->ialloc_inos && ino_rec != NULL) { /* * inodes chunks will always be aligned and sized * correctly */ if ((ino_rec = next_ino_rec(ino_rec)) != NULL) num_inos += XFS_INODES_PER_CHUNK; } ASSERT(num_inos == igeo->ialloc_inos); if (pf_args) { sem_post(&pf_args->ra_count); #ifdef XR_PF_TRACE sem_getvalue(&pf_args->ra_count, &count); pftrace("processing inode chunk %p in AG %d (sem count = %d)", first_ino_rec, agno, count); #endif } if (process_inode_chunk(mp, agno, num_inos, first_ino_rec, ino_discovery, check_dups, extra_attr_check, &bogus)) { /* XXX - i/o error, we've got a problem */ abort(); } if (!bogus) first_ino_rec = ino_rec = next_ino_rec(ino_rec); else { /* * inodes pointed to by this record are * completely bogus, blow the records for * this chunk out. * the inode block(s) will get reclaimed * in phase 4 when the block map is * reconstructed after inodes claiming * duplicate blocks are deleted. */ num_inos = 0; ino_rec = first_ino_rec; while (num_inos < igeo->ialloc_inos && ino_rec != NULL) { prev_ino_rec = ino_rec; if ((ino_rec = next_ino_rec(ino_rec)) != NULL) num_inos += XFS_INODES_PER_CHUNK; get_inode_rec(mp, agno, prev_ino_rec); free_inode_rec(agno, prev_ino_rec); } first_ino_rec = ino_rec; } PROG_RPT_INC(prog_rpt_done[agno], num_inos); } } /* * verify the uncertain inode list for an ag. * Good inodes get moved into the good inode tree. * returns 0 if there are no uncertain inode records to * be processed, 1 otherwise. This routine destroys the * the entire uncertain inode tree for the ag as a side-effect. */ void check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) { ino_tree_node_t *irec; ino_tree_node_t *nrec; xfs_agino_t start; xfs_agino_t i; xfs_agino_t agino; int got_some; nrec = NULL; got_some = 0; clear_uncertain_ino_cache(agno); if ((irec = findfirst_uncertain_inode_rec(agno)) == NULL) return; /* * the trick here is to find a contiguous range * of inodes, make sure that it doesn't overlap * with a known to exist chunk, and then make * sure it is a number of entire chunks. * we check on-disk once we have an idea of what's * going on just to double-check. * * process the uncertain inode record list and look * on disk to see if the referenced inodes are good */ do_warn(_("found inodes not in the inode allocation tree\n")); do { /* * check every confirmed (which in this case means * inode that we really suspect to be an inode) inode */ for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { if (!is_inode_confirmed(irec, i)) continue; agino = i + irec->ino_startnum; if (verify_aginum(mp, agno, agino)) continue; if (nrec != NULL && nrec->ino_startnum <= agino && agino < nrec->ino_startnum + XFS_INODES_PER_CHUNK) continue; if ((nrec = find_inode_rec(mp, agno, agino)) == NULL) if (!verify_aginum(mp, agno, agino)) if (verify_aginode_chunk(mp, agno, agino, &start)) got_some = 1; } get_uncertain_inode_rec(mp, agno, irec); free_inode_rec(agno, irec); irec = findfirst_uncertain_inode_rec(agno); } while (irec != NULL); if (got_some) do_warn(_("found inodes not in the inode allocation tree\n")); return; } /* * verify and process the uncertain inodes for an ag. * this is different from check_ in that we can't just * move the good inodes into the good inode tree and let * process_aginodes() deal with them because this gets called * after process_aginodes() has been run on the ag inode tree. * So we have to process the inodes as well as verify since * we don't want to rerun process_aginodes() on a tree that has * mostly been processed. * * Note that if this routine does process some inodes, it can * add uncertain inodes to any ag which would require that * the routine be called again to process those newly-added * uncertain inodes. * * returns 0 if no inodes were processed and 1 if inodes * were processed (and it is possible that new uncertain * inodes were discovered). * * as a side-effect, this routine tears down the uncertain * inode tree for the ag. */ int process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) { ino_tree_node_t *irec; ino_tree_node_t *nrec; xfs_agino_t agino; int i; int bogus; int cnt; int got_some; struct xfs_ino_geometry *igeo = M_IGEO(mp); #ifdef XR_INODE_TRACE fprintf(stderr, "in process_uncertain_aginodes, agno = %d\n", agno); #endif got_some = 0; clear_uncertain_ino_cache(agno); if ((irec = findfirst_uncertain_inode_rec(agno)) == NULL) return(0); nrec = NULL; do { /* * check every confirmed inode */ for (cnt = i = 0; i < XFS_INODES_PER_CHUNK; i++) { if (!is_inode_confirmed(irec, i)) continue; cnt++; agino = i + irec->ino_startnum; #ifdef XR_INODE_TRACE fprintf(stderr, "ag inode = %d (0x%x)\n", agino, agino); #endif /* * skip over inodes already processed (in the * good tree), bad inode numbers, and inode numbers * pointing to bogus inodes */ if (verify_aginum(mp, agno, agino)) continue; if (nrec != NULL && nrec->ino_startnum <= agino && agino < nrec->ino_startnum + XFS_INODES_PER_CHUNK) continue; if ((nrec = find_inode_rec(mp, agno, agino)) != NULL) continue; /* * verify the chunk. if good, it will be * added to the good inode tree. */ if ((nrec = verify_aginode_chunk_irec(mp, agno, agino)) == NULL) continue; got_some = 1; /* * process the inode record we just added * to the good inode tree. The inode * processing may add more records to the * uncertain inode lists. */ if (process_inode_chunk(mp, agno, igeo->ialloc_inos, nrec, 1, 0, 0, &bogus)) { /* XXX - i/o error, we've got a problem */ abort(); } } ASSERT(cnt != 0); /* * now return the uncertain inode record to the free pool * and pull another one off the list for processing */ get_uncertain_inode_rec(mp, agno, irec); free_inode_rec(agno, irec); irec = findfirst_uncertain_inode_rec(agno); } while (irec != NULL); if (got_some) do_warn(_("found inodes not in the inode allocation tree\n")); return(1); } xfsprogs-5.3.0/repair/dinode.c0000644000175000017500000022322513570057155016152 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dir2.h" #include "dinode.h" #include "scan.h" #include "versions.h" #include "attr_repair.h" #include "bmap.h" #include "threads.h" #include "slab.h" #include "rmap.h" /* * gettext lookups for translations of strings use mutexes internally to * the library. Hence when we come through here doing parallel scans in * multiple AGs, then all do concurrent text conversions and serialise * on the translation string lookups. Let's avoid doing repeated lookups * by making them static variables and only assigning the translation * once. */ static char *forkname_data; static char *forkname_attr; static char *ftype_real_time; static char *ftype_regular; void dinode_bmbt_translation_init(void) { forkname_data = _("data"); forkname_attr = _("attr"); ftype_real_time = _("real-time"); ftype_regular = _("regular"); } char * get_forkname(int whichfork) { if (whichfork == XFS_DATA_FORK) return forkname_data; return forkname_attr; } /* * inode clearing routines */ static int clear_dinode_attr(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num) { ASSERT(dino->di_forkoff != 0); if (!no_modify) fprintf(stderr, _("clearing inode %" PRIu64 " attributes\n"), ino_num); else fprintf(stderr, _("would have cleared inode %" PRIu64 " attributes\n"), ino_num); if (be16_to_cpu(dino->di_anextents) != 0) { if (no_modify) return(1); dino->di_anextents = cpu_to_be16(0); } if (dino->di_aformat != XFS_DINODE_FMT_EXTENTS) { if (no_modify) return(1); dino->di_aformat = XFS_DINODE_FMT_EXTENTS; } /* get rid of the fork by clearing forkoff */ /* Originally, when the attr repair code was added, the fork was cleared * by turning it into shortform status. This meant clearing the * hdr.totsize/count fields and also changing aformat to LOCAL * (vs EXTENTS). Over various fixes, the aformat and forkoff have * been updated to not show an attribute fork at all, however. * It could be possible that resetting totsize/count are not needed, * but just to be safe, leave it in for now. */ if (!no_modify) { xfs_attr_shortform_t *asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dino); asf->hdr.totsize = cpu_to_be16(sizeof(xfs_attr_sf_hdr_t)); asf->hdr.count = 0; dino->di_forkoff = 0; /* got to do this after asf is set */ } /* * always returns 1 since the fork gets zapped */ return(1); } static void clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num) { memset(dinoc, 0, sizeof(*dinoc)); dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); if (xfs_sb_version_hascrc(&mp->m_sb)) dinoc->di_version = 3; else dinoc->di_version = 2; dinoc->di_gen = cpu_to_be32(random()); dinoc->di_format = XFS_DINODE_FMT_EXTENTS; dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS; /* we are done for version 1/2 inodes */ if (dinoc->di_version < 3) return; dinoc->di_ino = cpu_to_be64(ino_num); platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid); return; } static void clear_dinode_unlinked(xfs_mount_t *mp, xfs_dinode_t *dino) { dino->di_next_unlinked = cpu_to_be32(NULLAGINO); } /* * this clears the unlinked list too so it should not be called * until after the agi unlinked lists are walked in phase 3. */ static void clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num) { clear_dinode_core(mp, dino, ino_num); clear_dinode_unlinked(mp, dino); /* and clear the forks */ memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp, dino->di_version)); return; } /* * misc. inode-related utility routines */ /* * verify_ag_bno is heavily used. In the common case, it * performs just two number of compares * Returns 1 for bad ag/bno pair or 0 if it's valid. */ static __inline int verify_ag_bno(xfs_sb_t *sbp, xfs_agnumber_t agno, xfs_agblock_t agbno) { if (agno < (sbp->sb_agcount - 1)) return (agbno >= sbp->sb_agblocks); if (agno == (sbp->sb_agcount - 1)) return (agbno >= (sbp->sb_dblocks - ((xfs_rfsblock_t)(sbp->sb_agcount - 1) * sbp->sb_agblocks))); return 1; } /* * returns 0 if inode number is valid, 1 if bogus */ int verify_inum(xfs_mount_t *mp, xfs_ino_t ino) { xfs_agnumber_t agno; xfs_agino_t agino; xfs_agblock_t agbno; xfs_sb_t *sbp = &mp->m_sb;; /* range check ag #, ag block. range-checking offset is pointless */ agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agbno == 0) return 1; if (ino == 0 || ino == NULLFSINO) return(1); if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) return(1); return verify_ag_bno(sbp, agno, agbno); } /* * have a separate routine to ensure that we don't accidentally * lose illegally set bits in the agino by turning it into an FSINO * to feed to the above routine */ int verify_aginum(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t agino) { xfs_agblock_t agbno; xfs_sb_t *sbp = &mp->m_sb;; /* range check ag #, ag block. range-checking offset is pointless */ if (agino == 0 || agino == NULLAGINO) return(1); /* * agino's can't be too close to NULLAGINO because the min blocksize * is 9 bits and at most 1 bit of that gets used for the inode offset * so if the agino gets shifted by the # of offset bits and compared * to the legal agbno values, a bogus agino will be too large. there * will be extra bits set at the top that shouldn't be set. */ agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agbno == 0) return 1; return verify_ag_bno(sbp, agno, agbno); } /* * return 1 if block number is good, 0 if out of range */ int verify_dfsbno(xfs_mount_t *mp, xfs_fsblock_t fsbno) { xfs_agnumber_t agno; xfs_agblock_t agbno; xfs_sb_t *sbp = &mp->m_sb;; /* range check ag #, ag block. range-checking offset is pointless */ agno = XFS_FSB_TO_AGNO(mp, fsbno); agbno = XFS_FSB_TO_AGBNO(mp, fsbno); return verify_ag_bno(sbp, agno, agbno) == 0; } #define XR_DFSBNORANGE_VALID 0 #define XR_DFSBNORANGE_BADSTART 1 #define XR_DFSBNORANGE_BADEND 2 #define XR_DFSBNORANGE_OVERFLOW 3 static __inline int verify_dfsbno_range(xfs_mount_t *mp, xfs_fsblock_t fsbno, xfs_filblks_t count) { xfs_agnumber_t agno; xfs_agblock_t agbno; xfs_sb_t *sbp = &mp->m_sb;; /* the start and end blocks better be in the same allocation group */ agno = XFS_FSB_TO_AGNO(mp, fsbno); if (agno != XFS_FSB_TO_AGNO(mp, fsbno + count - 1)) { return XR_DFSBNORANGE_OVERFLOW; } agbno = XFS_FSB_TO_AGBNO(mp, fsbno); if (verify_ag_bno(sbp, agno, agbno)) { return XR_DFSBNORANGE_BADSTART; } agbno = XFS_FSB_TO_AGBNO(mp, fsbno + count - 1); if (verify_ag_bno(sbp, agno, agbno)) { return XR_DFSBNORANGE_BADEND; } return (XR_DFSBNORANGE_VALID); } int verify_agbno(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) { xfs_sb_t *sbp = &mp->m_sb;; /* range check ag #, ag block. range-checking offset is pointless */ return verify_ag_bno(sbp, agno, agbno) == 0; } static int process_rt_rec( xfs_mount_t *mp, xfs_bmbt_irec_t *irec, xfs_ino_t ino, xfs_rfsblock_t *tot, int check_dups) { xfs_fsblock_t b; xfs_rtblock_t ext; int state; int pwe; /* partially-written extent */ /* * check numeric validity of the extent */ if (irec->br_startblock >= mp->m_sb.sb_rblocks) { do_warn( _("inode %" PRIu64 " - bad rt extent start block number %" PRIu64 ", offset %" PRIu64 "\n"), ino, irec->br_startblock, irec->br_startoff); return 1; } if (irec->br_startblock + irec->br_blockcount - 1 >= mp->m_sb.sb_rblocks) { do_warn( _("inode %" PRIu64 " - bad rt extent last block number %" PRIu64 ", offset %" PRIu64 "\n"), ino, irec->br_startblock + irec->br_blockcount - 1, irec->br_startoff); return 1; } if (irec->br_startblock + irec->br_blockcount - 1 < irec->br_startblock) { do_warn( _("inode %" PRIu64 " - bad rt extent overflows - start %" PRIu64 ", " "end %" PRIu64 ", offset %" PRIu64 "\n"), ino, irec->br_startblock, irec->br_startblock + irec->br_blockcount - 1, irec->br_startoff); return 1; } /* * set the appropriate number of extents * this iterates block by block, this can be optimised using extents */ for (b = irec->br_startblock; b < irec->br_startblock + irec->br_blockcount; b += mp->m_sb.sb_rextsize) { ext = (xfs_rtblock_t) b / mp->m_sb.sb_rextsize; pwe = irec->br_state == XFS_EXT_UNWRITTEN && (b % mp->m_sb.sb_rextsize != 0); if (check_dups == 1) { if (search_rt_dup_extent(mp, ext) && !pwe) { do_warn( _("data fork in rt ino %" PRIu64 " claims dup rt extent," "off - %" PRIu64 ", start - %" PRIu64 ", count %" PRIu64 "\n"), ino, irec->br_startoff, irec->br_startblock, irec->br_blockcount); return 1; } continue; } state = get_rtbmap(ext); switch (state) { case XR_E_FREE: case XR_E_UNKNOWN: set_rtbmap(ext, XR_E_INUSE); break; case XR_E_BAD_STATE: do_error( _("bad state in rt block map %" PRIu64 "\n"), ext); case XR_E_FS_MAP: case XR_E_INO: case XR_E_INUSE_FS: do_error( _("data fork in rt inode %" PRIu64 " found metadata block %" PRIu64 " in rt bmap\n"), ino, ext); case XR_E_INUSE: if (pwe) break; /* fall through */ case XR_E_MULT: set_rtbmap(ext, XR_E_MULT); do_warn( _("data fork in rt inode %" PRIu64 " claims used rt block %" PRIu64 "\n"), ino, ext); return 1; case XR_E_FREE1: default: do_error( _("illegal state %d in rt block map %" PRIu64 "\n"), state, b); } } /* * bump up the block counter */ *tot += irec->br_blockcount; return 0; } /* * return 1 if inode should be cleared, 0 otherwise * if check_dups should be set to 1, that implies that * the primary purpose of this call is to see if the * file overlaps with any duplicate extents (in the * duplicate extent list). */ static int process_bmbt_reclist_int( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, int *numrecs, int type, xfs_ino_t ino, xfs_rfsblock_t *tot, blkmap_t **blkmapp, xfs_fileoff_t *first_key, xfs_fileoff_t *last_key, int check_dups, int whichfork) { xfs_bmbt_irec_t irec; xfs_filblks_t cp = 0; /* prev count */ xfs_fsblock_t sp = 0; /* prev start */ xfs_fileoff_t op = 0; /* prev offset */ xfs_fsblock_t b; char *ftype; char *forkname = get_forkname(whichfork); int i; int state; xfs_agnumber_t agno; xfs_agblock_t agbno; xfs_agblock_t ebno; xfs_extlen_t blen; xfs_agnumber_t locked_agno = -1; int error = 1; if (type == XR_INO_RTDATA) ftype = ftype_real_time; else ftype = ftype_regular; for (i = 0; i < *numrecs; i++) { libxfs_bmbt_disk_get_all((rp +i), &irec); if (i == 0) *last_key = *first_key = irec.br_startoff; else *last_key = irec.br_startoff; if (i > 0 && op + cp > irec.br_startoff) { do_warn( _("bmap rec out of order, inode %" PRIu64" entry %d " "[o s c] [%" PRIu64 " %" PRIu64 " %" PRIu64 "], " "%d [%" PRIu64 " %" PRIu64 " %" PRIu64 "]\n"), ino, i, irec.br_startoff, irec.br_startblock, irec.br_blockcount, i - 1, op, sp, cp); goto done; } op = irec.br_startoff; cp = irec.br_blockcount; sp = irec.br_startblock; /* * check numeric validity of the extent */ if (irec.br_blockcount == 0) { do_warn( _("zero length extent (off = %" PRIu64 ", fsbno = %" PRIu64 ") in ino %" PRIu64 "\n"), irec.br_startoff, irec.br_startblock, ino); goto done; } if (type == XR_INO_RTDATA && whichfork == XFS_DATA_FORK) { /* * realtime bitmaps don't use AG locks, so returning * immediately is fine for this code path. */ if (process_rt_rec(mp, &irec, ino, tot, check_dups)) return 1; /* * skip rest of loop processing since that'irec.br_startblock * all for regular file forks and attr forks */ continue; } /* * regular file data fork or attribute fork */ switch (verify_dfsbno_range(mp, irec.br_startblock, irec.br_blockcount)) { case XR_DFSBNORANGE_VALID: break; case XR_DFSBNORANGE_BADSTART: do_warn( _("inode %" PRIu64 " - bad extent starting block number %" PRIu64 ", offset %" PRIu64 "\n"), ino, irec.br_startblock, irec.br_startoff); goto done; case XR_DFSBNORANGE_BADEND: do_warn( _("inode %" PRIu64 " - bad extent last block number %" PRIu64 ", offset %" PRIu64 "\n"), ino, irec.br_startblock + irec.br_blockcount - 1, irec.br_startoff); goto done; case XR_DFSBNORANGE_OVERFLOW: do_warn( _("inode %" PRIu64 " - bad extent overflows - start %" PRIu64 ", " "end %" PRIu64 ", offset %" PRIu64 "\n"), ino, irec.br_startblock, irec.br_startblock + irec.br_blockcount - 1, irec.br_startoff); goto done; } /* Ensure this extent does not extend beyond the max offset */ if (irec.br_startoff + irec.br_blockcount - 1 > fs_max_file_offset) { do_warn( _("inode %" PRIu64 " - extent exceeds max offset - start %" PRIu64 ", " "count %" PRIu64 ", physical block %" PRIu64 "\n"), ino, irec.br_startoff, irec.br_blockcount, irec.br_startblock); goto done; } if (blkmapp && *blkmapp) { int error2; error2 = blkmap_set_ext(blkmapp, irec.br_startoff, irec.br_startblock, irec.br_blockcount); if (error2) { /* * we don't want to clear the inode due to an * internal bmap tracking error, but if we've * run out of memory then we simply can't * validate that the filesystem is consistent. * Hence just abort at this point with an ENOMEM * error. */ do_abort( _("Fatal error: inode %" PRIu64 " - blkmap_set_ext(): %s\n" "\t%s fork, off - %" PRIu64 ", start - %" PRIu64 ", cnt %" PRIu64 "\n"), ino, strerror(error2), forkname, irec.br_startoff, irec.br_startblock, irec.br_blockcount); } } /* * Profiling shows that the following loop takes the * most time in all of xfs_repair. */ agno = XFS_FSB_TO_AGNO(mp, irec.br_startblock); agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock); ebno = agbno + irec.br_blockcount; if (agno != locked_agno) { if (locked_agno != -1) pthread_mutex_unlock(&ag_locks[locked_agno].lock); pthread_mutex_lock(&ag_locks[agno].lock); locked_agno = agno; } if (check_dups) { /* * if we're just checking the bmap for dups, * return if we find one, otherwise, continue * checking each entry without setting the * block bitmap */ if (!(type == XR_INO_DATA && xfs_sb_version_hasreflink(&mp->m_sb)) && search_dup_extent(agno, agbno, ebno)) { do_warn( _("%s fork in ino %" PRIu64 " claims dup extent, " "off - %" PRIu64 ", start - %" PRIu64 ", cnt %" PRIu64 "\n"), forkname, ino, irec.br_startoff, irec.br_startblock, irec.br_blockcount); goto done; } *tot += irec.br_blockcount; continue; } for (b = irec.br_startblock; agbno < ebno; b += blen, agbno += blen) { state = get_bmap_ext(agno, agbno, ebno, &blen); switch (state) { case XR_E_FREE: case XR_E_FREE1: do_warn( _("%s fork in ino %" PRIu64 " claims free block %" PRIu64 "\n"), forkname, ino, (uint64_t) b); /* fall through ... */ case XR_E_INUSE1: /* seen by rmap */ case XR_E_UNKNOWN: break; case XR_E_BAD_STATE: do_error(_("bad state in block map %" PRIu64 "\n"), b); case XR_E_FS_MAP1: case XR_E_INO1: case XR_E_INUSE_FS1: do_warn(_("rmap claims metadata use!\n")); /* fall through */ case XR_E_FS_MAP: case XR_E_INO: case XR_E_INUSE_FS: case XR_E_REFC: do_warn( _("%s fork in inode %" PRIu64 " claims metadata block %" PRIu64 "\n"), forkname, ino, b); goto done; case XR_E_INUSE: case XR_E_MULT: if (type == XR_INO_DATA && xfs_sb_version_hasreflink(&mp->m_sb)) break; do_warn( _("%s fork in %s inode %" PRIu64 " claims used block %" PRIu64 "\n"), forkname, ftype, ino, b); goto done; case XR_E_COW: do_warn( _("%s fork in %s inode %" PRIu64 " claims CoW block %" PRIu64 "\n"), forkname, ftype, ino, b); goto done; default: do_error( _("illegal state %d in block map %" PRIu64 "\n"), state, b); goto done; } } /* * Update the internal extent map only after we've checked * every block in this extent. The first time we reject this * data fork we'll try to rebuild the bmbt from rmap data. * After a successful rebuild we'll try this scan again. * (If the rebuild fails we won't come back here.) */ agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock); ebno = agbno + irec.br_blockcount; for (; agbno < ebno; agbno += blen) { state = get_bmap_ext(agno, agbno, ebno, &blen); switch (state) { case XR_E_FREE: case XR_E_FREE1: case XR_E_INUSE1: case XR_E_UNKNOWN: set_bmap_ext(agno, agbno, blen, XR_E_INUSE); break; case XR_E_INUSE: case XR_E_MULT: set_bmap_ext(agno, agbno, blen, XR_E_MULT); break; default: break; } } if (collect_rmaps) { /* && !check_dups */ error = rmap_add_rec(mp, ino, whichfork, &irec); if (error) do_error( _("couldn't add reverse mapping\n") ); } *tot += irec.br_blockcount; } error = 0; done: if (locked_agno != -1) pthread_mutex_unlock(&ag_locks[locked_agno].lock); if (i != *numrecs) { ASSERT(i < *numrecs); do_warn(_("correcting nextents for inode %" PRIu64 "\n"), ino); *numrecs = i; } return error; } /* * return 1 if inode should be cleared, 0 otherwise, sets block bitmap * as a side-effect */ int process_bmbt_reclist( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, int *numrecs, int type, xfs_ino_t ino, xfs_rfsblock_t *tot, blkmap_t **blkmapp, xfs_fileoff_t *first_key, xfs_fileoff_t *last_key, int whichfork) { return process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot, blkmapp, first_key, last_key, 0, whichfork); } /* * return 1 if inode should be cleared, 0 otherwise, does not set * block bitmap */ int scan_bmbt_reclist( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, int *numrecs, int type, xfs_ino_t ino, xfs_rfsblock_t *tot, int whichfork) { xfs_fileoff_t first_key = 0; xfs_fileoff_t last_key = 0; return process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot, NULL, &first_key, &last_key, 1, whichfork); } /* * Grab the buffer backing an inode. This is meant for routines that * work with inodes one at a time in any order (like walking the * unlinked lists to look for inodes). The caller is responsible for * writing/releasing the buffer. */ struct xfs_buf * get_agino_buf( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino, struct xfs_dinode **dipp) { struct xfs_buf *bp; xfs_agino_t cluster_agino; xfs_daddr_t cluster_daddr; xfs_daddr_t cluster_blks; struct xfs_ino_geometry *igeo = M_IGEO(mp); /* * Inode buffers have been read into memory in inode_cluster_size * chunks (or one FSB). To find the correct buffer for an inode, * we must find the buffer for its cluster, add the appropriate * offset, and return that. */ cluster_agino = agino & ~(igeo->inodes_per_cluster - 1); cluster_blks = XFS_FSB_TO_DADDR(mp, igeo->blocks_per_cluster); cluster_daddr = XFS_AGB_TO_DADDR(mp, agno, XFS_AGINO_TO_AGBNO(mp, cluster_agino)); #ifdef XR_INODE_TRACE printf("cluster_size %d ipc %d clusagino %d daddr %lld sectors %lld\n", M_IGEO(mp)->inode_cluster_size, M_IGEO(mp)->inodes_per_cluster, cluster_agino, cluster_daddr, cluster_blks); #endif bp = libxfs_readbuf(mp->m_dev, cluster_daddr, cluster_blks, 0, &xfs_inode_buf_ops); if (!bp) { do_warn(_("cannot read inode (%u/%u), disk block %" PRIu64 "\n"), agno, cluster_agino, cluster_daddr); return NULL; } *dipp = xfs_make_iptr(mp, bp, agino - cluster_agino); ASSERT(!xfs_sb_version_hascrc(&mp->m_sb) || XFS_AGINO_TO_INO(mp, agno, agino) == be64_to_cpu((*dipp)->di_ino)); return bp; } /* * higher level inode processing stuff starts here: * first, one utility routine for each type of inode */ /* * return 1 if inode should be cleared, 0 otherwise */ static int process_btinode( xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t ino, xfs_dinode_t *dip, int type, int *dirty, xfs_rfsblock_t *tot, uint64_t *nex, blkmap_t **blkmapp, int whichfork, int check_dups) { xfs_bmdr_block_t *dib; xfs_fileoff_t last_key; xfs_fileoff_t first_key = 0; xfs_ino_t lino; xfs_bmbt_ptr_t *pp; xfs_bmbt_key_t *pkey; char *forkname = get_forkname(whichfork); int i; int level; int numrecs; bmap_cursor_t cursor; uint64_t magic; dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); lino = XFS_AGINO_TO_INO(mp, agno, ino); *tot = 0; *nex = 0; magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_BMAP_CRC_MAGIC : XFS_BMAP_MAGIC; level = be16_to_cpu(dib->bb_level); numrecs = be16_to_cpu(dib->bb_numrecs); if ((level == 0) || (level > XFS_BM_MAXLEVELS(mp, whichfork))) { /* * XXX - if we were going to fix up the inode, * we'd try to treat the fork as an interior * node and see if we could get an accurate * level value from one of the blocks pointed * to by the pointers in the fork. For now * though, we just bail (and blow out the inode). */ do_warn( _("bad level %d in inode %" PRIu64 " bmap btree root block\n"), level, XFS_AGINO_TO_INO(mp, agno, ino)); return(1); } if (numrecs == 0) { do_warn( _("bad numrecs 0 in inode %" PRIu64 " bmap btree root block\n"), XFS_AGINO_TO_INO(mp, agno, ino)); return(1); } /* * use bmdr/dfork_dsize since the root block is in the data fork */ if (XFS_BMDR_SPACE_CALC(numrecs) > XFS_DFORK_SIZE(dip, mp, whichfork)) { do_warn( _("indicated size of %s btree root (%d bytes) greater than space in " "inode %" PRIu64 " %s fork\n"), forkname, XFS_BMDR_SPACE_CALC(numrecs), lino, forkname); return(1); } init_bm_cursor(&cursor, level + 1); pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0)); pkey = XFS_BMDR_KEY_ADDR(dib, 1); last_key = NULLFILEOFF; for (i = 0; i < numrecs; i++) { /* * XXX - if we were going to do more to fix up the inode * btree, we'd do it right here. For now, if there's a * problem, we'll bail out and presumably clear the inode. */ if (!verify_dfsbno(mp, get_unaligned_be64(&pp[i]))) { do_warn( _("bad bmap btree ptr 0x%" PRIx64 " in ino %" PRIu64 "\n"), get_unaligned_be64(&pp[i]), lino); return(1); } if (scan_lbtree(get_unaligned_be64(&pp[i]), level, scan_bmapbt, type, whichfork, lino, tot, nex, blkmapp, &cursor, 1, check_dups, magic, &xfs_bmbt_buf_ops)) return(1); /* * fix key (offset) mismatches between the keys in root * block records and the first key of each child block. * fixes cases where entries have been shifted between * blocks but the parent hasn't been updated */ if (!check_dups && cursor.level[level-1].first_key != get_unaligned_be64(&pkey[i].br_startoff)) { if (!no_modify) { do_warn( _("correcting key in bmbt root (was %" PRIu64 ", now %" PRIu64") in inode " "%" PRIu64" %s fork\n"), get_unaligned_be64(&pkey[i].br_startoff), cursor.level[level-1].first_key, XFS_AGINO_TO_INO(mp, agno, ino), forkname); *dirty = 1; put_unaligned_be64( cursor.level[level-1].first_key, &pkey[i].br_startoff); } else { do_warn( _("bad key in bmbt root (is %" PRIu64 ", would reset to %" PRIu64 ") in inode " "%" PRIu64 " %s fork\n"), get_unaligned_be64(&pkey[i].br_startoff), cursor.level[level-1].first_key, XFS_AGINO_TO_INO(mp, agno, ino), forkname); } } /* * make sure that keys are in ascending order. blow out * inode if the ordering doesn't hold */ if (check_dups == 0) { if (last_key != NULLFILEOFF && last_key >= cursor.level[level-1].first_key) { do_warn( _("out of order bmbt root key %" PRIu64 " in inode %" PRIu64 " %s fork\n"), first_key, XFS_AGINO_TO_INO(mp, agno, ino), forkname); return(1); } last_key = cursor.level[level-1].first_key; } } /* * Ideally if all the extents are ok (perhaps after further * checks below?) we'd just move this back into extents format. * But for now clear it, as the kernel will choke on this */ if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) { do_warn( _("extent count for ino %" PRIu64 " %s fork too low (%" PRIu64 ") for file format\n"), lino, forkname, *nex); return(1); } /* * Check that the last child block's forward sibling pointer * is NULL. */ if (check_dups == 0 && cursor.level[0].right_fsbno != NULLFSBLOCK) { do_warn( _("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLFSBLOCK)\n"), cursor.level[0].right_fsbno); do_warn( _("\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"), XFS_AGINO_TO_INO(mp, agno, ino), forkname, cursor.level[0].fsbno); return(1); } return(0); } /* * return 1 if inode should be cleared, 0 otherwise */ static int process_exinode( xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t ino, xfs_dinode_t *dip, int type, int *dirty, xfs_rfsblock_t *tot, uint64_t *nex, blkmap_t **blkmapp, int whichfork, int check_dups) { xfs_ino_t lino; xfs_bmbt_rec_t *rp; xfs_fileoff_t first_key; xfs_fileoff_t last_key; int32_t numrecs; int ret; lino = XFS_AGINO_TO_INO(mp, agno, ino); rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork); *tot = 0; numrecs = XFS_DFORK_NEXTENTS(dip, whichfork); /* * We've already decided on the maximum number of extents on the inode, * and numrecs may be corrupt. Hence make sure we only allow numrecs to * be in the range of valid on-disk numbers, which is: * 0 < numrecs < 2^31 - 1 */ if (numrecs < 0) numrecs = *nex; /* * XXX - if we were going to fix up the btree record, * we'd do it right here. For now, if there's a problem, * we'll bail out and presumably clear the inode. */ if (check_dups == 0) ret = process_bmbt_reclist(mp, rp, &numrecs, type, lino, tot, blkmapp, &first_key, &last_key, whichfork); else ret = scan_bmbt_reclist(mp, rp, &numrecs, type, lino, tot, whichfork); *nex = numrecs; return ret; } /* * return 1 if inode should be cleared, 0 otherwise */ static int process_lclinode( xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t ino, xfs_dinode_t *dip, int whichfork) { xfs_attr_shortform_t *asf; xfs_ino_t lino; lino = XFS_AGINO_TO_INO(mp, agno, ino); if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) > XFS_DFORK_DSIZE(dip, mp)) { do_warn( _("local inode %" PRIu64 " data fork is too large (size = %lld, max = %d)\n"), lino, (unsigned long long) be64_to_cpu(dip->di_size), XFS_DFORK_DSIZE(dip, mp)); return(1); } else if (whichfork == XFS_ATTR_FORK) { asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); if (be16_to_cpu(asf->hdr.totsize) > XFS_DFORK_ASIZE(dip, mp)) { do_warn( _("local inode %" PRIu64 " attr fork too large (size %d, max = %d)\n"), lino, be16_to_cpu(asf->hdr.totsize), XFS_DFORK_ASIZE(dip, mp)); return(1); } if (be16_to_cpu(asf->hdr.totsize) < sizeof(xfs_attr_sf_hdr_t)) { do_warn( _("local inode %" PRIu64 " attr too small (size = %d, min size = %zd)\n"), lino, be16_to_cpu(asf->hdr.totsize), sizeof(xfs_attr_sf_hdr_t)); return(1); } } return(0); } static int process_symlink_extlist(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino) { xfs_fileoff_t expected_offset; xfs_bmbt_rec_t *rp; xfs_bmbt_irec_t irec; int numrecs; int i; int max_blocks; if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp)) { if (dino->di_format == XFS_DINODE_FMT_LOCAL) return 0; do_warn( _("mismatch between format (%d) and size (%" PRId64 ") in symlink ino %" PRIu64 "\n"), dino->di_format, (int64_t)be64_to_cpu(dino->di_size), lino); return 1; } if (dino->di_format == XFS_DINODE_FMT_LOCAL) { do_warn( _("mismatch between format (%d) and size (%" PRId64 ") in symlink inode %" PRIu64 "\n"), dino->di_format, (int64_t)be64_to_cpu(dino->di_size), lino); return 1; } rp = (xfs_bmbt_rec_t *)XFS_DFORK_DPTR(dino); numrecs = be32_to_cpu(dino->di_nextents); /* * the max # of extents in a symlink inode is equal to the * number of max # of blocks required to store the symlink */ if (numrecs > max_symlink_blocks) { do_warn( _("bad number of extents (%d) in symlink %" PRIu64 " data fork\n"), numrecs, lino); return(1); } max_blocks = max_symlink_blocks; expected_offset = 0; for (i = 0; i < numrecs; i++) { libxfs_bmbt_disk_get_all((rp +i), &irec); if (irec.br_startoff != expected_offset) { do_warn( _("bad extent #%d offset (%" PRIu64 ") in symlink %" PRIu64 " data fork\n"), i, irec.br_startoff, lino); return(1); } if (irec.br_blockcount == 0 || irec.br_blockcount > max_blocks) { do_warn( _("bad extent #%d count (%" PRIu64 ") in symlink %" PRIu64 " data fork\n"), i, irec.br_blockcount, lino); return(1); } max_blocks -= irec.br_blockcount; expected_offset += irec.br_blockcount; } return(0); } /* * takes a name and length and returns 1 if the name contains * a \0, returns 0 otherwise */ static int null_check(char *name, int length) { int i; ASSERT(length < XFS_SYMLINK_MAXLEN); for (i = 0; i < length; i++, name++) { if (*name == '\0') return(1); } return(0); } /* * This does /not/ do quotacheck, it validates the basic quota * inode metadata, checksums, etc. */ #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) static int process_quota_inode( struct xfs_mount *mp, xfs_ino_t lino, struct xfs_dinode *dino, uint ino_type, struct blkmap *blkmap) { xfs_fsblock_t fsbno; struct xfs_buf *bp; xfs_filblks_t dqchunklen; uint dqperchunk; int quota_type = 0; char *quota_string = NULL; xfs_dqid_t dqid; xfs_fileoff_t qbno; int i; int t = 0; switch (ino_type) { case XR_INO_UQUOTA: quota_type = XFS_DQ_USER; quota_string = _("User quota"); break; case XR_INO_GQUOTA: quota_type = XFS_DQ_GROUP; quota_string = _("Group quota"); break; case XR_INO_PQUOTA: quota_type = XFS_DQ_PROJ; quota_string = _("Project quota"); break; default: ASSERT(0); } dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); dqperchunk = libxfs_calc_dquots_per_chunk(dqchunklen); dqid = 0; qbno = NULLFILEOFF; while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) { xfs_dqblk_t *dqb; int writebuf = 0; fsbno = blkmap_get(blkmap, qbno); dqid = (xfs_dqid_t)qbno * dqperchunk; bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), dqchunklen, 0, &xfs_dquot_buf_ops); if (!bp) { do_warn( _("cannot read inode %" PRIu64 ", file block %" PRIu64 ", disk block %" PRIu64 "\n"), lino, qbno, fsbno); return 1; } dqb = bp->b_addr; for (i = 0; i < dqperchunk; i++, dqid++, dqb++) { int bad_dqb = 0; /* We only print the first problem we find */ if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!libxfs_verify_cksum((char *)dqb, sizeof(*dqb), XFS_DQUOT_CRC_OFF)) { do_warn(_("%s: bad CRC for id %u. "), quota_string, dqid); bad_dqb = 1; goto bad; } if (!uuid_equal(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid)) { do_warn(_("%s: bad UUID for id %u. "), quota_string, dqid); bad_dqb = 1; goto bad; } } if (libxfs_dquot_verify(mp, &dqb->dd_diskdq, dqid, quota_type) != NULL) { do_warn(_("%s: Corrupt quota for id %u. "), quota_string, dqid); bad_dqb = 1; } bad: if (bad_dqb) { if (no_modify) do_warn(_("Would correct.\n")); else { do_warn(_("Corrected.\n")); libxfs_dqblk_repair(mp, dqb, dqid, quota_type); writebuf = 1; } } } if (writebuf && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); } return 0; } static int process_symlink_remote( struct xfs_mount *mp, xfs_ino_t lino, struct xfs_dinode *dino, struct blkmap *blkmap, char *dst) { xfs_fsblock_t fsbno; struct xfs_buf *bp; char *src; int pathlen; int offset; int i; offset = 0; pathlen = be64_to_cpu(dino->di_size); i = 0; while (pathlen > 0) { int blk_cnt = 1; int byte_cnt; int badcrc = 0; fsbno = blkmap_get(blkmap, i); if (fsbno == NULLFSBLOCK) { do_warn( _("cannot read inode %" PRIu64 ", file block %d, NULL disk block\n"), lino, i); return 1; } /* * There's a symlink header for each contiguous extent. If * there are contiguous blocks, read them in one go. */ while (blk_cnt <= max_symlink_blocks) { if (blkmap_get(blkmap, i + 1) != fsbno + 1) break; blk_cnt++; i++; } byte_cnt = XFS_FSB_TO_B(mp, blk_cnt); bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), BTOBB(byte_cnt), 0, &xfs_symlink_buf_ops); if (!bp) { do_warn( _("cannot read inode %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), lino, i, fsbno); return 1; } if (bp->b_error == -EFSCORRUPTED) { do_warn( _("Corrupt symlink remote block %" PRIu64 ", inode %" PRIu64 ".\n"), fsbno, lino); libxfs_putbuf(bp); return 1; } if (bp->b_error == -EFSBADCRC) { do_warn( _("Bad symlink buffer CRC, block %" PRIu64 ", inode %" PRIu64 ".\n" "Correcting CRC, but symlink may be bad.\n"), fsbno, lino); badcrc = 1; } byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); byte_cnt = min(pathlen, byte_cnt); src = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!libxfs_symlink_hdr_ok(lino, offset, byte_cnt, bp)) { do_warn( _("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), lino, i, fsbno); libxfs_putbuf(bp); return 1; } src += sizeof(struct xfs_dsymlink_hdr); } memmove(dst + offset, src, byte_cnt); pathlen -= byte_cnt; offset += byte_cnt; i++; if (badcrc && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); } return 0; } /* * like usual, returns 0 if everything's ok and 1 if something's * bogus */ static int process_symlink( xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino, blkmap_t *blkmap) { char *symlink; char data[XFS_SYMLINK_MAXLEN]; /* * check size against kernel symlink limits. we know * size is consistent with inode storage format -- e.g. * the inode is structurally ok so we don't have to check * for that */ if (be64_to_cpu(dino->di_size) >= XFS_SYMLINK_MAXLEN) { do_warn(_("symlink in inode %" PRIu64 " too long (%llu chars)\n"), lino, (unsigned long long) be64_to_cpu(dino->di_size)); return(1); } if (be64_to_cpu(dino->di_size) == 0) { do_warn(_("zero size symlink in inode %" PRIu64 "\n"), lino); return 1; } /* * have to check symlink component by component. * get symlink contents into data area */ symlink = &data[0]; if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp)) { /* * local symlink, just copy the symlink out of the * inode into the data area */ memmove(symlink, XFS_DFORK_DPTR(dino), be64_to_cpu(dino->di_size)); } else { int error; error = process_symlink_remote(mp, lino, dino, blkmap, symlink); if (error) return error; } data[be64_to_cpu(dino->di_size)] = '\0'; /* * check for nulls */ if (null_check(symlink, be64_to_cpu(dino->di_size))) { do_warn( _("found illegal null character in symlink inode %" PRIu64 "\n"), lino); return(1); } return(0); } /* * called to process the set of misc inode special inode types * that have no associated data storage (fifos, pipes, devices, etc.). */ static int process_misc_ino_types(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t lino, int type) { /* * disallow mountpoint inodes until such time as the * kernel actually allows them to be created (will * probably require a superblock version rev, sigh). */ if (type == XR_INO_MOUNTPOINT) { do_warn( _("inode %" PRIu64 " has bad inode type (IFMNT)\n"), lino); return(1); } /* * must also have a zero size */ if (be64_to_cpu(dino->di_size) != 0) { switch (type) { case XR_INO_CHRDEV: do_warn( _("size of character device inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, (int64_t)be64_to_cpu(dino->di_size)); break; case XR_INO_BLKDEV: do_warn( _("size of block device inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, (int64_t)be64_to_cpu(dino->di_size)); break; case XR_INO_SOCK: do_warn( _("size of socket inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, (int64_t)be64_to_cpu(dino->di_size)); break; case XR_INO_FIFO: do_warn( _("size of fifo inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, (int64_t)be64_to_cpu(dino->di_size)); break; case XR_INO_UQUOTA: case XR_INO_GQUOTA: case XR_INO_PQUOTA: do_warn( _("size of quota inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, (int64_t)be64_to_cpu(dino->di_size)); break; default: do_warn(_("Internal error - process_misc_ino_types, " "illegal type %d\n"), type); abort(); } return(1); } return(0); } static int process_misc_ino_types_blocks(xfs_rfsblock_t totblocks, xfs_ino_t lino, int type) { /* * you can not enforce all misc types have zero data fork blocks * by checking dino->di_nblocks because atotblocks (attribute * blocks) are part of nblocks. We must check this later when atotblocks * has been calculated or by doing a simple check that anExtents == 0. * We must also guarantee that totblocks is 0. Thus nblocks checking * will be done later in process_dinode_int for misc types. */ if (totblocks != 0) { switch (type) { case XR_INO_CHRDEV: do_warn( _("size of character device inode %" PRIu64 " != 0 (%" PRIu64 " blocks)\n"), lino, totblocks); break; case XR_INO_BLKDEV: do_warn( _("size of block device inode %" PRIu64 " != 0 (%" PRIu64 " blocks)\n"), lino, totblocks); break; case XR_INO_SOCK: do_warn( _("size of socket inode %" PRIu64 " != 0 (%" PRIu64 " blocks)\n"), lino, totblocks); break; case XR_INO_FIFO: do_warn( _("size of fifo inode %" PRIu64 " != 0 (%" PRIu64 " blocks)\n"), lino, totblocks); break; default: return(0); } return(1); } return (0); } static inline int dinode_fmt( xfs_dinode_t *dino) { return be16_to_cpu(dino->di_mode) & S_IFMT; } static inline void change_dinode_fmt( xfs_dinode_t *dino, int new_fmt) { int mode = be16_to_cpu(dino->di_mode); ASSERT((new_fmt & ~S_IFMT) == 0); mode &= ~S_IFMT; mode |= new_fmt; dino->di_mode = cpu_to_be16(mode); } static int check_dinode_mode_format( xfs_dinode_t *dinoc) { if (dinoc->di_format >= XFS_DINODE_FMT_UUID) return -1; /* FMT_UUID is not used */ switch (dinode_fmt(dinoc)) { case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: return (dinoc->di_format != XFS_DINODE_FMT_DEV) ? -1 : 0; case S_IFDIR: return (dinoc->di_format < XFS_DINODE_FMT_LOCAL || dinoc->di_format > XFS_DINODE_FMT_BTREE) ? -1 : 0; case S_IFREG: return (dinoc->di_format < XFS_DINODE_FMT_EXTENTS || dinoc->di_format > XFS_DINODE_FMT_BTREE) ? -1 : 0; case S_IFLNK: return (dinoc->di_format < XFS_DINODE_FMT_LOCAL || dinoc->di_format > XFS_DINODE_FMT_EXTENTS) ? -1 : 0; default: ; } return 0; /* invalid modes are checked elsewhere */ } /* * If inode is a superblock inode, does type check to make sure is it valid. * Returns 0 if it's valid, non-zero if it needs to be cleared. */ static int process_check_sb_inodes( xfs_mount_t *mp, xfs_dinode_t *dinoc, xfs_ino_t lino, int *type, int *dirty) { if (lino == mp->m_sb.sb_rootino) { if (*type != XR_INO_DIR) { do_warn(_("root inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); *type = XR_INO_DIR; if (!no_modify) { do_warn(_("resetting to directory\n")); change_dinode_fmt(dinoc, S_IFDIR); *dirty = 1; } else do_warn(_("would reset to directory\n")); } return 0; } if (lino == mp->m_sb.sb_uquotino) { if (*type != XR_INO_UQUOTA) { do_warn(_("user quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); mp->m_sb.sb_uquotino = NULLFSINO; return 1; } return 0; } if (lino == mp->m_sb.sb_gquotino) { if (*type != XR_INO_GQUOTA) { do_warn(_("group quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); mp->m_sb.sb_gquotino = NULLFSINO; return 1; } return 0; } if (lino == mp->m_sb.sb_pquotino) { if (*type != XR_INO_PQUOTA) { do_warn(_("project quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); mp->m_sb.sb_pquotino = NULLFSINO; return 1; } return 0; } if (lino == mp->m_sb.sb_rsumino) { if (*type != XR_INO_RTSUM) { do_warn( _("realtime summary inode %" PRIu64 " has bad type 0x%x, "), lino, dinode_fmt(dinoc)); if (!no_modify) { do_warn(_("resetting to regular file\n")); change_dinode_fmt(dinoc, S_IFREG); *dirty = 1; } else { do_warn(_("would reset to regular file\n")); } } if (mp->m_sb.sb_rblocks == 0 && dinoc->di_nextents != 0) { do_warn( _("bad # of extents (%u) for realtime summary inode %" PRIu64 "\n"), be32_to_cpu(dinoc->di_nextents), lino); return 1; } return 0; } if (lino == mp->m_sb.sb_rbmino) { if (*type != XR_INO_RTBITMAP) { do_warn( _("realtime bitmap inode %" PRIu64 " has bad type 0x%x, "), lino, dinode_fmt(dinoc)); if (!no_modify) { do_warn(_("resetting to regular file\n")); change_dinode_fmt(dinoc, S_IFREG); *dirty = 1; } else { do_warn(_("would reset to regular file\n")); } } if (mp->m_sb.sb_rblocks == 0 && dinoc->di_nextents != 0) { do_warn( _("bad # of extents (%u) for realtime bitmap inode %" PRIu64 "\n"), be32_to_cpu(dinoc->di_nextents), lino); return 1; } return 0; } return 0; } /* * general size/consistency checks: * * if the size <= size of the data fork, directories must be * local inodes unlike regular files which would be extent inodes. * all the other mentioned types have to have a zero size value. * * if the size and format don't match, get out now rather than * risk trying to process a non-existent extents or btree * type data fork. */ static int process_check_inode_sizes( xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t lino, int type) { xfs_fsize_t size = be64_to_cpu(dino->di_size); switch (type) { case XR_INO_DIR: if (size <= XFS_DFORK_DSIZE(dino, mp) && dino->di_format != XFS_DINODE_FMT_LOCAL) { do_warn( _("mismatch between format (%d) and size (%" PRId64 ") in directory ino %" PRIu64 "\n"), dino->di_format, size, lino); return 1; } if (size > XFS_DIR2_LEAF_OFFSET) { do_warn( _("directory inode %" PRIu64 " has bad size %" PRId64 "\n"), lino, size); return 1; } break; case XR_INO_SYMLINK: if (process_symlink_extlist(mp, lino, dino)) { do_warn(_("bad data fork in symlink %" PRIu64 "\n"), lino); return 1; } break; case XR_INO_CHRDEV: /* fall through to FIFO case ... */ case XR_INO_BLKDEV: /* fall through to FIFO case ... */ case XR_INO_SOCK: /* fall through to FIFO case ... */ case XR_INO_MOUNTPOINT: /* fall through to FIFO case ... */ case XR_INO_FIFO: if (process_misc_ino_types(mp, dino, lino, type)) return 1; break; case XR_INO_UQUOTA: case XR_INO_GQUOTA: case XR_INO_PQUOTA: /* Quota inodes have same restrictions as above types */ if (process_misc_ino_types(mp, dino, lino, type)) return 1; break; case XR_INO_RTDATA: /* * if we have no realtime blocks, any inode claiming * to be a real-time file is bogus */ if (mp->m_sb.sb_rblocks == 0) { do_warn( _("found inode %" PRIu64 " claiming to be a real-time file\n"), lino); return 1; } break; case XR_INO_RTBITMAP: if (size != (int64_t)mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize) { do_warn( _("realtime bitmap inode %" PRIu64 " has bad size %" PRId64 " (should be %" PRIu64 ")\n"), lino, size, (int64_t) mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize); return 1; } break; case XR_INO_RTSUM: if (size != mp->m_rsumsize) { do_warn( _("realtime summary inode %" PRIu64 " has bad size %" PRId64 " (should be %d)\n"), lino, size, mp->m_rsumsize); return 1; } break; default: break; } return 0; } /* * check for illegal values of forkoff */ static int process_check_inode_forkoff( xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t lino) { if (dino->di_forkoff == 0) return 0; switch (dino->di_format) { case XFS_DINODE_FMT_DEV: if (dino->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3)) { do_warn( _("bad attr fork offset %d in dev inode %" PRIu64 ", should be %d\n"), dino->di_forkoff, lino, (int)(roundup(sizeof(xfs_dev_t), 8) >> 3)); return 1; } break; case XFS_DINODE_FMT_LOCAL: /* fall through ... */ case XFS_DINODE_FMT_EXTENTS: /* fall through ... */ case XFS_DINODE_FMT_BTREE: if (dino->di_forkoff >= (XFS_LITINO(mp, dino->di_version) >> 3)) { do_warn( _("bad attr fork offset %d in inode %" PRIu64 ", max=%d\n"), dino->di_forkoff, lino, XFS_LITINO(mp, dino->di_version) >> 3); return 1; } break; default: do_error(_("unexpected inode format %d\n"), dino->di_format); break; } return 0; } /* * Updates the inodes block and extent counts if they are wrong */ static int process_inode_blocks_and_extents( xfs_dinode_t *dino, xfs_rfsblock_t nblocks, uint64_t nextents, uint64_t anextents, xfs_ino_t lino, int *dirty) { if (nblocks != be64_to_cpu(dino->di_nblocks)) { if (!no_modify) { do_warn( _("correcting nblocks for inode %" PRIu64 ", was %llu - counted %" PRIu64 "\n"), lino, (unsigned long long) be64_to_cpu(dino->di_nblocks), nblocks); dino->di_nblocks = cpu_to_be64(nblocks); *dirty = 1; } else { do_warn( _("bad nblocks %llu for inode %" PRIu64 ", would reset to %" PRIu64 "\n"), (unsigned long long) be64_to_cpu(dino->di_nblocks), lino, nblocks); } } if (nextents > MAXEXTNUM) { do_warn( _("too many data fork extents (%" PRIu64 ") in inode %" PRIu64 "\n"), nextents, lino); return 1; } if (nextents != be32_to_cpu(dino->di_nextents)) { if (!no_modify) { do_warn( _("correcting nextents for inode %" PRIu64 ", was %d - counted %" PRIu64 "\n"), lino, be32_to_cpu(dino->di_nextents), nextents); dino->di_nextents = cpu_to_be32(nextents); *dirty = 1; } else { do_warn( _("bad nextents %d for inode %" PRIu64 ", would reset to %" PRIu64 "\n"), be32_to_cpu(dino->di_nextents), lino, nextents); } } if (anextents > MAXAEXTNUM) { do_warn( _("too many attr fork extents (%" PRIu64 ") in inode %" PRIu64 "\n"), anextents, lino); return 1; } if (anextents != be16_to_cpu(dino->di_anextents)) { if (!no_modify) { do_warn( _("correcting anextents for inode %" PRIu64 ", was %d - counted %" PRIu64 "\n"), lino, be16_to_cpu(dino->di_anextents), anextents); dino->di_anextents = cpu_to_be16(anextents); *dirty = 1; } else { do_warn( _("bad anextents %d for inode %" PRIu64 ", would reset to %" PRIu64 "\n"), be16_to_cpu(dino->di_anextents), lino, anextents); } } /* * We are comparing different units here, but that's fine given that * an extent has to have at least a block in it. */ if (nblocks < nextents + anextents) { do_warn( _("nblocks (%" PRIu64 ") smaller than nextents for inode %" PRIu64 "\n"), nblocks, lino); return 1; } return 0; } /* * check data fork -- if it's bad, clear the inode */ static int process_inode_data_fork( xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t ino, xfs_dinode_t *dino, int type, int *dirty, xfs_rfsblock_t *totblocks, uint64_t *nextents, blkmap_t **dblkmap, int check_dups) { xfs_ino_t lino = XFS_AGINO_TO_INO(mp, agno, ino); int err = 0; int nex; /* * extent count on disk is only valid for positive values. The kernel * uses negative values in memory. hence if we see negative numbers * here, trash it! */ nex = be32_to_cpu(dino->di_nextents); if (nex < 0) *nextents = 1; else *nextents = nex; if (*nextents > be64_to_cpu(dino->di_nblocks)) *nextents = 1; if (dino->di_format != XFS_DINODE_FMT_LOCAL && type != XR_INO_RTDATA) *dblkmap = blkmap_alloc(*nextents, XFS_DATA_FORK); *nextents = 0; switch (dino->di_format) { case XFS_DINODE_FMT_LOCAL: err = process_lclinode(mp, agno, ino, dino, XFS_DATA_FORK); *totblocks = 0; break; case XFS_DINODE_FMT_EXTENTS: err = process_exinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, XFS_DATA_FORK, check_dups); break; case XFS_DINODE_FMT_BTREE: err = process_btinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, XFS_DATA_FORK, check_dups); break; case XFS_DINODE_FMT_DEV: /* fall through */ err = 0; break; default: do_error(_("unknown format %d, ino %" PRIu64 " (mode = %d)\n"), dino->di_format, lino, be16_to_cpu(dino->di_mode)); } if (err) { do_warn(_("bad data fork in inode %" PRIu64 "\n"), lino); if (!no_modify) { clear_dinode(mp, dino, lino); *dirty += 1; } return 1; } if (check_dups) { /* * if check_dups was non-zero, we have to * re-process data fork to set bitmap since the * bitmap wasn't set the first time through */ switch (dino->di_format) { case XFS_DINODE_FMT_LOCAL: err = process_lclinode(mp, agno, ino, dino, XFS_DATA_FORK); break; case XFS_DINODE_FMT_EXTENTS: err = process_exinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, XFS_DATA_FORK, 0); break; case XFS_DINODE_FMT_BTREE: err = process_btinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, XFS_DATA_FORK, 0); break; case XFS_DINODE_FMT_DEV: /* fall through */ err = 0; break; default: do_error(_("unknown format %d, ino %" PRIu64 " (mode = %d)\n"), dino->di_format, lino, be16_to_cpu(dino->di_mode)); } if (no_modify && err != 0) return 1; ASSERT(err == 0); } return 0; } /* * Process extended attribute fork in inode */ static int process_inode_attr_fork( xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t ino, xfs_dinode_t *dino, int type, int *dirty, xfs_rfsblock_t *atotblocks, uint64_t *anextents, int check_dups, int extra_attr_check, int *retval) { xfs_ino_t lino = XFS_AGINO_TO_INO(mp, agno, ino); blkmap_t *ablkmap = NULL; int repair = 0; int err; if (!XFS_DFORK_Q(dino)) { *anextents = 0; if (dino->di_aformat != XFS_DINODE_FMT_EXTENTS) { do_warn(_("bad attribute format %d in inode %" PRIu64 ", "), dino->di_aformat, lino); if (!no_modify) { do_warn(_("resetting value\n")); dino->di_aformat = XFS_DINODE_FMT_EXTENTS; *dirty = 1; } else do_warn(_("would reset value\n")); } return 0; } *anextents = be16_to_cpu(dino->di_anextents); if (*anextents > be64_to_cpu(dino->di_nblocks)) *anextents = 1; switch (dino->di_aformat) { case XFS_DINODE_FMT_LOCAL: *anextents = 0; *atotblocks = 0; err = process_lclinode(mp, agno, ino, dino, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_EXTENTS: ablkmap = blkmap_alloc(*anextents, XFS_ATTR_FORK); *anextents = 0; err = process_exinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, &ablkmap, XFS_ATTR_FORK, check_dups); break; case XFS_DINODE_FMT_BTREE: ablkmap = blkmap_alloc(*anextents, XFS_ATTR_FORK); *anextents = 0; err = process_btinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, &ablkmap, XFS_ATTR_FORK, check_dups); break; default: do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"), dino->di_aformat, lino); err = 1; break; } if (err) { /* * clear the attribute fork if necessary. we can't * clear the inode because we've already put the * inode space info into the blockmap. * * XXX - put the inode onto the "move it" list and * log the the attribute scrubbing */ do_warn(_("bad attribute fork in inode %" PRIu64), lino); if (!no_modify) { do_warn(_(", clearing attr fork\n")); *dirty += clear_dinode_attr(mp, dino, lino); dino->di_aformat = XFS_DINODE_FMT_LOCAL; ASSERT(*dirty > 0); } else { do_warn(_(", would clear attr fork\n")); } *atotblocks = 0; *anextents = 0; blkmap_free(ablkmap); *retval = 1; return 0; } if (check_dups) { switch (dino->di_aformat) { case XFS_DINODE_FMT_LOCAL: err = process_lclinode(mp, agno, ino, dino, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_EXTENTS: err = process_exinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, &ablkmap, XFS_ATTR_FORK, 0); break; case XFS_DINODE_FMT_BTREE: err = process_btinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, &ablkmap, XFS_ATTR_FORK, 0); break; default: do_error(_("illegal attribute fmt %d, ino %" PRIu64 "\n"), dino->di_aformat, lino); } if (no_modify && err != 0) { blkmap_free(ablkmap); return 1; } ASSERT(err == 0); } /* * do attribute semantic-based consistency checks now */ /* get this only in phase 3, not in both phase 3 and 4 */ if (extra_attr_check && process_attributes(mp, lino, dino, ablkmap, &repair)) { do_warn( _("problem with attribute contents in inode %" PRIu64 "\n"), lino); if (!repair) { /* clear attributes if not done already */ if (!no_modify) { *dirty += clear_dinode_attr(mp, dino, lino); dino->di_aformat = XFS_DINODE_FMT_LOCAL; } else { do_warn(_("would clear attr fork\n")); } *atotblocks = 0; *anextents = 0; } else { *dirty = 1; /* it's been repaired */ } } blkmap_free(ablkmap); return 0; } /* * check nlinks feature, if it's a version 1 inode, * just leave nlinks alone. even if it's set wrong, * it'll be reset when read in. */ static int process_check_inode_nlink_version( xfs_dinode_t *dino, xfs_ino_t lino) { int dirty = 0; /* * if it's a version 2 inode, it should have a zero * onlink field, so clear it. */ if (dino->di_version > 1 && dino->di_onlink != 0) { if (!no_modify) { do_warn( _("clearing obsolete nlink field in version 2 inode %" PRIu64 ", was %d, now 0\n"), lino, be16_to_cpu(dino->di_onlink)); dino->di_onlink = 0; dirty = 1; } else { do_warn( _("would clear obsolete nlink field in version 2 inode %" PRIu64 ", currently %d\n"), lino, be16_to_cpu(dino->di_onlink)); } } return dirty; } /* Check nanoseconds of a timestamp don't exceed 1 second. */ static void check_nsec( const char *name, xfs_ino_t lino, struct xfs_timestamp *t, int *dirty) { if (be32_to_cpu(t->t_nsec) < 1000000000) return; do_warn( _("Bad %s nsec %u on inode %" PRIu64 ", "), name, be32_to_cpu(t->t_nsec), lino); if (no_modify) { do_warn(_("would reset to zero\n")); } else { do_warn(_("resetting to zero\n")); t->t_nsec = 0; *dirty = 1; } } /* * returns 0 if the inode is ok, 1 if the inode is corrupt * check_dups can be set to 1 *only* when called by the * first pass of the duplicate block checking of phase 4. * *dirty is set > 0 if the dinode has been altered and * needs to be written out. * * for detailed, info, look at process_dinode() comments. */ static int process_dinode_int(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino, int was_free, /* 1 if inode is currently free */ int *dirty, /* out == > 0 if inode is now dirty */ int *used, /* out == 1 if inode is in use */ int verify_mode, /* 1 == verify but don't modify inode */ int uncertain, /* 1 == inode is uncertain */ int ino_discovery, /* 1 == check dirs for unknown inodes */ int check_dups, /* 1 == check if inode claims * duplicate blocks */ int extra_attr_check, /* 1 == do attribute format and value checks */ int *isa_dir, /* out == 1 if inode is a directory */ xfs_ino_t *parent) /* out -- parent if ino is a dir */ { xfs_rfsblock_t totblocks = 0; xfs_rfsblock_t atotblocks = 0; int di_mode; int type; int retval = 0; uint64_t nextents; uint64_t anextents; xfs_ino_t lino; const int is_free = 0; const int is_used = 1; blkmap_t *dblkmap = NULL; *dirty = *isa_dir = 0; *used = is_used; type = XR_INO_UNKNOWN; lino = XFS_AGINO_TO_INO(mp, agno, ino); di_mode = be16_to_cpu(dino->di_mode); /* * if in verify mode, don't modify the inode. * * if correcting, reset stuff that has known values * * if in uncertain mode, be silent on errors since we're * trying to find out if these are inodes as opposed * to assuming that they are. Just return the appropriate * return code in that case. * * If uncertain is set, verify_mode MUST be set. */ ASSERT(uncertain == 0 || verify_mode != 0); /* * This is the only valid point to check the CRC; after this we may have * made changes which invalidate it, and the CRC is only updated again * when it gets written out. * * Of course if we make any modifications after this, the inode gets * rewritten, and the CRC is updated automagically. */ if (xfs_sb_version_hascrc(&mp->m_sb) && !libxfs_verify_cksum((char *)dino, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF)) { retval = 1; if (!uncertain) do_warn(_("bad CRC for inode %" PRIu64 "%c"), lino, verify_mode ? '\n' : ','); if (!verify_mode) { if (!no_modify) { do_warn(_(" will rewrite\n")); *dirty = 1; } else do_warn(_(" would rewrite\n")); } } if (be16_to_cpu(dino->di_magic) != XFS_DINODE_MAGIC) { retval = 1; if (!uncertain) do_warn(_("bad magic number 0x%x on inode %" PRIu64 "%c"), be16_to_cpu(dino->di_magic), lino, verify_mode ? '\n' : ','); if (!verify_mode) { if (!no_modify) { do_warn(_(" resetting magic number\n")); dino->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); *dirty = 1; } else do_warn(_(" would reset magic number\n")); } } if (!libxfs_dinode_good_version(mp, dino->di_version)) { retval = 1; if (!uncertain) do_warn(_("bad version number 0x%x on inode %" PRIu64 "%c"), (__s8)dino->di_version, lino, verify_mode ? '\n' : ','); if (!verify_mode) { if (!no_modify) { do_warn(_(" resetting version number\n")); dino->di_version = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2; *dirty = 1; } else do_warn(_(" would reset version number\n")); } } /* * We don't bother checking the CRC here - we cannot guarantee that when * we are called here that the inode has not already been modified in * memory and hence invalidated the CRC. */ if (xfs_sb_version_hascrc(&mp->m_sb)) { if (be64_to_cpu(dino->di_ino) != lino) { if (!uncertain) do_warn( _("inode identifier %llu mismatch on inode %" PRIu64 "\n"), (unsigned long long)be64_to_cpu(dino->di_ino), lino); if (verify_mode) return 1; goto clear_bad_out; } if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_meta_uuid)) { if (!uncertain) do_warn( _("UUID mismatch on inode %" PRIu64 "\n"), lino); if (verify_mode) return 1; goto clear_bad_out; } } /* * blow out of here if the inode size is < 0 */ if ((xfs_fsize_t)be64_to_cpu(dino->di_size) < 0) { if (!uncertain) do_warn( _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), (int64_t)be64_to_cpu(dino->di_size), lino); if (verify_mode) return 1; goto clear_bad_out; } /* * if not in verify mode, check to see if the inode and imap * agree that the inode is free */ if (!verify_mode && di_mode == 0) { /* * was_free value is not meaningful if we're in verify mode */ if (was_free) { /* * easy case, inode free -- inode and map agree, check * it just in case to ensure that format, etc. are * set correctly */ if (libxfs_dinode_verify(mp, lino, dino) != NULL) { do_warn( _("free inode %" PRIu64 " contains errors, "), lino); if (!no_modify) { clear_dinode(mp, dino, lino); do_warn(_("corrected\n")); *dirty += 1; } else { do_warn(_("would correct\n")); } } *used = is_free; return 0; } /* * the inode looks free but the map says it's in use. * clear the inode just to be safe and mark the inode * free. */ do_warn( _("imap claims a free inode %" PRIu64 " is in use, "), lino); if (!no_modify) { do_warn(_("correcting imap and clearing inode\n")); clear_dinode(mp, dino, lino); *dirty += 1; retval = 1; } else do_warn(_("would correct imap and clear inode\n")); *used = is_free; return retval; } /* * because of the lack of any write ordering guarantee, it's * possible that the core got updated but the forks didn't. * so rather than be ambitious (and probably incorrect), * if there's an inconsistency, we get conservative and * just pitch the file. blow off checking formats of * free inodes since technically any format is legal * as we reset the inode when we re-use it. */ if (di_mode != 0 && check_dinode_mode_format(dino) != 0) { if (!uncertain) do_warn( _("bad inode format in inode %" PRIu64 "\n"), lino); if (verify_mode) return 1; goto clear_bad_out; } /* * check that we only have valid flags set, and those that are set make * sense. */ if (dino->di_flags) { uint16_t flags = be16_to_cpu(dino->di_flags); if (flags & ~XFS_DIFLAG_ANY) { if (!uncertain) { do_warn( _("Bad flags set in inode %" PRIu64 "\n"), lino); } flags &= XFS_DIFLAG_ANY; } if (flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT)) { /* need an rt-dev! */ if (!rt_name) { if (!uncertain) { do_warn( _("inode %" PRIu64 " has RT flag set but there is no RT device\n"), lino); } flags &= ~(XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT); } } if (flags & XFS_DIFLAG_NEWRTBM) { /* must be a rt bitmap inode */ if (lino != mp->m_sb.sb_rbmino) { if (!uncertain) { do_warn( _("inode %" PRIu64 " not rt bitmap\n"), lino); } flags &= ~XFS_DIFLAG_NEWRTBM; } } if (flags & (XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS)) { /* must be a directory */ if (di_mode && !S_ISDIR(di_mode)) { if (!uncertain) { do_warn( _("directory flags set on non-directory inode %" PRIu64 "\n" ), lino); } flags &= ~(XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS); } } if (flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) { /* must be a file */ if (di_mode && !S_ISREG(di_mode)) { if (!uncertain) { do_warn( _("file flags set on non-file inode %" PRIu64 "\n"), lino); } flags &= ~(XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE); } } if (!verify_mode && flags != be16_to_cpu(dino->di_flags)) { if (!no_modify) { do_warn(_("fixing bad flags.\n")); dino->di_flags = cpu_to_be16(flags); *dirty = 1; } else do_warn(_("would fix bad flags.\n")); } } /* * check that we only have valid flags2 set, and those that are set make * sense. */ if (dino->di_version >= 3) { uint16_t flags = be16_to_cpu(dino->di_flags); uint64_t flags2 = be64_to_cpu(dino->di_flags2); if (flags2 & ~XFS_DIFLAG2_ANY) { if (!uncertain) { do_warn( _("Bad flags2 set in inode %" PRIu64 "\n"), lino); } flags2 &= XFS_DIFLAG2_ANY; } if (flags2 & XFS_DIFLAG2_DAX) { /* must be a file or dir */ if (di_mode && !(S_ISREG(di_mode) || S_ISDIR(di_mode))) { if (!uncertain) { do_warn( _("DAX flag set on special inode %" PRIu64 "\n"), lino); } flags2 &= ~XFS_DIFLAG2_DAX; } } if ((flags2 & XFS_DIFLAG2_REFLINK) && !xfs_sb_version_hasreflink(&mp->m_sb)) { if (!uncertain) { do_warn( _("inode %" PRIu64 " is marked reflinked but file system does not support reflink\n"), lino); } goto clear_bad_out; } if (flags2 & XFS_DIFLAG2_REFLINK) { /* must be a file */ if (di_mode && !S_ISREG(di_mode)) { if (!uncertain) { do_warn( _("reflink flag set on non-file inode %" PRIu64 "\n"), lino); } goto clear_bad_out; } } if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT))) { if (!uncertain) { do_warn( _("Cannot have a reflinked realtime inode %" PRIu64 "\n"), lino); } goto clear_bad_out; } if ((flags2 & XFS_DIFLAG2_COWEXTSIZE) && !xfs_sb_version_hasreflink(&mp->m_sb)) { if (!uncertain) { do_warn( _("inode %" PRIu64 " has CoW extent size hint but file system does not support reflink\n"), lino); } flags2 &= ~XFS_DIFLAG2_COWEXTSIZE; } if (flags2 & XFS_DIFLAG2_COWEXTSIZE) { /* must be a directory or file */ if (di_mode && !S_ISDIR(di_mode) && !S_ISREG(di_mode)) { if (!uncertain) { do_warn( _("CoW extent size flag set on non-file, non-directory inode %" PRIu64 "\n" ), lino); } flags2 &= ~XFS_DIFLAG2_COWEXTSIZE; } } if ((flags2 & XFS_DIFLAG2_COWEXTSIZE) && (flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT))) { if (!uncertain) { do_warn( _("Cannot have CoW extent size hint on a realtime inode %" PRIu64 "\n"), lino); } flags2 &= ~XFS_DIFLAG2_COWEXTSIZE; } if (!verify_mode && flags2 != be64_to_cpu(dino->di_flags2)) { if (!no_modify) { do_warn(_("fixing bad flags2.\n")); dino->di_flags2 = cpu_to_be64(flags2); *dirty = 1; } else do_warn(_("would fix bad flags2.\n")); } } if (verify_mode) return retval; /* * clear the next unlinked field if necessary on a good * inode only during phase 4 -- when checking for inodes * referencing duplicate blocks. then it's safe because * we've done the inode discovery and have found all the inodes * we're going to find. check_dups is set to 1 only during * phase 4. Ugly. */ if (check_dups && be32_to_cpu(dino->di_next_unlinked) != NULLAGINO) { if (no_modify) { do_warn( _("Would clear next_unlinked in inode %" PRIu64 "\n"), lino); } else { clear_dinode_unlinked(mp, dino); do_warn( _("Cleared next_unlinked in inode %" PRIu64 "\n"), lino); *dirty += 1; } } /* set type and map type info */ switch (di_mode & S_IFMT) { case S_IFDIR: type = XR_INO_DIR; *isa_dir = 1; break; case S_IFREG: if (be16_to_cpu(dino->di_flags) & XFS_DIFLAG_REALTIME) type = XR_INO_RTDATA; else if (lino == mp->m_sb.sb_rbmino) type = XR_INO_RTBITMAP; else if (lino == mp->m_sb.sb_rsumino) type = XR_INO_RTSUM; else if (lino == mp->m_sb.sb_uquotino) type = XR_INO_UQUOTA; else if (lino == mp->m_sb.sb_gquotino) type = XR_INO_GQUOTA; else if (lino == mp->m_sb.sb_pquotino) type = XR_INO_PQUOTA; else type = XR_INO_DATA; break; case S_IFLNK: type = XR_INO_SYMLINK; break; case S_IFCHR: type = XR_INO_CHRDEV; break; case S_IFBLK: type = XR_INO_BLKDEV; break; case S_IFSOCK: type = XR_INO_SOCK; break; case S_IFIFO: type = XR_INO_FIFO; break; default: do_warn(_("bad inode type %#o inode %" PRIu64 "\n"), di_mode & S_IFMT, lino); goto clear_bad_out; } /* * type checks for superblock inodes */ if (process_check_sb_inodes(mp, dino, lino, &type, dirty) != 0) goto clear_bad_out; /* * only regular files with REALTIME or EXTSIZE flags set can have * extsize set, or directories with EXTSZINHERIT. */ if (libxfs_inode_validate_extsize(mp, be32_to_cpu(dino->di_extsize), be16_to_cpu(dino->di_mode), be16_to_cpu(dino->di_flags)) != NULL) { do_warn( _("Bad extent size %u on inode %" PRIu64 ", "), be32_to_cpu(dino->di_extsize), lino); if (!no_modify) { do_warn(_("resetting to zero\n")); dino->di_extsize = 0; dino->di_flags &= ~cpu_to_be16(XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT); *dirty = 1; } else do_warn(_("would reset to zero\n")); } /* * Only (regular files and directories) with COWEXTSIZE flags * set can have extsize set. */ if (dino->di_version >= 3 && libxfs_inode_validate_cowextsize(mp, be32_to_cpu(dino->di_cowextsize), be16_to_cpu(dino->di_mode), be16_to_cpu(dino->di_flags), be64_to_cpu(dino->di_flags2)) != NULL) { do_warn( _("Bad CoW extent size %u on inode %" PRIu64 ", "), be32_to_cpu(dino->di_cowextsize), lino); if (!no_modify) { do_warn(_("resetting to zero\n")); dino->di_flags2 &= ~cpu_to_be64(XFS_DIFLAG2_COWEXTSIZE); dino->di_cowextsize = 0; *dirty = 1; } else do_warn(_("would reset to zero\n")); } /* nsec fields cannot be larger than 1 billion */ check_nsec("atime", lino, &dino->di_atime, dirty); check_nsec("mtime", lino, &dino->di_mtime, dirty); check_nsec("ctime", lino, &dino->di_ctime, dirty); if (dino->di_version >= 3) check_nsec("crtime", lino, &dino->di_crtime, dirty); /* * general size/consistency checks: */ if (process_check_inode_sizes(mp, dino, lino, type) != 0) goto clear_bad_out; /* * check for illegal values of forkoff */ if (process_check_inode_forkoff(mp, dino, lino) != 0) goto clear_bad_out; /* * record the state of the reflink flag */ if (collect_rmaps) record_inode_reflink_flag(mp, dino, agno, ino, lino); /* * check data fork -- if it's bad, clear the inode */ if (process_inode_data_fork(mp, agno, ino, dino, type, dirty, &totblocks, &nextents, &dblkmap, check_dups) != 0) goto bad_out; /* * check attribute fork if necessary. attributes are * always stored in the regular filesystem. */ if (process_inode_attr_fork(mp, agno, ino, dino, type, dirty, &atotblocks, &anextents, check_dups, extra_attr_check, &retval)) goto bad_out; /* * enforce totblocks is 0 for misc types */ if (process_misc_ino_types_blocks(totblocks, lino, type)) goto clear_bad_out; /* * correct space counters if required */ if (process_inode_blocks_and_extents(dino, totblocks + atotblocks, nextents, anextents, lino, dirty) != 0) goto clear_bad_out; /* * do any semantic type-based checking here */ switch (type) { case XR_INO_DIR: if (process_dir2(mp, lino, dino, ino_discovery, dirty, "", parent, dblkmap)) { do_warn( _("problem with directory contents in inode %" PRIu64 "\n"), lino); goto clear_bad_out; } break; case XR_INO_SYMLINK: if (process_symlink(mp, lino, dino, dblkmap) != 0) { do_warn( _("problem with symbolic link in inode %" PRIu64 "\n"), lino); goto clear_bad_out; } break; case XR_INO_UQUOTA: case XR_INO_GQUOTA: case XR_INO_PQUOTA: if (process_quota_inode(mp, lino, dino, type, dblkmap) != 0) { do_warn( _("problem with quota inode %" PRIu64 "\n"), lino); goto clear_bad_out; } break; default: break; } blkmap_free(dblkmap); /* * check nlinks feature, if it's a version 1 inode, * just leave nlinks alone. even if it's set wrong, * it'll be reset when read in. */ *dirty += process_check_inode_nlink_version(dino, lino); return retval; clear_bad_out: if (!no_modify) { clear_dinode(mp, dino, lino); *dirty += 1; } bad_out: *used = is_free; *isa_dir = 0; blkmap_free(dblkmap); return 1; } /* * returns 1 if inode is used, 0 if free. * performs any necessary salvaging actions. * note that we leave the generation count alone * because nothing we could set it to would be * guaranteed to be correct so the best guess for * the correct value is just to leave it alone. * * The trick is detecting empty files. For those, * the core and the forks should all be in the "empty" * or zero-length state -- a zero or possibly minimum length * (in the case of dirs) extent list -- although inline directories * and symlinks might be handled differently. So it should be * possible to sanity check them against each other. * * If the forks are an empty extent list though, then forget it. * The file is toast anyway since we can't recover its storage. * * Parameters: * Ins: * mp -- mount structure * dino -- pointer to on-disk inode structure * agno/ino -- inode numbers * free -- whether the map thinks the inode is free (1 == free) * ino_discovery -- whether we should examine directory * contents to discover new inodes * check_dups -- whether we should check to see if the * inode references duplicate blocks * if so, we compare the inode's claimed * blocks against the contents of the * duplicate extent list but we don't * set the bitmap. If not, we set the * bitmap and try and detect multiply * claimed blocks using the bitmap. * Outs: * dirty -- whether we changed the inode (1 == yes) * used -- 1 if the inode is used, 0 if free. In no modify * mode, whether the inode should be used or free * isa_dir -- 1 if the inode is a directory, 0 if not. In * no modify mode, if the inode would be a dir or not. * * Return value -- 0 if the inode is good, 1 if it is/was corrupt */ int process_dinode( xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino, int was_free, int *dirty, int *used, int ino_discovery, int check_dups, int extra_attr_check, int *isa_dir, xfs_ino_t *parent) { const int verify_mode = 0; const int uncertain = 0; #ifdef XR_INODE_TRACE fprintf(stderr, _("processing inode %d/%d\n"), agno, ino); #endif return process_dinode_int(mp, dino, agno, ino, was_free, dirty, used, verify_mode, uncertain, ino_discovery, check_dups, extra_attr_check, isa_dir, parent); } /* * a more cursory check, check inode core, *DON'T* check forks * this basically just verifies whether the inode is an inode * and whether or not it has been totally trashed. returns 0 * if the inode passes the cursory sanity check, 1 otherwise. */ int verify_dinode( xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino) { xfs_ino_t parent; int used = 0; int dirty = 0; int isa_dir = 0; const int verify_mode = 1; const int check_dups = 0; const int ino_discovery = 0; const int uncertain = 0; return process_dinode_int(mp, dino, agno, ino, 0, &dirty, &used, verify_mode, uncertain, ino_discovery, check_dups, 0, &isa_dir, &parent); } /* * like above only for inode on the uncertain list. it sets * the uncertain flag which makes process_dinode_int quieter. * returns 0 if the inode passes the cursory sanity check, 1 otherwise. */ int verify_uncertain_dinode( xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino) { xfs_ino_t parent; int used = 0; int dirty = 0; int isa_dir = 0; const int verify_mode = 1; const int check_dups = 0; const int ino_discovery = 0; const int uncertain = 1; return process_dinode_int(mp, dino, agno, ino, 0, &dirty, &used, verify_mode, uncertain, ino_discovery, check_dups, 0, &isa_dir, &parent); } xfsprogs-5.3.0/repair/dinode.h0000644000175000017500000000412713435336037016154 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XR_DINODE_H #define _XR_DINODE_H struct blkmap; struct prefetch_args; int verify_agbno(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno); int verify_dfsbno(xfs_mount_t *mp, xfs_fsblock_t fsbno); void convert_extent( xfs_bmbt_rec_t *rp, xfs_fileoff_t *op, /* starting offset (blockno in file) */ xfs_fsblock_t *sp, /* starting block (fs blockno) */ xfs_filblks_t *cp, /* blockcount */ int *fp); /* extent flag */ int process_bmbt_reclist(xfs_mount_t *mp, xfs_bmbt_rec_t *rp, int *numrecs, int type, xfs_ino_t ino, xfs_rfsblock_t *tot, struct blkmap **blkmapp, uint64_t *first_key, uint64_t *last_key, int whichfork); int scan_bmbt_reclist( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, int *numrecs, int type, xfs_ino_t ino, xfs_rfsblock_t *tot, int whichfork); void update_rootino(xfs_mount_t *mp); int process_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino, int was_free, int *dirty, int *used, int check_dirs, int check_dups, int extra_attr_check, int *isa_dir, xfs_ino_t *parent); int verify_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino); int verify_uncertain_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_agnumber_t agno, xfs_agino_t ino); int verify_inum(xfs_mount_t *mp, xfs_ino_t ino); int verify_aginum(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t agino); int process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno); void process_aginodes(xfs_mount_t *mp, struct prefetch_args *pf_args, xfs_agnumber_t agno, int check_dirs, int check_dups, int extra_attr_check); void check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno); struct xfs_buf * get_agino_buf( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino, struct xfs_dinode **dipp); void dinode_bmbt_translation_init(void); char * get_forkname(int whichfork); #endif /* _XR_DINODE_H */ xfsprogs-5.3.0/repair/dir2.c0000644000175000017500000011335413570057155015551 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "incore.h" #include "err_protos.h" #include "dinode.h" #include "dir2.h" #include "bmap.h" #include "da_util.h" #include "prefetch.h" #include "progress.h" /* * Known bad inode list. These are seen when the leaf and node * block linkages are incorrect. */ typedef struct dir2_bad { xfs_ino_t ino; struct dir2_bad *next; } dir2_bad_t; static dir2_bad_t *dir2_bad_list; static void dir2_add_badlist( xfs_ino_t ino) { dir2_bad_t *l; if ((l = malloc(sizeof(dir2_bad_t))) == NULL) { do_error( _("malloc failed (%zu bytes) dir2_add_badlist:ino %" PRIu64 "\n"), sizeof(dir2_bad_t), ino); exit(1); } l->next = dir2_bad_list; dir2_bad_list = l; l->ino = ino; } int dir2_is_badino( xfs_ino_t ino) { dir2_bad_t *l; for (l = dir2_bad_list; l; l = l->next) if (l->ino == ino) return 1; return 0; } /* * Fix up a shortform directory which was in long form (i8count set) * and is now in short form (i8count clear). * Return pointer to the end of the data when done. */ void process_sf_dir2_fixi8( struct xfs_mount *mp, struct xfs_dir2_sf_hdr *sfp, xfs_dir2_sf_entry_t **next_sfep) { xfs_ino_t ino; struct xfs_dir2_sf_hdr *newsfp; xfs_dir2_sf_entry_t *newsfep; struct xfs_dir2_sf_hdr *oldsfp; xfs_dir2_sf_entry_t *oldsfep; int oldsize; newsfp = sfp; oldsize = (intptr_t)*next_sfep - (intptr_t)sfp; oldsfp = malloc(oldsize); if (oldsfp == NULL) { do_error(_("couldn't malloc dir2 shortform copy\n")); exit(1); } memmove(oldsfp, newsfp, oldsize); newsfp->count = oldsfp->count; newsfp->i8count = 0; ino = M_DIROPS(mp)->sf_get_parent_ino(sfp); M_DIROPS(mp)->sf_put_parent_ino(newsfp, ino); oldsfep = xfs_dir2_sf_firstentry(oldsfp); newsfep = xfs_dir2_sf_firstentry(newsfp); while ((int)((char *)oldsfep - (char *)oldsfp) < oldsize) { newsfep->namelen = oldsfep->namelen; xfs_dir2_sf_put_offset(newsfep, xfs_dir2_sf_get_offset(oldsfep)); memmove(newsfep->name, oldsfep->name, newsfep->namelen); ino = M_DIROPS(mp)->sf_get_ino(oldsfp, oldsfep); M_DIROPS(mp)->sf_put_ino(newsfp, newsfep, ino); oldsfep = M_DIROPS(mp)->sf_nextentry(oldsfp, oldsfep); newsfep = M_DIROPS(mp)->sf_nextentry(newsfp, newsfep); } *next_sfep = newsfep; free(oldsfp); } /* * Regenerate legal (minimal) offsets for the shortform directory. */ static void process_sf_dir2_fixoff( xfs_mount_t *mp, xfs_dinode_t *dip) { int i; int offset; xfs_dir2_sf_entry_t *sfep; struct xfs_dir2_sf_hdr *sfp; sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); sfep = xfs_dir2_sf_firstentry(sfp); offset = M_DIROPS(mp)->data_first_offset; for (i = 0; i < sfp->count; i++) { xfs_dir2_sf_put_offset(sfep, offset); offset += M_DIROPS(mp)->data_entsize(sfep->namelen); sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep); } } /* * this routine performs inode discovery and tries to fix things * in place. available redundancy -- inode data size should match * used directory space in inode. * a non-zero return value means the directory is bogus and should be blasted. */ /* ARGSUSED */ static int process_sf_dir2( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, int ino_discovery, int *dino_dirty, /* out - 1 if dinode buffer dirty */ char *dirname, /* directory pathname */ xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ int *repair) /* out - 1 if dir was fixed up */ { int bad_offset; int bad_sfnamelen; int i; int i8; int64_t ino_dir_size; int ino_off; ino_tree_node_t *irec_p; int junkit; char *junkreason = NULL; xfs_ino_t lino; int max_size; char name[MAXNAMELEN + 1]; int namelen; xfs_dir2_sf_entry_t *next_sfep; int num_entries; int offset; struct xfs_dir2_sf_hdr *sfp; xfs_dir2_sf_entry_t *sfep; int tmp_elen; int tmp_len; xfs_dir2_sf_entry_t *tmp_sfep; xfs_ino_t zero = 0; sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); max_size = XFS_DFORK_DSIZE(dip, mp); num_entries = sfp->count; ino_dir_size = be64_to_cpu(dip->di_size); offset = M_DIROPS(mp)->data_first_offset; bad_offset = *repair = 0; ASSERT(ino_dir_size <= max_size); /* * Initialize i8 based on size of parent inode number. */ i8 = (M_DIROPS(mp)->sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM); /* * check for bad entry count */ if (num_entries * M_DIROPS(mp)->sf_entsize(sfp, 1) + xfs_dir2_sf_hdr_size(0) > max_size || num_entries == 0) num_entries = 0xFF; /* * run through entries, stop at first bad entry, don't need * to check for .. since that's encoded in its own field */ next_sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0; i < num_entries && ino_dir_size > (char *)next_sfep - (char *)sfp; i++) { tmp_sfep = NULL; sfep = next_sfep; junkit = 0; bad_sfnamelen = 0; lino = M_DIROPS(mp)->sf_get_ino(sfp, sfep); /* * if entry points to self, junk it since only '.' or '..' * should do that and shortform dirs don't contain either * entry. if inode number is invalid, trash entry. * if entry points to special inodes, trash it. * if inode is unknown but number is valid, * add it to the list of uncertain inodes. don't * have to worry about an entry pointing to a * deleted lost+found inode because the entry was * deleted at the same time that the inode was cleared. */ if (lino == ino) { junkit = 1; junkreason = _("current"); } else if (verify_inum(mp, lino)) { junkit = 1; junkreason = _("invalid"); } else if (lino == mp->m_sb.sb_rbmino) { junkit = 1; junkreason = _("realtime bitmap"); } else if (lino == mp->m_sb.sb_rsumino) { junkit = 1; junkreason = _("realtime summary"); } else if (lino == mp->m_sb.sb_uquotino) { junkit = 1; junkreason = _("user quota"); } else if (lino == mp->m_sb.sb_gquotino) { junkit = 1; junkreason = _("group quota"); } else if (lino == mp->m_sb.sb_pquotino) { junkit = 1; junkreason = _("project quota"); } else if ((irec_p = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino))) != NULL) { /* * if inode is marked free and we're in inode * discovery mode, leave the entry alone for now. * if the inode turns out to be used, we'll figure * that out when we scan it. If the inode really * is free, we'll hit this code again in phase 4 * after we've finished inode discovery and blow * out the entry then. */ ino_off = XFS_INO_TO_AGINO(mp, lino) - irec_p->ino_startnum; ASSERT(is_inode_confirmed(irec_p, ino_off)); if (is_inode_free(irec_p, ino_off) && !ino_discovery) { junkit = 1; junkreason = _("free"); } } else if (ino_discovery) { /* * put the inode on the uncertain list. we'll * pull the inode off the list and check it later. * if the inode turns out be bogus, we'll delete * this entry in phase 6. */ add_inode_uncertain(mp, lino, 0); } else { /* * blow the entry out. we know about all * undiscovered entries now (past inode discovery * phase) so this is clearly a bogus entry. */ junkit = 1; junkreason = _("non-existent"); } namelen = sfep->namelen; if (junkit) do_warn( _("entry \"%*.*s\" in shortform directory %" PRIu64 " references %s inode %" PRIu64 "\n"), namelen, namelen, sfep->name, ino, junkreason, lino); /* is dir namelen 0 or does this entry extend past dir size? */ if (namelen == 0) { junkreason = _("is zero length"); bad_sfnamelen = 1; } else if ((intptr_t) sfep - (intptr_t) sfp + M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen) > ino_dir_size) { junkreason = _("extends past end of dir"); bad_sfnamelen = 1; } if (bad_sfnamelen) { do_warn( _("entry #%d %s in shortform dir %" PRIu64), i, junkreason, ino); if (!no_modify) do_warn(_(", junking %d entries\n"), num_entries - i); else do_warn(_(", would junk %d entries\n"), num_entries - i); /* * don't process the rest of the directory, * break out of processing loop */ break; } /* * check for illegal chars in name. * no need to check for bad length because * the length value is stored in a byte * so it can't be too big, it can only wrap */ if (!libxfs_dir2_namecheck(sfep->name, namelen)) { /* * junk entry */ do_warn( _("entry contains illegal character in shortform dir %" PRIu64 "\n"), ino); junkit = 1; } if (xfs_dir2_sf_get_offset(sfep) < offset) { do_warn( _("entry contains offset out of order in shortform dir %" PRIu64 "\n"), ino); bad_offset = 1; } offset = xfs_dir2_sf_get_offset(sfep) + M_DIROPS(mp)->data_entsize(namelen); /* * junk the entry by copying up the rest of the * fork over the current entry and decrementing * the entry count. if we're in no_modify mode, * just issue the warning instead. then continue * the loop with the next_sfep pointer set to the * correct place in the fork and other counters * properly set to reflect the deletion if it * happened. */ if (junkit) { memmove(name, sfep->name, namelen); name[namelen] = '\0'; if (!no_modify) { tmp_elen = M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen); be64_add_cpu(&dip->di_size, -tmp_elen); ino_dir_size -= tmp_elen; tmp_sfep = (xfs_dir2_sf_entry_t *) ((intptr_t) sfep + tmp_elen); tmp_len = max_size - ((intptr_t) tmp_sfep - (intptr_t) sfp); memmove(sfep, tmp_sfep, tmp_len); sfp->count -= 1; num_entries--; memset((void *) ((intptr_t) sfep + tmp_len), 0, tmp_elen); /* * reset the tmp value to the current * pointer so we'll process the entry * we just moved up */ tmp_sfep = sfep; /* * WARNING: drop the index i by one * so it matches the decremented count * for accurate comparisons later */ i--; *dino_dirty = 1; *repair = 1; do_warn( _("junking entry \"%s\" in directory inode %" PRIu64 "\n"), name, ino); } else { do_warn( _("would have junked entry \"%s\" in directory inode %" PRIu64 "\n"), name, ino); } } else if (lino > XFS_DIR2_MAX_SHORT_INUM) i8++; /* * go onto next entry unless we've just junked an * entry in which the current entry pointer points * to an unprocessed entry. have to take into zero-len * entries into account in no modify mode since we * calculate size based on next_sfep. */ next_sfep = (tmp_sfep == NULL) ? (xfs_dir2_sf_entry_t *) ((intptr_t) sfep + ((!bad_sfnamelen) ? M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen) : M_DIROPS(mp)->sf_entsize(sfp, namelen))) : tmp_sfep; } /* sync up sizes and entry counts */ if (sfp->count != i) { if (no_modify) { do_warn( _("would have corrected entry count in directory %" PRIu64 " from %d to %d\n"), ino, sfp->count, i); } else { do_warn( _("corrected entry count in directory %" PRIu64 ", was %d, now %d\n"), ino, sfp->count, i); sfp->count = i; *dino_dirty = 1; *repair = 1; } } if (sfp->i8count != i8) { if (no_modify) { do_warn( _("would have corrected i8 count in directory %" PRIu64 " from %d to %d\n"), ino, sfp->i8count, i8); } else { do_warn( _("corrected i8 count in directory %" PRIu64 ", was %d, now %d\n"), ino, sfp->i8count, i8); if (i8 == 0) process_sf_dir2_fixi8(mp, sfp, &next_sfep); else sfp->i8count = i8; *dino_dirty = 1; *repair = 1; } } if ((intptr_t)next_sfep - (intptr_t)sfp != ino_dir_size) { if (no_modify) { do_warn( _("would have corrected directory %" PRIu64 " size from %" PRId64 " to %" PRIdPTR "\n"), ino, ino_dir_size, (intptr_t)next_sfep - (intptr_t)sfp); } else { do_warn( _("corrected directory %" PRIu64 " size, was %" PRId64 ", now %" PRIdPTR "\n"), ino, ino_dir_size, (intptr_t)next_sfep - (intptr_t)sfp); dip->di_size = cpu_to_be64( (intptr_t)next_sfep - (intptr_t)sfp); *dino_dirty = 1; *repair = 1; } } if (offset + (sfp->count + 2) * sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) { do_warn(_("directory %" PRIu64 " offsets too high\n"), ino); bad_offset = 1; } if (bad_offset) { if (no_modify) { do_warn( _("would have corrected entry offsets in directory %" PRIu64 "\n"), ino); } else { do_warn( _("corrected entry offsets in directory %" PRIu64 "\n"), ino); process_sf_dir2_fixoff(mp, dip); *dino_dirty = 1; *repair = 1; } } /* * check parent (..) entry */ *parent = M_DIROPS(mp)->sf_get_parent_ino(sfp); /* * if parent entry is bogus, null it out. we'll fix it later . * If the validation fails for the root inode we fix it in * the next else case. */ if (verify_inum(mp, *parent) && ino != mp->m_sb.sb_rootino) { do_warn( _("bogus .. inode number (%" PRIu64 ") in directory inode %" PRIu64 ", "), *parent, ino); *parent = NULLFSINO; if (!no_modify) { do_warn(_("clearing inode number\n")); M_DIROPS(mp)->sf_put_parent_ino(sfp, zero); *dino_dirty = 1; *repair = 1; } else { do_warn(_("would clear inode number\n")); } } else if (ino == mp->m_sb.sb_rootino && ino != *parent) { /* * root directories must have .. == . */ if (!no_modify) { do_warn( _("corrected root directory %" PRIu64 " .. entry, was %" PRIu64 ", now %" PRIu64 "\n"), ino, *parent, ino); *parent = ino; M_DIROPS(mp)->sf_put_parent_ino(sfp, ino); *dino_dirty = 1; *repair = 1; } else { do_warn( _("would have corrected root directory %" PRIu64 " .. entry from %" PRIu64" to %" PRIu64 "\n"), ino, *parent, ino); } } else if (ino == *parent && ino != mp->m_sb.sb_rootino) { /* * likewise, non-root directories can't have .. pointing * to . */ *parent = NULLFSINO; do_warn( _("bad .. entry in directory inode %" PRIu64 ", points to self, "), ino); if (!no_modify) { do_warn(_("clearing inode number\n")); M_DIROPS(mp)->sf_put_parent_ino(sfp, zero); *dino_dirty = 1; *repair = 1; } else { do_warn(_("would clear inode number\n")); } } return(0); } /* * Process one directory data block. */ /* ARGSUSED */ static int process_dir2_data( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, int ino_discovery, char *dirname, /* directory pathname */ xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ struct xfs_buf *bp, int *dot, /* out - 1 if there is a dot, else 0 */ int *dotdot, /* out - 1 if there's a dotdot, else 0 */ xfs_dablk_t da_bno, char *endptr, int *dirty) { int badbest; xfs_dir2_data_free_t *bf; int clearino; char *clearreason = NULL; struct xfs_dir2_data_hdr *d; xfs_dir2_data_entry_t *dep; xfs_dir2_data_free_t *dfp; xfs_dir2_data_unused_t *dup; int freeseen; int i; int ino_off; ino_tree_node_t *irec_p; int junkit; int lastfree; int nm_illegal; char *ptr; xfs_ino_t ent_ino; d = bp->b_addr; bf = M_DIROPS(mp)->data_bestfree_p(d); ptr = (char *)M_DIROPS(mp)->data_entry_p(d); badbest = lastfree = freeseen = 0; if (be16_to_cpu(bf[0].length) == 0) { badbest |= be16_to_cpu(bf[0].offset) != 0; freeseen |= 1 << 0; } if (be16_to_cpu(bf[1].length) == 0) { badbest |= be16_to_cpu(bf[1].offset) != 0; freeseen |= 1 << 1; } if (be16_to_cpu(bf[2].length) == 0) { badbest |= be16_to_cpu(bf[2].offset) != 0; freeseen |= 1 << 2; } badbest |= be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length); badbest |= be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length); while (ptr < endptr) { dup = (xfs_dir2_data_unused_t *)ptr; /* * If it's unused, look for the space in the bestfree table. * If we find it, account for that, else make sure it doesn't * need to be there. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { if (ptr + be16_to_cpu(dup->length) > endptr || be16_to_cpu(dup->length) == 0 || (be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1))) break; if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) != (char *)dup - (char *)d) break; badbest |= lastfree != 0; dfp = xfs_dir2_data_freefind(d, bf, dup); if (dfp) { i = dfp - bf; badbest |= (freeseen & (1 << i)) != 0; freeseen |= 1 << i; } else badbest |= be16_to_cpu(dup->length) > be16_to_cpu(bf[2].length); ptr += be16_to_cpu(dup->length); lastfree = 1; continue; } dep = (xfs_dir2_data_entry_t *)ptr; if (ptr + M_DIROPS(mp)->data_entsize(dep->namelen) > endptr) break; if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) != (char *)dep - (char *)d) break; ptr += M_DIROPS(mp)->data_entsize(dep->namelen); lastfree = 0; } /* * Dropped out before we processed everything, give up. * Phase 6 will kill this block if we don't kill the inode. */ if (ptr != endptr) { do_warn(_("corrupt block %u in directory inode %" PRIu64 "\n"), da_bno, ino); if (!no_modify) do_warn(_("\twill junk block\n")); else do_warn(_("\twould junk block\n")); return 1; } ptr = (char *)M_DIROPS(mp)->data_entry_p(d); /* * Process the entries now. */ while (ptr < endptr) { dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { ptr += be16_to_cpu(dup->length); continue; } dep = (xfs_dir2_data_entry_t *)ptr; ent_ino = be64_to_cpu(dep->inumber); clearino = 1; clearreason = NULL; /* * We may have to blow out an entry because of bad inode * numbers. Do NOT touch the name until after we've computed * the hashvalue and done a namecheck() on the name. * * Conditions must either set clearino to zero or set * clearreason why it's being cleared. */ if (!ino_discovery && dep->name[0] == '/') { /* * Don't do a damned thing. We already found this * (or did it ourselves) during phase 3. */ clearino = 0; } else if (verify_inum(mp, ent_ino)) { /* * Bad inode number. Clear the inode number and the * entry will get removed later. We don't trash the * directory since it's still structurally intact. */ clearreason = _("invalid"); } else if (ent_ino == mp->m_sb.sb_rbmino) { clearreason = _("realtime bitmap"); } else if (ent_ino == mp->m_sb.sb_rsumino) { clearreason = _("realtime summary"); } else if (ent_ino == mp->m_sb.sb_uquotino) { clearreason = _("user quota"); } else if (ent_ino == mp->m_sb.sb_gquotino) { clearreason = _("group quota"); } else if (ent_ino == mp->m_sb.sb_pquotino) { clearreason = _("project quota"); } else { irec_p = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ent_ino), XFS_INO_TO_AGINO(mp, ent_ino)); if (irec_p == NULL) { if (ino_discovery) { add_inode_uncertain(mp, ent_ino, 0); clearino = 0; } else clearreason = _("non-existent"); } else { /* * Inode recs should have only confirmed * inodes in them. */ ino_off = XFS_INO_TO_AGINO(mp, ent_ino) - irec_p->ino_startnum; ASSERT(is_inode_confirmed(irec_p, ino_off)); /* * If inode is marked free and we're in inode * discovery mode, leave the entry alone for * now. If the inode turns out to be used, * we'll figure that out when we scan it. * If the inode really is free, we'll hit this * code again in phase 4 after we've finished * inode discovery and blow out the entry then. */ if (!ino_discovery && is_inode_free(irec_p, ino_off)) clearreason = _("free"); else clearino = 0; } } ASSERT((clearino == 0 && clearreason == NULL) || (clearino != 0 && clearreason != NULL)); if (clearino) do_warn( _("entry \"%*.*s\" at block %d offset %" PRIdPTR " in directory inode %" PRIu64 " references %s inode %" PRIu64 "\n"), dep->namelen, dep->namelen, dep->name, da_bno, (intptr_t)ptr - (intptr_t)d, ino, clearreason, ent_ino); /* * We have a special dot & dotdot fixer-upper below which can * sort out the proper inode number, so don't clear it. */ if ((dep->namelen == 1 && dep->name[0] == '.') || (dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.')) { clearino = 0; clearreason = NULL; } /* * If the name length is 0 (illegal) make it 1 and blast * the entry. */ if (dep->namelen == 0) { do_warn( _("entry at block %u offset %" PRIdPTR " in directory inode %" PRIu64 "has 0 namelength\n"), da_bno, (intptr_t)ptr - (intptr_t)d, ino); if (!no_modify) dep->namelen = 1; clearino = 1; } /* * If needed to clear the inode number, do it now. */ if (clearino) { if (!no_modify) { do_warn( _("\tclearing inode number in entry at offset %" PRIdPTR "...\n"), (intptr_t)ptr - (intptr_t)d); dep->name[0] = '/'; *dirty = 1; } else { do_warn( _("\twould clear inode number in entry at offset %" PRIdPTR "...\n"), (intptr_t)ptr - (intptr_t)d); } } /* * Only complain about illegal names in phase 3 (when inode * discovery is turned on). Otherwise, we'd complain a lot * during phase 4. */ junkit = dep->name[0] == '/'; nm_illegal = !libxfs_dir2_namecheck(dep->name, dep->namelen); if (ino_discovery && nm_illegal) { do_warn( _("entry at block %u offset %" PRIdPTR " in directory inode %" PRIu64 " has illegal name \"%*.*s\": "), da_bno, (intptr_t)ptr - (intptr_t)d, ino, dep->namelen, dep->namelen, dep->name); junkit = 1; } /* * Ensure we write back bad entries for later processing */ if (!no_modify && dep->name[0] == '/') { *dirty = 1; junkit = 0; } /* * Special .. entry processing. */ if (dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.') { if (!*dotdot) { (*dotdot)++; *parent = ent_ino; /* * What if .. == .? Legal only in the root * inode. Blow out entry and set parent to * NULLFSINO otherwise. */ if (ino == ent_ino && ino != mp->m_sb.sb_rootino) { *parent = NULLFSINO; do_warn( _("bad .. entry in directory inode %" PRIu64 ", points to self: "), ino); junkit = 1; } /* * We have to make sure that . == .. in the * root inode. */ else if (ino != ent_ino && ino == mp->m_sb.sb_rootino) { do_warn( _("bad .. entry in root directory inode %" PRIu64 ", was %" PRIu64 ": "), ino, ent_ino); if (!no_modify) { do_warn(_("correcting\n")); dep->inumber = cpu_to_be64(ino); *dirty = 1; } else { do_warn(_("would correct\n")); } *parent = ino; } /* * Make sure our parent directory doesn't point * off into space. */ if (!junkit && *parent != NULLFSINO && !libxfs_verify_ino(mp, *parent)) { do_warn( _("bad .. entry in directory inode %" PRIu64 ", was %" PRIu64 ": "), ino, *parent); if (!no_modify) { do_warn(_("correcting\n")); } else { do_warn(_("would correct\n")); } *parent = NULLFSINO; } } /* * Can't fix the directory unless we know which .. * entry is the right one. Both have valid inode * numbers or we wouldn't be here. So since both * seem equally valid, trash this one. */ else { do_warn( _("multiple .. entries in directory inode %" PRIu64 ": "), ino); junkit = 1; } } /* * Special . entry processing. */ else if (dep->namelen == 1 && dep->name[0] == '.') { if (!*dot) { (*dot)++; if (ent_ino != ino) { do_warn( _("bad . entry in directory inode %" PRIu64 ", was %" PRIu64 ": "), ino, ent_ino); if (!no_modify) { do_warn(_("correcting\n")); dep->inumber = cpu_to_be64(ino); *dirty = 1; } else { do_warn(_("would correct\n")); } } } else { do_warn( _("multiple . entries in directory inode %" PRIu64 ": "), ino); junkit = 1; } } /* * All other entries -- make sure only . references self. */ else if (ent_ino == ino) { do_warn( _("entry \"%*.*s\" in directory inode %" PRIu64 " points to self: "), dep->namelen, dep->namelen, dep->name, ino); junkit = 1; } /* * Clear junked entries. */ if (junkit) { if (!no_modify) { dep->name[0] = '/'; *dirty = 1; do_warn(_("clearing entry\n")); } else { do_warn(_("would clear entry\n")); } } /* * Advance to the next entry. */ ptr += M_DIROPS(mp)->data_entsize(dep->namelen); } /* * Check the bestfree table. */ if (freeseen != 7 || badbest) { do_warn( _("bad bestfree table in block %u in directory inode %" PRIu64 ": "), da_bno, ino); if (!no_modify) { do_warn(_("repairing table\n")); libxfs_dir2_data_freescan_int(mp->m_dir_geo, M_DIROPS(mp), d, &i); *dirty = 1; } else { do_warn(_("would repair table\n")); } } return 0; } /* * Process a block-format directory. */ /* ARGSUSED */ static int process_block_dir2( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, int ino_discovery, int *dino_dirty, /* out - 1 if dinode buffer dirty */ char *dirname, /* directory pathname */ xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ blkmap_t *blkmap, int *dot, /* out - 1 if there is a dot, else 0 */ int *dotdot, /* out - 1 if there's a dotdot, else 0 */ int *repair) /* out - 1 if something was fixed */ { struct xfs_dir2_data_hdr *block; xfs_dir2_leaf_entry_t *blp; bmap_ext_t *bmp; struct xfs_buf *bp; xfs_dir2_block_tail_t *btp; int nex; int rval; bmap_ext_t lbmp; int dirty = 0; *repair = *dot = *dotdot = 0; *parent = NULLFSINO; nex = blkmap_getn(blkmap, mp->m_dir_geo->datablk, mp->m_dir_geo->fsbcount, &bmp, &lbmp); if (nex == 0) { do_warn( _("block %u for directory inode %" PRIu64 " is missing\n"), mp->m_dir_geo->datablk, ino); return 1; } bp = da_read_buf(mp, nex, bmp, &xfs_dir3_block_buf_ops); if (bmp != &lbmp) free(bmp); if (bp == NULL) { do_warn( _("can't read block %u for directory inode %" PRIu64 "\n"), mp->m_dir_geo->datablk, ino); return 1; } /* * Verify the block */ block = bp->b_addr; if (!(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC)) do_warn( _("bad directory block magic # %#x in block %u for directory inode %" PRIu64 "\n"), be32_to_cpu(block->magic), mp->m_dir_geo->datablk, ino); /* * process the data area * this also checks & fixes the bestfree */ btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); blp = xfs_dir2_block_leaf_p(btp); /* * Don't let this go past the end of the block. */ if ((char *)blp > (char *)btp) blp = (xfs_dir2_leaf_entry_t *)btp; rval = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent, bp, dot, dotdot, mp->m_dir_geo->datablk, (char *)blp, &dirty); /* If block looks ok but CRC didn't match, make sure to recompute it. */ if (!rval && bp->b_error == -EFSBADCRC) dirty = 1; if (dirty && !no_modify) { *repair = 1; libxfs_writebuf(bp, 0); } else libxfs_putbuf(bp); return rval; } /* * Validates leaf contents, node format directories only. * magic number and sibling pointers checked by caller. * Returns 0 if block is ok, 1 if the block is bad. * Looking for: out of order hash values, bad stale counts. */ static int process_leaf_block_dir2( xfs_mount_t *mp, xfs_dir2_leaf_t *leaf, xfs_dablk_t da_bno, xfs_ino_t ino, xfs_dahash_t last_hashval, xfs_dahash_t *next_hashval) { int i; int stale; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf); ents = M_DIROPS(mp)->leaf_ents_p(leaf); for (i = stale = 0; i < leafhdr.count; i++) { if ((char *)&ents[i] >= (char *)leaf + mp->m_dir_geo->blksize) { do_warn( _("bad entry count in block %u of directory inode %" PRIu64 "\n"), da_bno, ino); return 1; } if (be32_to_cpu(ents[i].address) == XFS_DIR2_NULL_DATAPTR) stale++; else if (be32_to_cpu(ents[i].hashval) < last_hashval) { do_warn( _("bad hash ordering in block %u of directory inode %" PRIu64 "\n"), da_bno, ino); return 1; } *next_hashval = last_hashval = be32_to_cpu(ents[i].hashval); } if (stale != leafhdr.stale) { do_warn( _("bad stale count in block %u of directory inode %" PRIu64 "\n"), da_bno, ino); return 1; } return 0; } /* * Returns 0 if the directory is ok, 1 if it has to be rebuilt. */ static int process_leaf_level_dir2( xfs_mount_t *mp, da_bt_cursor_t *da_cursor, int *repair) { bmap_ext_t *bmp; struct xfs_buf *bp; int buf_dirty; xfs_dahash_t current_hashval; xfs_dablk_t da_bno; xfs_dahash_t greatest_hashval; xfs_ino_t ino; xfs_dir2_leaf_t *leaf; int nex; xfs_dablk_t prev_bno; bmap_ext_t lbmp; struct xfs_dir3_icleaf_hdr leafhdr; da_bno = da_cursor->level[0].bno; ino = da_cursor->ino; prev_bno = 0; bmp = NULL; current_hashval = 0; greatest_hashval = 0; buf_dirty = 0; do { nex = blkmap_getn(da_cursor->blkmap, da_bno, mp->m_dir_geo->fsbcount, &bmp, &lbmp); /* * Directory code uses 0 as the NULL block pointer since 0 * is the root block and no directory block pointer can point * to the root block of the btree. */ ASSERT(da_bno != 0); if (nex == 0) { do_warn( _("can't map block %u for directory inode %" PRIu64 "\n"), da_bno, ino); goto error_out; } bp = da_read_buf(mp, nex, bmp, &xfs_dir3_leafn_buf_ops); if (bmp != &lbmp) free(bmp); bmp = NULL; if (bp == NULL) { do_warn( _("can't read file block %u for directory inode %" PRIu64 "\n"), da_bno, ino); goto error_out; } leaf = bp->b_addr; M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf); /* * Check magic number for leaf directory btree block. */ if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) { do_warn( _("bad directory leaf magic # %#x for directory inode %" PRIu64 " block %u\n"), leafhdr.magic, ino, da_bno); libxfs_putbuf(bp); goto error_out; } buf_dirty = 0; /* * For each block, process the block, verify its path, * then get next block. Update cursor values along the way. */ if (process_leaf_block_dir2(mp, leaf, da_bno, ino, current_hashval, &greatest_hashval)) { libxfs_putbuf(bp); goto error_out; } /* * Index can be set to hdr.count so match the indices of the * interior blocks -- which at the end of the block will point * to 1 after the final real entry in the block. */ da_cursor->level[0].hashval = greatest_hashval; da_cursor->level[0].bp = bp; da_cursor->level[0].bno = da_bno; da_cursor->level[0].index = leafhdr.count; da_cursor->level[0].dirty = buf_dirty; if (leafhdr.back != prev_bno) { do_warn( _("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"), da_bno, ino); libxfs_putbuf(bp); goto error_out; } prev_bno = da_bno; da_bno = leafhdr.forw; if (da_bno != 0) { if (verify_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) { libxfs_putbuf(bp); goto error_out; } } current_hashval = greatest_hashval; /* * If block looks ok but CRC didn't match, make sure to * recompute it. */ if (!no_modify && bp->b_error == -EFSBADCRC) buf_dirty = 1; ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify)); if (buf_dirty && !no_modify) { *repair = 1; libxfs_writebuf(bp, 0); } else libxfs_putbuf(bp); } while (da_bno != 0); if (verify_final_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) { /* * Verify the final path up (right-hand-side) if still ok. */ do_warn(_("bad hash path in directory %" PRIu64 "\n"), ino); goto error_out; } /* * Redundant but just for testing. */ release_da_cursor(mp, da_cursor, 0); return 0; error_out: /* * Release all buffers holding interior btree blocks. */ err_release_da_cursor(mp, da_cursor, 0); if (bmp && (bmp != &lbmp)) free(bmp); return 1; } /* * Return 1 if the directory's leaf/node space is corrupted and * needs to be rebuilt, 0 if it's ok. */ static int process_node_dir2( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, blkmap_t *blkmap, int *repair) { xfs_dablk_t bno; da_bt_cursor_t da_cursor; /* * Try again -- traverse down left-side of tree until we hit the * left-most leaf block setting up the btree cursor along the way. * Then walk the leaf blocks left-to-right, calling a parent * verification routine each time we traverse a block. */ memset(&da_cursor, 0, sizeof(da_cursor)); da_cursor.ino = ino; da_cursor.dip = dip; da_cursor.blkmap = blkmap; /* * Now process interior node. */ if (traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK) == 0) return 1; /* * Skip directories with a root marked XFS_DIR2_LEAFN_MAGIC * * Be careful here: If any level of the da cursor was filled out then * the directory has a da btree containing an invalid before pointer to * dblock 0, and we should move on to rebuilding the directory. If no * levels in the da cursor got filled out, then we just have a single * leafn block and we're done. */ if (bno == 0) { if (da_cursor.active > 0) { err_release_da_cursor(mp, &da_cursor, 0); return 1; } else { release_da_cursor(mp, &da_cursor, 0); return 0; } } else { /* * Now pass cursor and bno into leaf-block processing routine. * The leaf dir level routine checks the interior paths up to * the root including the final right-most path. */ return process_leaf_level_dir2(mp, &da_cursor, repair); } } /* * Process leaf and node directories. * Process the data blocks then, if it's a node directory, check * the consistency of those blocks. */ static int process_leaf_node_dir2( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, int ino_discovery, char *dirname, /* directory pathname */ xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ blkmap_t *blkmap, int *dot, /* out - 1 if there is a dot, else 0 */ int *dotdot, /* out - 1 if there's a dotdot, else 0 */ int *repair, /* out - 1 if something was fixed */ int isnode) /* node directory not leaf */ { bmap_ext_t *bmp; struct xfs_buf *bp; struct xfs_dir2_data_hdr *data; xfs_fileoff_t dbno; int good; int i; xfs_fileoff_t ndbno; int nex; int t; bmap_ext_t lbmp; int dirty = 0; *repair = *dot = *dotdot = good = 0; *parent = NULLFSINO; ndbno = NULLFILEOFF; while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dir_geo->leafblk) { nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp, &lbmp); /* Advance through map to last dfs block in this dir block */ ndbno = dbno; while (ndbno < dbno + mp->m_dir_geo->fsbcount - 1) { ndbno = blkmap_next_off(blkmap, ndbno, &t); } if (nex == 0) { do_warn( _("block %" PRIu64 " for directory inode %" PRIu64 " is missing\n"), dbno, ino); continue; } bp = da_read_buf(mp, nex, bmp, &xfs_dir3_data_buf_ops); if (bmp != &lbmp) free(bmp); if (bp == NULL) { do_warn( _("can't read block %" PRIu64 " for directory inode %" PRIu64 "\n"), dbno, ino); continue; } data = bp->b_addr; if (!(be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC || be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC)) do_warn( _("bad directory block magic # %#x in block %" PRIu64 " for directory inode %" PRIu64 "\n"), be32_to_cpu(data->magic), dbno, ino); i = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent, bp, dot, dotdot, (xfs_dablk_t)dbno, (char *)data + mp->m_dir_geo->blksize, &dirty); if (i == 0) { good++; /* Maybe just CRC is wrong. Make sure we correct it. */ if (bp->b_error == -EFSBADCRC) dirty = 1; } if (dirty && !no_modify) { *repair = 1; libxfs_writebuf(bp, 0); } else libxfs_putbuf(bp); } if (good == 0) return 1; if (!isnode) return 0; if (dir2_is_badino(ino)) return 0; if (process_node_dir2(mp, ino, dip, blkmap, repair)) dir2_add_badlist(ino); return 0; } /* * Returns 1 if things are bad (directory needs to be junked) * and 0 if things are ok. If ino_discovery is 1, add unknown * inodes to uncertain inode list. */ int process_dir2( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, int ino_discovery, int *dino_dirty, char *dirname, xfs_ino_t *parent, blkmap_t *blkmap) { int dot; int dotdot; xfs_fileoff_t last; int repair; int res; *parent = NULLFSINO; dot = dotdot = 0; last = 0; /* * branch off depending on the type of inode. This routine * is only called ONCE so all the subordinate routines will * fix '.' and junk '..' if they're bogus. */ if (blkmap) last = blkmap_last_off(blkmap); if (be64_to_cpu(dip->di_size) <= XFS_DFORK_DSIZE(dip, mp) && dip->di_format == XFS_DINODE_FMT_LOCAL) { dot = dotdot = 1; res = process_sf_dir2(mp, ino, dip, ino_discovery, dino_dirty, dirname, parent, &repair); } else if (last == mp->m_dir_geo->fsbcount && (dip->di_format == XFS_DINODE_FMT_EXTENTS || dip->di_format == XFS_DINODE_FMT_BTREE)) { res = process_block_dir2(mp, ino, dip, ino_discovery, dino_dirty, dirname, parent, blkmap, &dot, &dotdot, &repair); } else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount && (dip->di_format == XFS_DINODE_FMT_EXTENTS || dip->di_format == XFS_DINODE_FMT_BTREE)) { res = process_leaf_node_dir2(mp, ino, dip, ino_discovery, dirname, parent, blkmap, &dot, &dotdot, &repair, last > mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount); } else { do_warn(_("bad size/format for directory %" PRIu64 "\n"), ino); return 1; } /* * bad . entries in all directories will be fixed up in phase 6 */ if (dot == 0) { do_warn(_("no . entry for directory %" PRIu64 "\n"), ino); } /* * shortform dirs always have a .. entry. .. for all longform * directories will get fixed in phase 6. .. for other shortform * dirs also get fixed there. .. for a shortform root was * fixed in place since we know what it should be */ if (dotdot == 0 && ino != mp->m_sb.sb_rootino) { do_warn(_("no .. entry for directory %" PRIu64 "\n"), ino); } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) { do_warn(_("no .. entry for root directory %" PRIu64 "\n"), ino); need_root_dotdot = 1; } ASSERT((ino != mp->m_sb.sb_rootino && ino != *parent) || (ino == mp->m_sb.sb_rootino && (ino == *parent || need_root_dotdot == 1))); return res; } xfsprogs-5.3.0/repair/dir2.h0000644000175000017500000000104013435336037015541 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XR_DIR2_H #define _XR_DIR2_H struct blkmap; struct bmap_ext; int process_dir2( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, int ino_discovery, int *dirty, char *dirname, xfs_ino_t *parent, struct blkmap *blkmap); void process_sf_dir2_fixi8( struct xfs_mount *mp, struct xfs_dir2_sf_hdr *sfp, xfs_dir2_sf_entry_t **next_sfep); int dir2_is_badino( xfs_ino_t ino); #endif /* _XR_DIR2_H */ xfsprogs-5.3.0/repair/err_protos.h0000644000175000017500000000105413435336037017104 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ /* abort, internal error */ void __attribute__((noreturn)) do_abort(char const *, ...) __attribute__((format(printf,1,2))); /* abort, system error */ void __attribute__((noreturn)) do_error(char const *, ...) __attribute__((format(printf,1,2))); /* issue warning */ void do_warn(char const *, ...) __attribute__((format(printf,1,2))); /* issue log message */ void do_log(char const *, ...) __attribute__((format(printf,1,2))); xfsprogs-5.3.0/repair/globals.c0000644000175000017500000000537513570057155016337 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "globals.h" /* global variables for xfs_repair */ /* arguments and argument flag variables */ char *fs_name; /* name of filesystem */ int verbose; /* verbose flag, mostly for debugging */ /* for reading stuff in manually (bypassing libsim) */ char *iobuf; /* large buffer */ int iobuf_size; char *smallbuf; /* small (1-4 page) buffer */ int smallbuf_size; int sbbuf_size; /* direct I/O info */ int minio_align; /* min I/O size and alignment */ int mem_align; /* memory alignment */ int max_iosize; /* max I/O size */ /* file descriptors */ int fs_fd; /* filesystem fd */ /* command-line flags */ int verbose; int no_modify; int dangerously; /* live dangerously ... fix ro mount */ int isa_file; int zap_log; int dumpcore; /* abort, not exit on fatal errs */ int force_geo; /* can set geo on low confidence info */ int assume_xfs; /* assume we have an xfs fs */ char *log_name; /* Name of log device */ int log_spec; /* Log dev specified as option */ char *rt_name; /* Name of realtime device */ int rt_spec; /* Realtime dev specified as option */ int convert_lazy_count; /* Convert lazy-count mode on/off */ int lazy_count; /* What to set if to if converting */ /* misc status variables */ int primary_sb_modified; int bad_ino_btree; int copied_sunit; int fs_is_dirty; /* for hunting down the root inode */ int need_root_inode; int need_root_dotdot; int need_rbmino; int need_rsumino; int lost_quotas; int have_uquotino; int have_gquotino; int have_pquotino; int lost_uquotino; int lost_gquotino; int lost_pquotino; xfs_agino_t first_prealloc_ino; xfs_agino_t last_prealloc_ino; xfs_agblock_t bnobt_root; xfs_agblock_t bcntbt_root; xfs_agblock_t inobt_root; /* configuration vars -- fs geometry dependent */ int inodes_per_block; unsigned int glob_agcount; int chunks_pblock; /* # of 64-ino chunks per allocation */ int max_symlink_blocks; int64_t fs_max_file_offset; /* realtime info */ xfs_rtword_t *btmcompute; xfs_suminfo_t *sumcompute; /* inode tree records have full or partial backptr fields ? */ int full_ino_ex_data; /* * if 1, use ino_ex_data_t component * of ino_un union, if 0, use * parent_list_t component. see * incore.h for more details */ #define ORPHANAGE "lost+found" /* superblock counters */ uint64_t sb_icount; /* allocated (made) inodes */ uint64_t sb_ifree; /* free inodes */ uint64_t sb_fdblocks; /* free data blocks */ uint64_t sb_frextents; /* free realtime extents */ /* superblock geometry info */ xfs_extlen_t sb_inoalignmt; uint32_t sb_unit; uint32_t sb_width; struct aglock *ag_locks; int report_interval; uint64_t *prog_rpt_done; int ag_stride; int thread_count; xfsprogs-5.3.0/repair/globals.h0000644000175000017500000001174513570057155016342 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XFS_REPAIR_GLOBAL_H #define _XFS_REPAIR_GLOBAL_H #include "libxfs.h" /* useful macros */ #define rounddown(x, y) (((x)/(y))*(y)) /* error flags */ #define XR_OK 0 /* good */ #define XR_BAD_MAGIC 1 /* bad magic number */ #define XR_BAD_BLOCKSIZE 2 /* bad block size */ #define XR_BAD_BLOCKLOG 3 /* bad sb_blocklog field */ #define XR_BAD_VERSION 4 /* bad version number */ #define XR_BAD_INPROGRESS 5 /* in progress set */ #define XR_BAD_FS_SIZE_DATA 6 /* ag sizes, number, fs size mismatch */ #define XR_BAD_INO_SIZE_DATA 7 /* bad inode size or perblock fields */ #define XR_BAD_SECT_SIZE_DATA 8 /* bad sector size info */ #define XR_AGF_GEO_MISMATCH 9 /* agf info conflicts with sb */ #define XR_AGI_GEO_MISMATCH 10 /* agf info conflicts with sb */ #define XR_SB_GEO_MISMATCH 11 /* sb geo conflicts with fs sb geo */ #define XR_EOF 12 /* seeked beyond EOF */ #define XR_BAD_RT_GEO_DATA 13 /* realtime geometry inconsistent */ #define XR_BAD_INO_MAX_PCT 14 /* max % of inodes > 100% */ #define XR_BAD_INO_ALIGN 15 /* bad inode alignment value */ #define XR_INSUFF_SEC_SB 16 /* not enough matching secondary sbs */ #define XR_BAD_SB_UNIT 17 /* bad stripe unit */ #define XR_BAD_SB_WIDTH 18 /* bad stripe width */ #define XR_BAD_SVN 19 /* bad shared version number */ #define XR_BAD_CRC 20 /* Bad CRC */ #define XR_BAD_DIR_SIZE_DATA 21 /* Bad directory geometry */ #define XR_BAD_LOG_GEOMETRY 22 /* Bad log geometry */ #define XR_BAD_ERR_CODE 23 /* Bad error code */ /* XFS filesystem (il)legal values */ #define XR_LOG2BSIZE_MIN 9 /* min/max fs blocksize (log2) */ #define XR_LOG2BSIZE_MAX 16 /* 2^XR_* == blocksize */ #define NUM_AGH_SECTS 4 /* # of components in an ag header */ /* global variables for xfs_repair */ /* arguments and argument flag variables */ extern char *fs_name; /* name of filesystem */ extern int verbose; /* verbose flag, mostly for debugging */ /* for reading stuff in manually (bypassing libsim) */ extern char *iobuf; /* large buffer */ extern int iobuf_size; extern char *smallbuf; /* small (1-4 page) buffer */ extern int smallbuf_size; extern int sbbuf_size; /* direct I/O info */ extern int minio_align; /* min I/O size and alignment */ extern int mem_align; /* memory alignment */ extern int max_iosize; /* max I/O size */ /* file descriptors */ extern int fs_fd; /* filesystem fd */ /* command-line flags */ extern int verbose; extern int no_modify; extern int dangerously; /* live dangerously ... fix ro mount */ extern int isa_file; extern int zap_log; extern int dumpcore; /* abort, not exit on fatal errs */ extern int force_geo; /* can set geo on low confidence info */ extern int assume_xfs; /* assume we have an xfs fs */ extern char *log_name; /* Name of log device */ extern int log_spec; /* Log dev specified as option */ extern char *rt_name; /* Name of realtime device */ extern int rt_spec; /* Realtime dev specified as option */ extern int convert_lazy_count; /* Convert lazy-count mode on/off */ extern int lazy_count; /* What to set if to if converting */ /* misc status variables */ extern int primary_sb_modified; extern int bad_ino_btree; extern int copied_sunit; extern int fs_is_dirty; /* for hunting down the root inode */ extern int need_root_inode; extern int need_root_dotdot; extern int need_rbmino; extern int need_rsumino; extern int lost_quotas; extern int have_uquotino; extern int have_gquotino; extern int have_pquotino; extern int lost_uquotino; extern int lost_gquotino; extern int lost_pquotino; extern xfs_agino_t first_prealloc_ino; extern xfs_agino_t last_prealloc_ino; extern xfs_agblock_t bnobt_root; extern xfs_agblock_t bcntbt_root; extern xfs_agblock_t inobt_root; /* configuration vars -- fs geometry dependent */ extern int inodes_per_block; extern unsigned int glob_agcount; extern int chunks_pblock; /* # of 64-ino chunks per allocation */ extern int max_symlink_blocks; extern int64_t fs_max_file_offset; /* realtime info */ extern xfs_rtword_t *btmcompute; extern xfs_suminfo_t *sumcompute; /* inode tree records have full or partial backptr fields ? */ extern int full_ino_ex_data;/* * if 1, use ino_ex_data_t component * of ino_un union, if 0, use * parent_list_t component. see * incore.h for more details */ #define ORPHANAGE "lost+found" /* superblock counters */ extern uint64_t sb_icount; /* allocated (made) inodes */ extern uint64_t sb_ifree; /* free inodes */ extern uint64_t sb_fdblocks; /* free data blocks */ extern uint64_t sb_frextents; /* free realtime extents */ /* superblock geometry info */ extern xfs_extlen_t sb_inoalignmt; extern uint32_t sb_unit; extern uint32_t sb_width; struct aglock { pthread_mutex_t lock __attribute__((__aligned__(64))); }; extern struct aglock *ag_locks; extern int report_interval; extern uint64_t *prog_rpt_done; extern int ag_stride; extern int thread_count; #endif /* _XFS_REPAIR_GLOBAL_H */ xfsprogs-5.3.0/repair/incore.c0000644000175000017500000001527713435336037016174 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "btree.h" #include "globals.h" #include "incore.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" #include "threads.h" /* * The following manages the in-core bitmap of the entire filesystem * using extents in a btree. * * The btree items will point to one of the state values below, * rather than storing the value itself in the pointer. */ static int states[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; static struct btree_root **ag_bmap; static void update_bmap( struct btree_root *bmap, unsigned long offset, xfs_extlen_t blen, void *new_state) { unsigned long end = offset + blen; int *cur_state; unsigned long cur_key; int *next_state; unsigned long next_key; int *prev_state; cur_state = btree_find(bmap, offset, &cur_key); if (!cur_state) return; if (offset == cur_key) { /* if the start is the same as the "item" extent */ if (cur_state == new_state) return; /* * Note: this may be NULL if we are updating the map for * the superblock. */ prev_state = btree_peek_prev(bmap, NULL); next_state = btree_peek_next(bmap, &next_key); if (next_key > end) { /* different end */ if (new_state == prev_state) { /* #1: prev has same state, move offset up */ btree_update_key(bmap, offset, end); return; } /* #4: insert new extent after, update current value */ btree_update_value(bmap, offset, new_state); btree_insert(bmap, end, cur_state); return; } /* same end (and same start) */ if (new_state == next_state) { /* next has same state */ if (new_state == prev_state) { /* #3: merge prev & next */ btree_delete(bmap, offset); btree_delete(bmap, end); return; } /* #8: merge next */ btree_update_value(bmap, offset, new_state); btree_delete(bmap, end); return; } /* same start, same end, next has different state */ if (new_state == prev_state) { /* #5: prev has same state */ btree_delete(bmap, offset); return; } /* #6: update value only */ btree_update_value(bmap, offset, new_state); return; } /* different start, offset is in the middle of "cur" */ prev_state = btree_peek_prev(bmap, NULL); ASSERT(prev_state != NULL); if (prev_state == new_state) return; if (end == cur_key) { /* end is at the same point as the current extent */ if (new_state == cur_state) { /* #7: move next extent down */ btree_update_key(bmap, end, offset); return; } /* #9: different start, same end, add new extent */ btree_insert(bmap, offset, new_state); return; } /* #2: insert an extent into the middle of another extent */ btree_insert(bmap, offset, new_state); btree_insert(bmap, end, prev_state); } void set_bmap_ext( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t blen, int state) { update_bmap(ag_bmap[agno], agbno, blen, &states[state]); } int get_bmap_ext( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t maxbno, xfs_extlen_t *blen) { int *statep; unsigned long key; statep = btree_find(ag_bmap[agno], agbno, &key); if (!statep) return -1; if (key == agbno) { if (blen) { if (!btree_peek_next(ag_bmap[agno], &key)) return -1; *blen = min(maxbno, key) - agbno; } return *statep; } statep = btree_peek_prev(ag_bmap[agno], NULL); if (!statep) return -1; if (blen) *blen = min(maxbno, key) - agbno; return *statep; } static uint64_t *rt_bmap; static size_t rt_bmap_size; /* block records fit into uint64_t's units */ #define XR_BB_UNIT 64 /* number of bits/unit */ #define XR_BB 4 /* bits per block record */ #define XR_BB_NUM (XR_BB_UNIT/XR_BB) /* number of records per unit */ #define XR_BB_MASK 0xF /* block record mask */ /* * these work in real-time extents (e.g. fsbno == rt extent number) */ int get_rtbmap( xfs_rtblock_t bno) { return (*(rt_bmap + bno / XR_BB_NUM) >> ((bno % XR_BB_NUM) * XR_BB)) & XR_BB_MASK; } void set_rtbmap( xfs_rtblock_t bno, int state) { *(rt_bmap + bno / XR_BB_NUM) = ((*(rt_bmap + bno / XR_BB_NUM) & (~((uint64_t) XR_BB_MASK << ((bno % XR_BB_NUM) * XR_BB)))) | (((uint64_t) state) << ((bno % XR_BB_NUM) * XR_BB))); } static void reset_rt_bmap(void) { if (rt_bmap) memset(rt_bmap, 0x22, rt_bmap_size); /* XR_E_FREE */ } static void init_rt_bmap( xfs_mount_t *mp) { if (mp->m_sb.sb_rextents == 0) return; rt_bmap_size = roundup(mp->m_sb.sb_rextents / (NBBY / XR_BB), sizeof(uint64_t)); rt_bmap = memalign(sizeof(uint64_t), rt_bmap_size); if (!rt_bmap) { do_error( _("couldn't allocate realtime block map, size = %" PRIu64 "\n"), mp->m_sb.sb_rextents); return; } } static void free_rt_bmap(xfs_mount_t *mp) { free(rt_bmap); rt_bmap = NULL; } void reset_bmaps(xfs_mount_t *mp) { xfs_agnumber_t agno; xfs_agblock_t ag_size; int ag_hdr_block; ag_hdr_block = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize); ag_size = mp->m_sb.sb_agblocks; for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { if (agno == mp->m_sb.sb_agcount - 1) ag_size = (xfs_extlen_t)(mp->m_sb.sb_dblocks - (xfs_rfsblock_t)mp->m_sb.sb_agblocks * agno); #ifdef BTREE_STATS if (btree_find(ag_bmap[agno], 0, NULL)) { printf("ag_bmap[%d] btree stats:\n", i); btree_print_stats(ag_bmap[agno], stdout); } #endif /* * We always insert an item for the first block having a * given state. So the code below means: * * block 0..ag_hdr_block-1: XR_E_INUSE_FS * ag_hdr_block..ag_size: XR_E_UNKNOWN * ag_size... XR_E_BAD_STATE */ btree_clear(ag_bmap[agno]); btree_insert(ag_bmap[agno], 0, &states[XR_E_INUSE_FS]); btree_insert(ag_bmap[agno], ag_hdr_block, &states[XR_E_UNKNOWN]); btree_insert(ag_bmap[agno], ag_size, &states[XR_E_BAD_STATE]); } if (mp->m_sb.sb_logstart != 0) { set_bmap_ext(XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart), XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart), mp->m_sb.sb_logblocks, XR_E_INUSE_FS); } reset_rt_bmap(); } void init_bmaps(xfs_mount_t *mp) { xfs_agnumber_t i; ag_bmap = calloc(mp->m_sb.sb_agcount, sizeof(struct btree_root *)); if (!ag_bmap) do_error(_("couldn't allocate block map btree roots\n")); ag_locks = calloc(mp->m_sb.sb_agcount, sizeof(struct aglock)); if (!ag_locks) do_error(_("couldn't allocate block map locks\n")); for (i = 0; i < mp->m_sb.sb_agcount; i++) { btree_init(&ag_bmap[i]); pthread_mutex_init(&ag_locks[i].lock, NULL); } init_rt_bmap(mp); reset_bmaps(mp); } void free_bmaps(xfs_mount_t *mp) { xfs_agnumber_t i; for (i = 0; i < mp->m_sb.sb_agcount; i++) btree_destroy(ag_bmap[i]); free(ag_bmap); ag_bmap = NULL; free_rt_bmap(mp); } xfsprogs-5.3.0/repair/incore.h0000644000175000017500000004373413435336037016200 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef XFS_REPAIR_INCORE_H #define XFS_REPAIR_INCORE_H #include "avl.h" /* * contains definition information. implementation (code) * is spread out in separate files. */ /* * block map -- track state of each filesystem block. */ void init_bmaps(xfs_mount_t *mp); void reset_bmaps(xfs_mount_t *mp); void free_bmaps(xfs_mount_t *mp); void set_bmap_ext(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t blen, int state); int get_bmap_ext(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t maxbno, xfs_extlen_t *blen); void set_rtbmap(xfs_rtblock_t bno, int state); int get_rtbmap(xfs_rtblock_t bno); static inline void set_bmap(xfs_agnumber_t agno, xfs_agblock_t agbno, int state) { set_bmap_ext(agno, agbno, 1, state); } static inline int get_bmap(xfs_agnumber_t agno, xfs_agblock_t agbno) { return get_bmap_ext(agno, agbno, agbno + 1, NULL); } /* * extent tree definitions * right now, there are 3 trees per AG, a bno tree, a bcnt tree * and a tree for dup extents. If the code is modified in the * future to use an extent tree instead of a bitmask for tracking * fs blocks, then we could lose the dup extent tree if we labelled * each extent with the inode that owned it. */ typedef unsigned char extent_state_t; typedef struct extent_tree_node { avlnode_t avl_node; xfs_agblock_t ex_startblock; /* starting block (agbno) */ xfs_extlen_t ex_blockcount; /* number of blocks in extent */ extent_state_t ex_state; /* see state flags below */ struct extent_tree_node *next; /* for bcnt extent lists */ struct extent_tree_node *last; /* for bcnt extent list anchors */ #if 0 xfs_ino_t ex_inode; /* owner, NULL if free or */ /* multiply allocated */ #endif } extent_tree_node_t; typedef struct rt_extent_tree_node { avlnode_t avl_node; xfs_rtblock_t rt_startblock; /* starting realtime block */ xfs_extlen_t rt_blockcount; /* number of blocks in extent */ extent_state_t rt_state; /* see state flags below */ #if 0 xfs_ino_t ex_inode; /* owner, NULL if free or */ /* multiply allocated */ #endif } rt_extent_tree_node_t; /* extent states, prefix with XR_ to avoid conflict with buffer cache defines */ #define XR_E_UNKNOWN 0 /* unknown state */ #define XR_E_FREE1 1 /* free block (marked by one fs space tree) */ #define XR_E_FREE 2 /* free block (marked by both fs space trees) */ #define XR_E_INUSE 3 /* extent used by file/dir data or metadata */ #define XR_E_INUSE_FS 4 /* extent used by fs ag header or log */ #define XR_E_MULT 5 /* extent is multiply referenced */ #define XR_E_INO 6 /* extent used by inodes (inode blocks) */ #define XR_E_FS_MAP 7 /* extent used by fs space/inode maps */ #define XR_E_INUSE1 8 /* used block (marked by rmap btree) */ #define XR_E_INUSE_FS1 9 /* used by fs ag header or log (rmap btree) */ #define XR_E_INO1 10 /* used by inodes (marked by rmap btree) */ #define XR_E_FS_MAP1 11 /* used by fs space/inode maps (rmap btree) */ #define XR_E_REFC 12 /* used by fs ag reference count btree */ #define XR_E_COW 13 /* leftover cow extent */ #define XR_E_BAD_STATE 14 /* separate state bit, OR'ed into high (4th) bit of ex_state field */ #define XR_E_WRITTEN 0x8 /* extent has been written out, can't reclaim */ #define written(state) ((state) & XR_E_WRITTEN) #define set_written(state) (state) &= XR_E_WRITTEN /* * bno extent tree functions */ void add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount); extent_tree_node_t * findfirst_bno_extent(xfs_agnumber_t agno); extent_tree_node_t * find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t agbno); extent_tree_node_t * findfirst_bno_extent(xfs_agnumber_t agno); #define findnext_bno_extent(exent_ptr) \ ((extent_tree_node_t *) ((exent_ptr)->avl_node.avl_nextino)) void get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext); /* * bcnt tree functions */ void add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount); extent_tree_node_t * findfirst_bcnt_extent(xfs_agnumber_t agno); extent_tree_node_t * find_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t agbno); extent_tree_node_t * findbiggest_bcnt_extent(xfs_agnumber_t agno); extent_tree_node_t * findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext); extent_tree_node_t * get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount); /* * duplicate extent tree functions */ int add_dup_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount); int search_dup_extent(xfs_agnumber_t agno, xfs_agblock_t start_agbno, xfs_agblock_t end_agbno); void add_rt_dup_extent(xfs_rtblock_t startblock, xfs_extlen_t blockcount); int search_rt_dup_extent(xfs_mount_t *mp, xfs_rtblock_t bno); /* * extent/tree recyling and deletion routines */ /* * return an extent node to the extent node free list */ void release_extent_tree_node(extent_tree_node_t *node); /* * recycle all the nodes in the per-AG tree */ void release_dup_extent_tree(xfs_agnumber_t agno); void release_agbno_extent_tree(xfs_agnumber_t agno); void release_agbcnt_extent_tree(xfs_agnumber_t agno); /* * realtime duplicate extent tree - this one actually frees the memory */ void free_rt_dup_extent_tree(xfs_mount_t *mp); void incore_ext_init(xfs_mount_t *); /* * per-AG extent trees shutdown routine -- all (bno, bcnt and dup) * at once. this one actually frees the memory instead of just recyling * the nodes. */ void incore_ext_teardown(xfs_mount_t *mp); void incore_ino_init(xfs_mount_t *); int count_bno_extents(xfs_agnumber_t); int count_bno_extents_blocks(xfs_agnumber_t, uint *); int count_bcnt_extents(xfs_agnumber_t); /* * inode definitions */ /* inode types */ #define XR_INO_UNKNOWN 0 /* unknown */ #define XR_INO_DIR 1 /* directory */ #define XR_INO_RTDATA 2 /* realtime file */ #define XR_INO_RTBITMAP 3 /* realtime bitmap inode */ #define XR_INO_RTSUM 4 /* realtime summary inode */ #define XR_INO_DATA 5 /* regular file */ #define XR_INO_SYMLINK 6 /* symlink */ #define XR_INO_CHRDEV 7 /* character device */ #define XR_INO_BLKDEV 8 /* block device */ #define XR_INO_SOCK 9 /* socket */ #define XR_INO_FIFO 10 /* fifo */ #define XR_INO_MOUNTPOINT 11 /* mountpoint */ #define XR_INO_UQUOTA 12 /* user quota inode */ #define XR_INO_GQUOTA 13 /* group quota inode */ #define XR_INO_PQUOTA 14 /* project quota inode */ /* inode allocation tree */ /* * Inodes in the inode allocation trees are allocated in chunks. * Those groups can be easily duplicated in our trees. * Disconnected inodes are harder. We can do one of two * things in that case: if we know the inode allocation btrees * are good, then we can disallow directory references to unknown * inode chunks. If the inode allocation trees have been trashed or * we feel like being aggressive, then as we hit unknown inodes, * we can search on the disk for all contiguous inodes and see if * they fit into chunks. Before putting them into the inode tree, * we can scan each inode starting at the earliest inode to see which * ones are good. This protects us from the pathalogical case of * inodes appearing in user-data. We still may have to mark the * inodes as "possibly fake" so that if a file claims the blocks, * we decide to believe the inodes, especially if they're not * connected. */ #define PLIST_CHUNK_SIZE 4 typedef xfs_ino_t parent_entry_t; struct nlink_ops; typedef struct parent_list { uint64_t pmask; parent_entry_t *pentries; #ifdef DEBUG short cnt; #endif } parent_list_t; union ino_nlink { uint8_t *un8; uint16_t *un16; uint32_t *un32; }; typedef struct ino_ex_data { uint64_t ino_reached; /* bit == 1 if reached */ uint64_t ino_processed; /* reference checked bit mask */ parent_list_t *parents; union ino_nlink counted_nlinks;/* counted nlinks in P6 */ } ino_ex_data_t; typedef struct ino_tree_node { avlnode_t avl_node; xfs_agino_t ino_startnum; /* starting inode # */ xfs_inofree_t ir_free; /* inode free bit mask */ uint64_t ir_sparse; /* sparse inode bitmask */ uint64_t ino_confirmed; /* confirmed bitmask */ uint64_t ino_isa_dir; /* bit == 1 if a directory */ uint64_t ino_was_rl; /* bit == 1 if reflink flag set */ uint64_t ino_is_rl; /* bit == 1 if reflink flag should be set */ uint8_t nlink_size; union ino_nlink disk_nlinks; /* on-disk nlinks, set in P3 */ union { ino_ex_data_t *ex_data; /* phases 6,7 */ parent_list_t *plist; /* phases 2-5 */ } ino_un; uint8_t *ftypes; /* phases 3,6 */ } ino_tree_node_t; #define INOS_PER_IREC (sizeof(uint64_t) * NBBY) #define IREC_MASK(i) ((uint64_t)1 << (i)) void add_ino_ex_data(xfs_mount_t *mp); /* * return an inode record to the free inode record pool */ void free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec); /* * get pulls the inode record from the good inode tree */ void get_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, ino_tree_node_t *ino_rec); extern avltree_desc_t **inode_tree_ptrs; static inline int get_inode_offset(struct xfs_mount *mp, xfs_ino_t ino, ino_tree_node_t *irec) { return XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum; } static inline ino_tree_node_t * findfirst_inode_rec(xfs_agnumber_t agno) { return((ino_tree_node_t *) inode_tree_ptrs[agno]->avl_firstino); } static inline ino_tree_node_t * find_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino) { /* * Is the AG inside the file system */ if (agno >= mp->m_sb.sb_agcount) return NULL; return((ino_tree_node_t *) avl_findrange(inode_tree_ptrs[agno], ino)); } void find_inode_rec_range(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t start_ino, xfs_agino_t end_ino, ino_tree_node_t **first, ino_tree_node_t **last); /* * set inode states -- setting an inode to used or free also * automatically marks it as "existing". Note -- all the inode * add/set/get routines assume a valid inode number. */ ino_tree_node_t *set_inode_used_alloc(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino); ino_tree_node_t *set_inode_free_alloc(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino); void print_inode_list(xfs_agnumber_t agno); void print_uncertain_inode_list(xfs_agnumber_t agno); /* * separate trees for uncertain inodes (they may not exist). */ ino_tree_node_t *findfirst_uncertain_inode_rec(xfs_agnumber_t agno); ino_tree_node_t *find_uncertain_inode_rec(xfs_agnumber_t agno, xfs_agino_t ino); void add_inode_uncertain(xfs_mount_t *mp, xfs_ino_t ino, int free); void add_aginode_uncertain(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino, int free); void get_uncertain_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, ino_tree_node_t *ino_rec); void clear_uncertain_ino_cache(xfs_agnumber_t agno); /* * return next in-order inode tree node. takes an "ino_tree_node_t *" */ #define next_ino_rec(ino_node_ptr) \ ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_nextino)) /* * return the next linked inode (forward avl tree link)-- meant to be used * by linked list routines (uncertain inode routines/records) */ #define next_link_rec(ino_node_ptr) \ ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_forw)) /* * finobt helpers */ static inline bool inode_rec_has_free(struct ino_tree_node *ino_rec) { /* must have real, allocated inodes for finobt */ return ino_rec->ir_free & ~ino_rec->ir_sparse; } static inline ino_tree_node_t * findfirst_free_inode_rec(xfs_agnumber_t agno) { ino_tree_node_t *ino_rec; ino_rec = findfirst_inode_rec(agno); while (ino_rec && !inode_rec_has_free(ino_rec)) ino_rec = next_ino_rec(ino_rec); return ino_rec; } static inline ino_tree_node_t * next_free_ino_rec(ino_tree_node_t *ino_rec) { ino_rec = next_ino_rec(ino_rec); while (ino_rec && !inode_rec_has_free(ino_rec)) ino_rec = next_ino_rec(ino_rec); return ino_rec; } /* * Has an inode been processed for phase 6 (reference count checking)? * * add_inode_refchecked() is set on an inode when it gets traversed * during the reference count phase (6). It's set so that if the inode * is a directory, it's traversed (and it's links counted) only once. */ static inline void add_inode_refchecked(struct ino_tree_node *irec, int offset) { irec->ino_un.ex_data->ino_processed |= IREC_MASK(offset); } static inline int is_inode_refchecked(struct ino_tree_node *irec, int offset) { return (irec->ino_un.ex_data->ino_processed & IREC_MASK(offset)) != 0; } /* * set/test is inode known to be valid (although perhaps corrupt) */ static inline void set_inode_confirmed(struct ino_tree_node *irec, int offset) { irec->ino_confirmed |= IREC_MASK(offset); } static inline int is_inode_confirmed(struct ino_tree_node *irec, int offset) { return (irec->ino_confirmed & IREC_MASK(offset)) != 0; } /* * set/clear/test is inode a directory inode */ static inline void set_inode_isadir(struct ino_tree_node *irec, int offset) { irec->ino_isa_dir |= IREC_MASK(offset); } static inline void clear_inode_isadir(struct ino_tree_node *irec, int offset) { irec->ino_isa_dir &= ~IREC_MASK(offset); } static inline int inode_isadir(struct ino_tree_node *irec, int offset) { return (irec->ino_isa_dir & IREC_MASK(offset)) != 0; } /* * set/clear/test is inode free or used */ static inline void set_inode_free(struct ino_tree_node *irec, int offset) { set_inode_confirmed(irec, offset); irec->ir_free |= XFS_INOBT_MASK(offset); } static inline void set_inode_used(struct ino_tree_node *irec, int offset) { set_inode_confirmed(irec, offset); irec->ir_free &= ~XFS_INOBT_MASK(offset); } static inline int is_inode_free(struct ino_tree_node *irec, int offset) { return (irec->ir_free & XFS_INOBT_MASK(offset)) != 0; } /* * set/test is inode sparse (not physically allocated) */ static inline void set_inode_sparse(struct ino_tree_node *irec, int offset) { irec->ir_sparse |= XFS_INOBT_MASK(offset); } static inline bool is_inode_sparse(struct ino_tree_node *irec, int offset) { return irec->ir_sparse & XFS_INOBT_MASK(offset); } /* * set/clear/test was inode marked as reflinked */ static inline void set_inode_was_rl(struct ino_tree_node *irec, int offset) { irec->ino_was_rl |= IREC_MASK(offset); } static inline void clear_inode_was_rl(struct ino_tree_node *irec, int offset) { irec->ino_was_rl &= ~IREC_MASK(offset); } static inline int inode_was_rl(struct ino_tree_node *irec, int offset) { return (irec->ino_was_rl & IREC_MASK(offset)) != 0; } /* * set/clear/test should inode be marked as reflinked */ static inline void set_inode_is_rl(struct ino_tree_node *irec, int offset) { irec->ino_is_rl |= IREC_MASK(offset); } static inline void clear_inode_is_rl(struct ino_tree_node *irec, int offset) { irec->ino_is_rl &= ~IREC_MASK(offset); } static inline int inode_is_rl(struct ino_tree_node *irec, int offset) { return (irec->ino_is_rl & IREC_MASK(offset)) != 0; } /* * add_inode_reached() is set on inode I only if I has been reached * by an inode P claiming to be the parent and if I is a directory, * the .. link in the I says that P is I's parent. * * add_inode_ref() is called every time a link to an inode is * detected and drop_inode_ref() is called every time a link to * an inode that we've counted is removed. */ void add_inode_ref(struct ino_tree_node *irec, int offset); void drop_inode_ref(struct ino_tree_node *irec, int offset); uint32_t num_inode_references(struct ino_tree_node *irec, int offset); void set_inode_disk_nlinks(struct ino_tree_node *irec, int offset, uint32_t nlinks); uint32_t get_inode_disk_nlinks(struct ino_tree_node *irec, int offset); static inline int is_inode_reached(struct ino_tree_node *irec, int offset) { ASSERT(irec->ino_un.ex_data != NULL); return (irec->ino_un.ex_data->ino_reached & IREC_MASK(offset)) != 0; } static inline void add_inode_reached(struct ino_tree_node *irec, int offset) { add_inode_ref(irec, offset); irec->ino_un.ex_data->ino_reached |= IREC_MASK(offset); } /* * get/set inode filetype. Only used if the superblock feature bit is set * which allocates irec->ftypes. */ static inline void set_inode_ftype(struct ino_tree_node *irec, int ino_offset, uint8_t ftype) { if (irec->ftypes) irec->ftypes[ino_offset] = ftype; } static inline uint8_t get_inode_ftype( struct ino_tree_node *irec, int ino_offset) { if (!irec->ftypes) return XFS_DIR3_FT_UNKNOWN; return irec->ftypes[ino_offset]; } /* * set/get inode number of parent -- works for directory inodes only */ void set_inode_parent(ino_tree_node_t *irec, int ino_offset, xfs_ino_t ino); xfs_ino_t get_inode_parent(ino_tree_node_t *irec, int ino_offset); /* * Allocate extra inode data */ void alloc_ex_data(ino_tree_node_t *irec); /* * bmap cursor for tracking and fixing bmap btrees. All xfs btrees number * the levels with 0 being the leaf and every level up being 1 greater. */ #define XR_MAX_BMLEVELS 10 /* XXX - rcc need to verify number */ typedef struct bm_level_state { xfs_fsblock_t fsbno; xfs_fsblock_t left_fsbno; xfs_fsblock_t right_fsbno; uint64_t first_key; uint64_t last_key; /* int level; uint64_t prev_last_key; xfs_buf_t *bp; xfs_bmbt_block_t *block; */ } bm_level_state_t; typedef struct bm_cursor { int num_levels; xfs_ino_t ino; xfs_dinode_t *dip; bm_level_state_t level[XR_MAX_BMLEVELS]; } bmap_cursor_t; void init_bm_cursor(bmap_cursor_t *cursor, int num_level); /* * On-disk inobt record helpers. The sparse inode record format has a single * byte freecount. The older format has a 32-bit freecount and thus byte * conversion is necessary. */ static inline int inorec_get_freecount( struct xfs_mount *mp, struct xfs_inobt_rec *rp) { if (xfs_sb_version_hassparseinodes(&mp->m_sb)) return rp->ir_u.sp.ir_freecount; return be32_to_cpu(rp->ir_u.f.ir_freecount); } static inline void inorec_set_freecount( struct xfs_mount *mp, struct xfs_inobt_rec *rp, int freecount) { if (xfs_sb_version_hassparseinodes(&mp->m_sb)) rp->ir_u.sp.ir_freecount = freecount; else rp->ir_u.f.ir_freecount = cpu_to_be32(freecount); } #endif /* XFS_REPAIR_INCORE_H */ xfsprogs-5.3.0/repair/incore_bmc.c0000644000175000017500000000130313435336037016776 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "incore.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" void init_bm_cursor(bmap_cursor_t *cursor, int num_levels) { int i; memset(cursor, 0, sizeof(bmap_cursor_t)); cursor->ino = NULLFSINO; cursor->num_levels = num_levels; for (i = 0; i < XR_MAX_BMLEVELS; i++) { cursor->level[i].fsbno = NULLFSBLOCK; cursor->level[i].right_fsbno = NULLFSBLOCK; cursor->level[i].left_fsbno = NULLFSBLOCK; cursor->level[i].first_key = NULLFILEOFF; cursor->level[i].last_key = NULLFILEOFF; } } xfsprogs-5.3.0/repair/incore_ext.c0000644000175000017500000004767013570057155017057 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "btree.h" #include "globals.h" #include "incore.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" #include "libfrog/avl64.h" #include "threads.h" /* * note: there are 4 sets of incore things handled here: * block bitmaps, extent trees, uncertain inode list, * and inode tree. The tree-based code uses the AVL * tree package used by the IRIX kernel VM code * (sys/avl.h). The inode list code uses the same records * as the inode tree code for convenience. The bitmaps * and bitmap operators are mostly macros defined in incore.h. * There are one of everything per AG except for extent * trees. There's one duplicate extent tree, one bno and * one bcnt extent tree per AG. Not all of the above exist * through all phases. The duplicate extent tree gets trashed * at the end of phase 4. The bno/bcnt trees don't appear until * phase 5. The uncertain inode list goes away at the end of * phase 3. The inode tree and bno/bnct trees go away after phase 5. */ static avl64tree_desc_t *rt_ext_tree_ptr; /* dup extent tree for rt */ static pthread_mutex_t rt_ext_tree_lock; static struct btree_root **dup_extent_trees; /* per ag dup extent trees */ static pthread_mutex_t *dup_extent_tree_locks; static avltree_desc_t **extent_bno_ptrs; /* * array of extent tree ptrs * one per ag for free extents * sorted by starting block * number */ static avltree_desc_t **extent_bcnt_ptrs; /* * array of extent tree ptrs * one per ag for free extents * sorted by size */ /* * duplicate extent tree functions */ void release_dup_extent_tree( xfs_agnumber_t agno) { pthread_mutex_lock(&dup_extent_tree_locks[agno]); btree_clear(dup_extent_trees[agno]); pthread_mutex_unlock(&dup_extent_tree_locks[agno]); } int add_dup_extent( xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount) { int ret; #ifdef XR_DUP_TRACE fprintf(stderr, "Adding dup extent - %d/%d %d\n", agno, startblock, blockcount); #endif pthread_mutex_lock(&dup_extent_tree_locks[agno]); ret = btree_insert(dup_extent_trees[agno], startblock, (void *)(uintptr_t)(startblock + blockcount)); pthread_mutex_unlock(&dup_extent_tree_locks[agno]); return ret; } int search_dup_extent( xfs_agnumber_t agno, xfs_agblock_t start_agbno, xfs_agblock_t end_agbno) { unsigned long bno; int ret; pthread_mutex_lock(&dup_extent_tree_locks[agno]); if (!btree_find(dup_extent_trees[agno], start_agbno, &bno)) { ret = 0; goto out; /* this really shouldn't happen */ } if (bno < end_agbno) { ret = 1; goto out; } ret = (uintptr_t)btree_peek_prev(dup_extent_trees[agno], NULL) > start_agbno; out: pthread_mutex_unlock(&dup_extent_tree_locks[agno]); return ret; } /* * extent tree stuff is avl trees of duplicate extents, * sorted in order by block number. there is one tree per ag. */ static extent_tree_node_t * mk_extent_tree_nodes(xfs_agblock_t new_startblock, xfs_extlen_t new_blockcount, extent_state_t new_state) { extent_tree_node_t *new; new = malloc(sizeof(*new)); if (!new) do_error(_("couldn't allocate new extent descriptor.\n")); new->avl_node.avl_nextino = NULL; new->ex_startblock = new_startblock; new->ex_blockcount = new_blockcount; new->ex_state = new_state; new->next = NULL; new->last = NULL; return new; } void release_extent_tree_node(extent_tree_node_t *node) { free(node); } /* * routines to recycle all nodes in a tree. it walks the tree * and puts all nodes back on the free list so the nodes can be * reused. the duplicate and bno/bcnt extent trees for each AG * are recycled after they're no longer needed to save memory */ static void release_extent_tree(avltree_desc_t *tree) { extent_tree_node_t *ext; extent_tree_node_t *tmp; extent_tree_node_t *lext; extent_tree_node_t *ltmp; if (tree->avl_firstino == NULL) return; ext = (extent_tree_node_t *) tree->avl_firstino; while (ext != NULL) { tmp = (extent_tree_node_t *) ext->avl_node.avl_nextino; /* * ext->next is guaranteed to be set only in bcnt trees */ if (ext->next != NULL) { lext = ext->next; while (lext != NULL) { ltmp = lext->next; release_extent_tree_node(lext); lext = ltmp; } } release_extent_tree_node(ext); ext = tmp; } tree->avl_root = tree->avl_firstino = NULL; return; } /* * top-level (visible) routines */ void release_agbno_extent_tree(xfs_agnumber_t agno) { release_extent_tree(extent_bno_ptrs[agno]); return; } void release_agbcnt_extent_tree(xfs_agnumber_t agno) { release_extent_tree(extent_bcnt_ptrs[agno]); return; } /* * the next 4 routines manage the trees of free extents -- 2 trees * per AG. The first tree is sorted by block number. The second * tree is sorted by extent size. This is the bno tree. */ void add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount) { extent_tree_node_t *ext; ASSERT(extent_bno_ptrs != NULL); ASSERT(extent_bno_ptrs[agno] != NULL); ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_FREE); if (avl_insert(extent_bno_ptrs[agno], (avlnode_t *) ext) == NULL) { do_error(_("duplicate bno extent range\n")); } } extent_tree_node_t * findfirst_bno_extent(xfs_agnumber_t agno) { ASSERT(extent_bno_ptrs != NULL); ASSERT(extent_bno_ptrs[agno] != NULL); return((extent_tree_node_t *) extent_bno_ptrs[agno]->avl_firstino); } extent_tree_node_t * find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock) { ASSERT(extent_bno_ptrs != NULL); ASSERT(extent_bno_ptrs[agno] != NULL); return((extent_tree_node_t *) avl_find(extent_bno_ptrs[agno], startblock)); } /* * delete a node that's in the tree (pointer obtained by a find routine) */ void get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext) { ASSERT(extent_bno_ptrs != NULL); ASSERT(extent_bno_ptrs[agno] != NULL); avl_delete(extent_bno_ptrs[agno], &ext->avl_node); return; } /* * the next 4 routines manage the trees of free extents -- 2 trees * per AG. The first tree is sorted by block number. The second * tree is sorted by extent size. This is the bcnt tree. */ void add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount) { extent_tree_node_t *ext, *prev, *current, *top; xfs_agblock_t tmp_startblock; xfs_extlen_t tmp_blockcount; extent_state_t tmp_state; ASSERT(extent_bcnt_ptrs != NULL); ASSERT(extent_bcnt_ptrs[agno] != NULL); ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_FREE); ASSERT(ext->next == NULL); #ifdef XR_BCNT_TRACE fprintf(stderr, "adding bcnt: agno = %d, start = %u, count = %u\n", agno, startblock, blockcount); #endif if ((current = (extent_tree_node_t *) avl_find(extent_bcnt_ptrs[agno], blockcount)) != NULL) { /* * avl tree code doesn't handle dups so insert * onto linked list in increasing startblock order * * when called from mk_incore_fstree, * startblock is in increasing order. * current is an "anchor" node. * quick check if the new ext goes to the end. * if so, append at the end, using the last field * of the "anchor". */ ASSERT(current->last != NULL); if (startblock > current->last->ex_startblock) { current->last->next = ext; current->last = ext; return; } /* * scan, to find the proper location for new entry. * this scan is *very* expensive and gets worse with * with increasing entries. */ top = prev = current; while (current != NULL && startblock > current->ex_startblock) { prev = current; current = current->next; } if (top == current) { ASSERT(top == prev); /* * new entry should be ahead of current. * to keep the avl tree intact, * swap the values of to-be-inserted element * and the values of the head of the list. * then insert as the 2nd element on the list. * * see the comment in get_bcnt_extent() * as to why we have to do this. */ tmp_startblock = top->ex_startblock; tmp_blockcount = top->ex_blockcount; tmp_state = top->ex_state; top->ex_startblock = ext->ex_startblock; top->ex_blockcount = ext->ex_blockcount; top->ex_state = ext->ex_state; ext->ex_startblock = tmp_startblock; ext->ex_blockcount = tmp_blockcount; ext->ex_state = tmp_state; current = top->next; prev = top; } prev->next = ext; ext->next = current; return; } if (avl_insert(extent_bcnt_ptrs[agno], (avlnode_t *) ext) == NULL) { do_error(_(": duplicate bno extent range\n")); } ext->last = ext; /* ext is an "anchor" node */ return; } extent_tree_node_t * findfirst_bcnt_extent(xfs_agnumber_t agno) { ASSERT(extent_bcnt_ptrs != NULL); ASSERT(extent_bcnt_ptrs[agno] != NULL); return((extent_tree_node_t *) extent_bcnt_ptrs[agno]->avl_firstino); } extent_tree_node_t * findbiggest_bcnt_extent(xfs_agnumber_t agno) { ASSERT(extent_bcnt_ptrs != NULL); ASSERT(extent_bcnt_ptrs[agno] != NULL); return((extent_tree_node_t *) avl_lastino(extent_bcnt_ptrs[agno]->avl_root)); } extent_tree_node_t * findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext) { avlnode_t *nextino; if (ext->next != NULL) { ASSERT(ext->ex_blockcount == ext->next->ex_blockcount); ASSERT(ext->ex_startblock < ext->next->ex_startblock); return(ext->next); } else { /* * have to look at the top of the list to get the * correct avl_nextino pointer since that pointer * is maintained and altered by the AVL code. */ nextino = avl_find(extent_bcnt_ptrs[agno], ext->ex_blockcount); ASSERT(nextino != NULL); if (nextino->avl_nextino != NULL) { ASSERT(ext->ex_blockcount < ((extent_tree_node_t *) nextino->avl_nextino)->ex_blockcount); } return((extent_tree_node_t *) nextino->avl_nextino); } } /* * this is meant to be called after you walk the bno tree to * determine exactly which extent you want (so you'll know the * desired value for startblock when you call this routine). */ extent_tree_node_t * get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, xfs_extlen_t blockcount) { extent_tree_node_t *ext, *prev, *top; xfs_agblock_t tmp_startblock; xfs_extlen_t tmp_blockcount; extent_state_t tmp_state; prev = NULL; ASSERT(extent_bcnt_ptrs != NULL); ASSERT(extent_bcnt_ptrs[agno] != NULL); if ((ext = (extent_tree_node_t *) avl_find(extent_bcnt_ptrs[agno], blockcount)) == NULL) return(NULL); top = ext; if (ext->next != NULL) { /* * pull it off the list */ while (ext != NULL && startblock != ext->ex_startblock) { prev = ext; ext = ext->next; } ASSERT(ext != NULL); if (ext == top) { /* * this node is linked into the tree so we * swap the core values so we can delete * the next item on the list instead of * the head of the list. This is because * the rest of the tree undoubtedly has * pointers to the piece of memory that * is the head of the list so pulling * the item out of the list and hence * the avl tree would be a bad idea. * * (cheaper than the alternative, a tree * delete of this node followed by a tree * insert of the next node on the list). */ tmp_startblock = ext->next->ex_startblock; tmp_blockcount = ext->next->ex_blockcount; tmp_state = ext->next->ex_state; ext->next->ex_startblock = ext->ex_startblock; ext->next->ex_blockcount = ext->ex_blockcount; ext->next->ex_state = ext->ex_state; ext->ex_startblock = tmp_startblock; ext->ex_blockcount = tmp_blockcount; ext->ex_state = tmp_state; ext = ext->next; prev = top; } /* * now, a simple list deletion */ prev->next = ext->next; ext->next = NULL; } else { /* * no list, just one node. simply delete */ avl_delete(extent_bcnt_ptrs[agno], &ext->avl_node); } ASSERT(ext->ex_startblock == startblock); ASSERT(ext->ex_blockcount == blockcount); return(ext); } static uintptr_t avl_ext_start(avlnode_t *node) { return((uintptr_t) ((extent_tree_node_t *) node)->ex_startblock); } static uintptr_t avl_ext_end(avlnode_t *node) { return((uintptr_t) ( ((extent_tree_node_t *) node)->ex_startblock + ((extent_tree_node_t *) node)->ex_blockcount)); } /* * convert size to an address for the AVL tree code -- the bigger the size, * the lower the address so the biggest extent will be first in the tree */ static uintptr_t avl_ext_bcnt_start(avlnode_t *node) { /* return((uintptr_t) (BCNT_ADDR(((extent_tree_node_t *) node)->ex_blockcount))); */ return((uintptr_t) ((extent_tree_node_t *)node)->ex_blockcount); } static uintptr_t avl_ext_bcnt_end(avlnode_t *node) { /* return((uintptr_t) (BCNT_ADDR(((extent_tree_node_t *) node)->ex_blockcount))); */ return((uintptr_t) ((extent_tree_node_t *)node)->ex_blockcount); } static avlops_t avl_extent_bcnt_tree_ops = { avl_ext_bcnt_start, avl_ext_bcnt_end }; static avlops_t avl_extent_tree_ops = { avl_ext_start, avl_ext_end }; /* * for real-time extents -- have to dup code since realtime extent * startblocks can be 64-bit values. */ static rt_extent_tree_node_t * mk_rt_extent_tree_nodes(xfs_rtblock_t new_startblock, xfs_extlen_t new_blockcount, extent_state_t new_state) { rt_extent_tree_node_t *new; new = malloc(sizeof(*new)); if (!new) do_error(_("couldn't allocate new extent descriptor.\n")); new->avl_node.avl_nextino = NULL; new->rt_startblock = new_startblock; new->rt_blockcount = new_blockcount; new->rt_state = new_state; return new; } #if 0 void release_rt_extent_tree_node(rt_extent_tree_node_t *node) { free(node); } void release_rt_extent_tree() { extent_tree_node_t *ext; extent_tree_node_t *tmp; extent_tree_node_t *lext; extent_tree_node_t *ltmp; avl64tree_desc_t *tree; tree = rt_extent_tree_ptr; if (tree->avl_firstino == NULL) return; ext = (extent_tree_node_t *) tree->avl_firstino; while (ext != NULL) { tmp = (extent_tree_node_t *) ext->avl_node.avl_nextino; release_rt_extent_tree_node(ext); ext = tmp; } tree->avl_root = tree->avl_firstino = NULL; return; } #endif /* * don't need release functions for realtime tree teardown * since we only have one tree, not one per AG */ /* ARGSUSED */ void free_rt_dup_extent_tree(xfs_mount_t *mp) { ASSERT(mp->m_sb.sb_rblocks != 0); free(rt_ext_tree_ptr); rt_ext_tree_ptr = NULL; } /* * add a duplicate real-time extent */ void add_rt_dup_extent(xfs_rtblock_t startblock, xfs_extlen_t blockcount) { rt_extent_tree_node_t *first, *last, *ext, *next_ext; xfs_rtblock_t new_startblock; xfs_extlen_t new_blockcount; pthread_mutex_lock(&rt_ext_tree_lock); avl64_findranges(rt_ext_tree_ptr, startblock - 1, startblock + blockcount + 1, (avl64node_t **) &first, (avl64node_t **) &last); /* * find adjacent and overlapping extent blocks */ if (first == NULL && last == NULL) { /* nothing, just make and insert new extent */ ext = mk_rt_extent_tree_nodes(startblock, blockcount, XR_E_MULT); if (avl64_insert(rt_ext_tree_ptr, (avl64node_t *) ext) == NULL) { do_error(_("duplicate extent range\n")); } pthread_mutex_unlock(&rt_ext_tree_lock); return; } ASSERT(first != NULL && last != NULL); /* * find the new composite range, delete old extent nodes * as we go */ new_startblock = startblock; new_blockcount = blockcount; for (ext = first; ext != (rt_extent_tree_node_t *) last->avl_node.avl_nextino; ext = next_ext) { /* * preserve the next inorder node */ next_ext = (rt_extent_tree_node_t *) ext->avl_node.avl_nextino; /* * just bail if the new extent is contained within an old one */ if (ext->rt_startblock <= startblock && ext->rt_blockcount >= blockcount) { pthread_mutex_unlock(&rt_ext_tree_lock); return; } /* * now check for overlaps and adjacent extents */ if (ext->rt_startblock + ext->rt_blockcount >= startblock || ext->rt_startblock <= startblock + blockcount) { if (ext->rt_startblock < new_startblock) new_startblock = ext->rt_startblock; if (ext->rt_startblock + ext->rt_blockcount > new_startblock + new_blockcount) new_blockcount = ext->rt_startblock + ext->rt_blockcount - new_startblock; avl64_delete(rt_ext_tree_ptr, (avl64node_t *) ext); continue; } } ext = mk_rt_extent_tree_nodes(new_startblock, new_blockcount, XR_E_MULT); if (avl64_insert(rt_ext_tree_ptr, (avl64node_t *) ext) == NULL) { do_error(_("duplicate extent range\n")); } pthread_mutex_unlock(&rt_ext_tree_lock); return; } /* * returns 1 if block is a dup, 0 if not */ /* ARGSUSED */ int search_rt_dup_extent(xfs_mount_t *mp, xfs_rtblock_t bno) { int ret; pthread_mutex_lock(&rt_ext_tree_lock); if (avl64_findrange(rt_ext_tree_ptr, bno) != NULL) ret = 1; else ret = 0; pthread_mutex_unlock(&rt_ext_tree_lock); return(ret); } static uint64_t avl64_rt_ext_start(avl64node_t *node) { return(((rt_extent_tree_node_t *) node)->rt_startblock); } static uint64_t avl64_ext_end(avl64node_t *node) { return(((rt_extent_tree_node_t *) node)->rt_startblock + ((rt_extent_tree_node_t *) node)->rt_blockcount); } static avl64ops_t avl64_extent_tree_ops = { avl64_rt_ext_start, avl64_ext_end }; void incore_ext_init(xfs_mount_t *mp) { int i; xfs_agnumber_t agcount = mp->m_sb.sb_agcount; pthread_mutex_init(&rt_ext_tree_lock, NULL); dup_extent_trees = calloc(agcount, sizeof(struct btree_root *)); if (!dup_extent_trees) do_error(_("couldn't malloc dup extent tree descriptor table\n")); dup_extent_tree_locks = calloc(agcount, sizeof(pthread_mutex_t)); if (!dup_extent_tree_locks) do_error(_("couldn't malloc dup extent tree descriptor table\n")); if ((extent_bno_ptrs = malloc(agcount * sizeof(avltree_desc_t *))) == NULL) do_error( _("couldn't malloc free by-bno extent tree descriptor table\n")); if ((extent_bcnt_ptrs = malloc(agcount * sizeof(avltree_desc_t *))) == NULL) do_error( _("couldn't malloc free by-bcnt extent tree descriptor table\n")); for (i = 0; i < agcount; i++) { if ((extent_bno_ptrs[i] = malloc(sizeof(avltree_desc_t))) == NULL) do_error( _("couldn't malloc bno extent tree descriptor\n")); if ((extent_bcnt_ptrs[i] = malloc(sizeof(avltree_desc_t))) == NULL) do_error( _("couldn't malloc bcnt extent tree descriptor\n")); } for (i = 0; i < agcount; i++) { btree_init(&dup_extent_trees[i]); pthread_mutex_init(&dup_extent_tree_locks[i], NULL); avl_init_tree(extent_bno_ptrs[i], &avl_extent_tree_ops); avl_init_tree(extent_bcnt_ptrs[i], &avl_extent_bcnt_tree_ops); } if ((rt_ext_tree_ptr = malloc(sizeof(avl64tree_desc_t))) == NULL) do_error(_("couldn't malloc dup rt extent tree descriptor\n")); avl64_init_tree(rt_ext_tree_ptr, &avl64_extent_tree_ops); } /* * this routine actually frees all the memory used to track per-AG trees */ void incore_ext_teardown(xfs_mount_t *mp) { xfs_agnumber_t i; for (i = 0; i < mp->m_sb.sb_agcount; i++) { btree_destroy(dup_extent_trees[i]); free(extent_bno_ptrs[i]); free(extent_bcnt_ptrs[i]); } free(dup_extent_trees); free(extent_bcnt_ptrs); free(extent_bno_ptrs); dup_extent_trees = NULL; extent_bcnt_ptrs = NULL; extent_bno_ptrs = NULL; } static int count_extents(xfs_agnumber_t agno, avltree_desc_t *tree, int whichtree) { extent_tree_node_t *node; int i = 0; node = (extent_tree_node_t *) tree->avl_firstino; while (node != NULL) { i++; if (whichtree) node = findnext_bcnt_extent(agno, node); else node = findnext_bno_extent(node); } return(i); } int count_bno_extents_blocks(xfs_agnumber_t agno, uint *numblocks) { uint64_t nblocks; extent_tree_node_t *node; int i = 0; ASSERT(agno < glob_agcount); nblocks = 0; node = (extent_tree_node_t *) extent_bno_ptrs[agno]->avl_firstino; while (node != NULL) { nblocks += node->ex_blockcount; i++; node = findnext_bno_extent(node); } *numblocks = nblocks; return(i); } int count_bno_extents(xfs_agnumber_t agno) { ASSERT(agno < glob_agcount); return(count_extents(agno, extent_bno_ptrs[agno], 0)); } int count_bcnt_extents(xfs_agnumber_t agno) { ASSERT(agno < glob_agcount); return(count_extents(agno, extent_bcnt_ptrs[agno], 1)); } xfsprogs-5.3.0/repair/incore_ino.c0000644000175000017500000004462013435336037017033 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "incore.h" #include "agheader.h" #include "protos.h" #include "threads.h" #include "err_protos.h" /* * array of inode tree ptrs, one per ag */ avltree_desc_t **inode_tree_ptrs; /* * ditto for uncertain inodes */ static avltree_desc_t **inode_uncertain_tree_ptrs; /* memory optimised nlink counting for all inodes */ static void * alloc_nlink_array(uint8_t nlink_size) { void *ptr; ptr = calloc(XFS_INODES_PER_CHUNK, nlink_size); if (!ptr) do_error(_("could not allocate nlink array\n")); return ptr; } static void nlink_grow_8_to_16(ino_tree_node_t *irec) { uint16_t *new_nlinks; int i; irec->nlink_size = sizeof(uint16_t); new_nlinks = alloc_nlink_array(irec->nlink_size); for (i = 0; i < XFS_INODES_PER_CHUNK; i++) new_nlinks[i] = irec->disk_nlinks.un8[i]; free(irec->disk_nlinks.un8); irec->disk_nlinks.un16 = new_nlinks; if (full_ino_ex_data) { new_nlinks = alloc_nlink_array(irec->nlink_size); for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { new_nlinks[i] = irec->ino_un.ex_data->counted_nlinks.un8[i]; } free(irec->ino_un.ex_data->counted_nlinks.un8); irec->ino_un.ex_data->counted_nlinks.un16 = new_nlinks; } } static void nlink_grow_16_to_32(ino_tree_node_t *irec) { uint32_t *new_nlinks; int i; irec->nlink_size = sizeof(uint32_t); new_nlinks = alloc_nlink_array(irec->nlink_size); for (i = 0; i < XFS_INODES_PER_CHUNK; i++) new_nlinks[i] = irec->disk_nlinks.un16[i]; free(irec->disk_nlinks.un16); irec->disk_nlinks.un32 = new_nlinks; if (full_ino_ex_data) { new_nlinks = alloc_nlink_array(irec->nlink_size); for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { new_nlinks[i] = irec->ino_un.ex_data->counted_nlinks.un16[i]; } free(irec->ino_un.ex_data->counted_nlinks.un16); irec->ino_un.ex_data->counted_nlinks.un32 = new_nlinks; } } void add_inode_ref(struct ino_tree_node *irec, int ino_offset) { ASSERT(irec->ino_un.ex_data != NULL); switch (irec->nlink_size) { case sizeof(uint8_t): if (irec->ino_un.ex_data->counted_nlinks.un8[ino_offset] < 0xff) { irec->ino_un.ex_data->counted_nlinks.un8[ino_offset]++; break; } nlink_grow_8_to_16(irec); /*FALLTHRU*/ case sizeof(uint16_t): if (irec->ino_un.ex_data->counted_nlinks.un16[ino_offset] < 0xffff) { irec->ino_un.ex_data->counted_nlinks.un16[ino_offset]++; break; } nlink_grow_16_to_32(irec); /*FALLTHRU*/ case sizeof(uint32_t): irec->ino_un.ex_data->counted_nlinks.un32[ino_offset]++; break; default: ASSERT(0); } } void drop_inode_ref(struct ino_tree_node *irec, int ino_offset) { uint32_t refs = 0; ASSERT(irec->ino_un.ex_data != NULL); switch (irec->nlink_size) { case sizeof(uint8_t): ASSERT(irec->ino_un.ex_data->counted_nlinks.un8[ino_offset] > 0); refs = --irec->ino_un.ex_data->counted_nlinks.un8[ino_offset]; break; case sizeof(uint16_t): ASSERT(irec->ino_un.ex_data->counted_nlinks.un16[ino_offset] > 0); refs = --irec->ino_un.ex_data->counted_nlinks.un16[ino_offset]; break; case sizeof(uint32_t): ASSERT(irec->ino_un.ex_data->counted_nlinks.un32[ino_offset] > 0); refs = --irec->ino_un.ex_data->counted_nlinks.un32[ino_offset]; break; default: ASSERT(0); } if (refs == 0) irec->ino_un.ex_data->ino_reached &= ~IREC_MASK(ino_offset); } uint32_t num_inode_references(struct ino_tree_node *irec, int ino_offset) { ASSERT(irec->ino_un.ex_data != NULL); switch (irec->nlink_size) { case sizeof(uint8_t): return irec->ino_un.ex_data->counted_nlinks.un8[ino_offset]; case sizeof(uint16_t): return irec->ino_un.ex_data->counted_nlinks.un16[ino_offset]; case sizeof(uint32_t): return irec->ino_un.ex_data->counted_nlinks.un32[ino_offset]; default: ASSERT(0); } return 0; } void set_inode_disk_nlinks(struct ino_tree_node *irec, int ino_offset, uint32_t nlinks) { switch (irec->nlink_size) { case sizeof(uint8_t): if (nlinks < 0xff) { irec->disk_nlinks.un8[ino_offset] = nlinks; break; } nlink_grow_8_to_16(irec); /*FALLTHRU*/ case sizeof(uint16_t): if (nlinks < 0xffff) { irec->disk_nlinks.un16[ino_offset] = nlinks; break; } nlink_grow_16_to_32(irec); /*FALLTHRU*/ case sizeof(uint32_t): irec->disk_nlinks.un32[ino_offset] = nlinks; break; default: ASSERT(0); } } uint32_t get_inode_disk_nlinks(struct ino_tree_node *irec, int ino_offset) { switch (irec->nlink_size) { case sizeof(uint8_t): return irec->disk_nlinks.un8[ino_offset]; case sizeof(uint16_t): return irec->disk_nlinks.un16[ino_offset]; case sizeof(uint32_t): return irec->disk_nlinks.un32[ino_offset]; default: ASSERT(0); } return 0; } static uint8_t * alloc_ftypes_array( struct xfs_mount *mp) { uint8_t *ptr; if (!xfs_sb_version_hasftype(&mp->m_sb)) return NULL; ptr = calloc(XFS_INODES_PER_CHUNK, sizeof(*ptr)); if (!ptr) do_error(_("could not allocate ftypes array\n")); return ptr; } /* * Next is the uncertain inode list -- a sorted (in ascending order) * list of inode records sorted on the starting inode number. There * is one list per ag. */ /* * Common code for creating inode records for use by trees and lists. * called only from add_inodes and add_inodes_uncertain * * IMPORTANT: all inodes (inode records) start off as free and * unconfirmed. */ static struct ino_tree_node * alloc_ino_node( struct xfs_mount *mp, xfs_agino_t starting_ino) { struct ino_tree_node *irec; irec = malloc(sizeof(*irec)); if (!irec) do_error(_("inode map malloc failed\n")); irec->avl_node.avl_nextino = NULL; irec->avl_node.avl_forw = NULL; irec->avl_node.avl_back = NULL; irec->ino_startnum = starting_ino; irec->ino_confirmed = 0; irec->ino_isa_dir = 0; irec->ino_was_rl = 0; irec->ino_is_rl = 0; irec->ir_free = (xfs_inofree_t) - 1; irec->ir_sparse = 0; irec->ino_un.ex_data = NULL; irec->nlink_size = sizeof(uint8_t); irec->disk_nlinks.un8 = alloc_nlink_array(irec->nlink_size); irec->ftypes = alloc_ftypes_array(mp); return irec; } static void free_nlink_array(union ino_nlink nlinks, uint8_t nlink_size) { switch (nlink_size) { case sizeof(uint8_t): free(nlinks.un8); break; case sizeof(uint16_t): free(nlinks.un16); break; case sizeof(uint32_t): free(nlinks.un32); break; default: ASSERT(0); } } static void free_ino_tree_node( struct ino_tree_node *irec) { irec->avl_node.avl_nextino = NULL; irec->avl_node.avl_forw = NULL; irec->avl_node.avl_back = NULL; free_nlink_array(irec->disk_nlinks, irec->nlink_size); if (irec->ino_un.ex_data != NULL) { if (full_ino_ex_data) { free(irec->ino_un.ex_data->parents); free_nlink_array(irec->ino_un.ex_data->counted_nlinks, irec->nlink_size); } free(irec->ino_un.ex_data); } free(irec->ftypes); free(irec); } /* * last referenced cache for uncertain inodes */ static ino_tree_node_t **last_rec; /* * ok, the uncertain inodes are a set of trees just like the * good inodes but all starting inode records are (arbitrarily) * aligned on XFS_CHUNK_PER_INODE boundaries to prevent overlaps. * this means we may have partials records in the tree (e.g. records * without 64 confirmed uncertain inodes). Tough. * * free is set to 1 if the inode is thought to be free, 0 if used */ void add_aginode_uncertain( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino, int free) { ino_tree_node_t *ino_rec; xfs_agino_t s_ino; int offset; ASSERT(agno < glob_agcount); ASSERT(last_rec != NULL); s_ino = rounddown(ino, XFS_INODES_PER_CHUNK); /* * check for a cache hit */ if (last_rec[agno] != NULL && last_rec[agno]->ino_startnum == s_ino) { offset = ino - s_ino; if (free) set_inode_free(last_rec[agno], offset); else set_inode_used(last_rec[agno], offset); return; } /* * check to see if record containing inode is already in the tree. * if not, add it */ ino_rec = (ino_tree_node_t *) avl_findrange(inode_uncertain_tree_ptrs[agno], s_ino); if (!ino_rec) { ino_rec = alloc_ino_node(mp, s_ino); if (!avl_insert(inode_uncertain_tree_ptrs[agno], &ino_rec->avl_node)) do_error( _("add_aginode_uncertain - duplicate inode range\n")); } if (free) set_inode_free(ino_rec, ino - s_ino); else set_inode_used(ino_rec, ino - s_ino); /* * set cache entry */ last_rec[agno] = ino_rec; } /* * like add_aginode_uncertain() only it needs an xfs_mount_t * * to perform the inode number conversion. */ void add_inode_uncertain(xfs_mount_t *mp, xfs_ino_t ino, int free) { add_aginode_uncertain(mp, XFS_INO_TO_AGNO(mp, ino), XFS_INO_TO_AGINO(mp, ino), free); } /* * pull the indicated inode record out of the uncertain inode tree */ void get_uncertain_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, ino_tree_node_t *ino_rec) { ASSERT(inode_tree_ptrs != NULL); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(inode_tree_ptrs[agno] != NULL); avl_delete(inode_uncertain_tree_ptrs[agno], &ino_rec->avl_node); ino_rec->avl_node.avl_nextino = NULL; ino_rec->avl_node.avl_forw = NULL; ino_rec->avl_node.avl_back = NULL; } ino_tree_node_t * findfirst_uncertain_inode_rec(xfs_agnumber_t agno) { return((ino_tree_node_t *) inode_uncertain_tree_ptrs[agno]->avl_firstino); } ino_tree_node_t * find_uncertain_inode_rec(xfs_agnumber_t agno, xfs_agino_t ino) { return((ino_tree_node_t *) avl_findrange(inode_uncertain_tree_ptrs[agno], ino)); } void clear_uncertain_ino_cache(xfs_agnumber_t agno) { last_rec[agno] = NULL; } /* * Next comes the inode trees. One per AG, AVL trees of inode records, each * inode record tracking 64 inodes */ /* * Set up an inode tree record for a group of inodes that will include the * requested inode. * * This does NOT do error-check for duplicate records. The caller is * responsible for checking that. Ino must be the start of an * XFS_INODES_PER_CHUNK (64) inode chunk * * Each inode resides in a 64-inode chunk which can be part one or more chunks * (max(64, inodes-per-block). The fs allocates in chunks (as opposed to 1 * chunk) when a block can hold more than one chunk (inodes per block > 64). * Allocating in one chunk pieces causes us problems when it takes more than * one fs block to contain an inode chunk because the chunks can start on * *any* block boundary. So we assume that the caller has a clue because at * this level, we don't. */ static struct ino_tree_node * add_inode( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino) { struct ino_tree_node *irec; irec = alloc_ino_node(mp, agino); if (!avl_insert(inode_tree_ptrs[agno], &irec->avl_node)) do_warn(_("add_inode - duplicate inode range\n")); return irec; } /* * pull the indicated inode record out of the inode tree */ void get_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, ino_tree_node_t *ino_rec) { ASSERT(inode_tree_ptrs != NULL); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(inode_tree_ptrs[agno] != NULL); avl_delete(inode_tree_ptrs[agno], &ino_rec->avl_node); ino_rec->avl_node.avl_nextino = NULL; ino_rec->avl_node.avl_forw = NULL; ino_rec->avl_node.avl_back = NULL; } /* * free the designated inode record (return it to the free pool) */ /* ARGSUSED */ void free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec) { free_ino_tree_node(ino_rec); } void find_inode_rec_range(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t start_ino, xfs_agino_t end_ino, ino_tree_node_t **first, ino_tree_node_t **last) { *first = *last = NULL; /* * Is the AG inside the file system ? */ if (agno < mp->m_sb.sb_agcount) avl_findranges(inode_tree_ptrs[agno], start_ino, end_ino, (avlnode_t **) first, (avlnode_t **) last); } /* * if ino doesn't exist, it must be properly aligned -- on a * filesystem block boundary or XFS_INODES_PER_CHUNK boundary, * whichever alignment is larger. */ ino_tree_node_t * set_inode_used_alloc(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino) { ino_tree_node_t *ino_rec; /* * check alignment -- the only way to detect this * is too see if the chunk overlaps another chunk * already in the tree */ ino_rec = add_inode(mp, agno, ino); ASSERT(ino_rec != NULL); ASSERT(ino >= ino_rec->ino_startnum && ino - ino_rec->ino_startnum < XFS_INODES_PER_CHUNK); set_inode_used(ino_rec, ino - ino_rec->ino_startnum); return(ino_rec); } ino_tree_node_t * set_inode_free_alloc(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino) { ino_tree_node_t *ino_rec; ino_rec = add_inode(mp, agno, ino); ASSERT(ino_rec != NULL); ASSERT(ino >= ino_rec->ino_startnum && ino - ino_rec->ino_startnum < XFS_INODES_PER_CHUNK); set_inode_free(ino_rec, ino - ino_rec->ino_startnum); return(ino_rec); } static void print_inode_list_int(xfs_agnumber_t agno, int uncertain) { ino_tree_node_t *ino_rec; if (!uncertain) { fprintf(stderr, _("good inode list is --\n")); ino_rec = findfirst_inode_rec(agno); } else { fprintf(stderr, _("uncertain inode list is --\n")); ino_rec = findfirst_uncertain_inode_rec(agno); } if (ino_rec == NULL) { fprintf(stderr, _("agno %d -- no inodes\n"), agno); return; } printf(_("agno %d\n"), agno); while(ino_rec != NULL) { fprintf(stderr, _("\tptr = %lx, start = 0x%x, free = 0x%llx, confirmed = 0x%llx\n"), (unsigned long)ino_rec, ino_rec->ino_startnum, (unsigned long long)ino_rec->ir_free, (unsigned long long)ino_rec->ino_confirmed); if (ino_rec->ino_startnum == 0) ino_rec = ino_rec; ino_rec = next_ino_rec(ino_rec); } } void print_inode_list(xfs_agnumber_t agno) { print_inode_list_int(agno, 0); } void print_uncertain_inode_list(xfs_agnumber_t agno) { print_inode_list_int(agno, 1); } /* * set parent -- use a bitmask and a packed array. The bitmask * indicate which inodes have an entry in the array. An inode that * is the Nth bit set in the mask is stored in the Nth location in * the array where N starts at 0. */ void set_inode_parent( ino_tree_node_t *irec, int offset, xfs_ino_t parent) { parent_list_t *ptbl; int i; int cnt; int target; uint64_t bitmask; parent_entry_t *tmp; if (full_ino_ex_data) ptbl = irec->ino_un.ex_data->parents; else ptbl = irec->ino_un.plist; if (ptbl == NULL) { ptbl = (parent_list_t *)malloc(sizeof(parent_list_t)); if (!ptbl) do_error(_("couldn't malloc parent list table\n")); if (full_ino_ex_data) irec->ino_un.ex_data->parents = ptbl; else irec->ino_un.plist = ptbl; ptbl->pmask = 1ULL << offset; ptbl->pentries = (xfs_ino_t*)memalign(sizeof(xfs_ino_t), sizeof(xfs_ino_t)); if (!ptbl->pentries) do_error(_("couldn't memalign pentries table\n")); #ifdef DEBUG ptbl->cnt = 1; #endif ptbl->pentries[0] = parent; return; } if (ptbl->pmask & (1ULL << offset)) { bitmask = 1ULL; target = 0; for (i = 0; i < offset; i++) { if (ptbl->pmask & bitmask) target++; bitmask <<= 1; } #ifdef DEBUG ASSERT(target < ptbl->cnt); #endif ptbl->pentries[target] = parent; return; } bitmask = 1ULL; cnt = target = 0; for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { if (ptbl->pmask & bitmask) { cnt++; if (i < offset) target++; } bitmask <<= 1; } #ifdef DEBUG ASSERT(cnt == ptbl->cnt); #endif ASSERT(cnt >= target); tmp = (xfs_ino_t*)memalign(sizeof(xfs_ino_t), (cnt + 1) * sizeof(xfs_ino_t)); if (!tmp) do_error(_("couldn't memalign pentries table\n")); memmove(tmp, ptbl->pentries, target * sizeof(parent_entry_t)); if (cnt > target) memmove(tmp + target + 1, ptbl->pentries + target, (cnt - target) * sizeof(parent_entry_t)); free(ptbl->pentries); ptbl->pentries = tmp; #ifdef DEBUG ptbl->cnt++; #endif ptbl->pentries[target] = parent; ptbl->pmask |= (1ULL << offset); } xfs_ino_t get_inode_parent(ino_tree_node_t *irec, int offset) { uint64_t bitmask; parent_list_t *ptbl; int i; int target; if (full_ino_ex_data) ptbl = irec->ino_un.ex_data->parents; else ptbl = irec->ino_un.plist; if (ptbl->pmask & (1ULL << offset)) { bitmask = 1ULL; target = 0; for (i = 0; i < offset; i++) { if (ptbl->pmask & bitmask) target++; bitmask <<= 1; } #ifdef DEBUG ASSERT(target < ptbl->cnt); #endif return(ptbl->pentries[target]); } return(0LL); } void alloc_ex_data(ino_tree_node_t *irec) { parent_list_t *ptbl; ptbl = irec->ino_un.plist; irec->ino_un.ex_data = (ino_ex_data_t *)calloc(1, sizeof(ino_ex_data_t)); if (irec->ino_un.ex_data == NULL) do_error(_("could not malloc inode extra data\n")); irec->ino_un.ex_data->parents = ptbl; switch (irec->nlink_size) { case sizeof(uint8_t): irec->ino_un.ex_data->counted_nlinks.un8 = alloc_nlink_array(irec->nlink_size); break; case sizeof(uint16_t): irec->ino_un.ex_data->counted_nlinks.un16 = alloc_nlink_array(irec->nlink_size); break; case sizeof(uint32_t): irec->ino_un.ex_data->counted_nlinks.un32 = alloc_nlink_array(irec->nlink_size); break; default: ASSERT(0); } } void add_ino_ex_data(xfs_mount_t *mp) { ino_tree_node_t *ino_rec; xfs_agnumber_t i; for (i = 0; i < mp->m_sb.sb_agcount; i++) { ino_rec = findfirst_inode_rec(i); while (ino_rec != NULL) { alloc_ex_data(ino_rec); ino_rec = next_ino_rec(ino_rec); } } full_ino_ex_data = 1; } static uintptr_t avl_ino_start(avlnode_t *node) { return((uintptr_t) ((ino_tree_node_t *) node)->ino_startnum); } static uintptr_t avl_ino_end(avlnode_t *node) { return((uintptr_t) ( ((ino_tree_node_t *) node)->ino_startnum + XFS_INODES_PER_CHUNK)); } static avlops_t avl_ino_tree_ops = { avl_ino_start, avl_ino_end }; void incore_ino_init(xfs_mount_t *mp) { int i; int agcount = mp->m_sb.sb_agcount; if ((inode_tree_ptrs = malloc(agcount * sizeof(avltree_desc_t *))) == NULL) do_error(_("couldn't malloc inode tree descriptor table\n")); if ((inode_uncertain_tree_ptrs = malloc(agcount * sizeof(avltree_desc_t *))) == NULL) do_error( _("couldn't malloc uncertain ino tree descriptor table\n")); for (i = 0; i < agcount; i++) { if ((inode_tree_ptrs[i] = malloc(sizeof(avltree_desc_t))) == NULL) do_error(_("couldn't malloc inode tree descriptor\n")); if ((inode_uncertain_tree_ptrs[i] = malloc(sizeof(avltree_desc_t))) == NULL) do_error( _("couldn't malloc uncertain ino tree descriptor\n")); } for (i = 0; i < agcount; i++) { avl_init_tree(inode_tree_ptrs[i], &avl_ino_tree_ops); avl_init_tree(inode_uncertain_tree_ptrs[i], &avl_ino_tree_ops); } if ((last_rec = malloc(sizeof(ino_tree_node_t *) * agcount)) == NULL) do_error(_("couldn't malloc uncertain inode cache area\n")); memset(last_rec, 0, sizeof(ino_tree_node_t *) * agcount); full_ino_ex_data = 0; } xfsprogs-5.3.0/repair/init.c0000644000175000017500000000446713435336037015657 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "globals.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" #include "pthread.h" #include "avl.h" #include "bmap.h" #include "incore.h" #include "prefetch.h" #include static void ts_create(void) { pthread_key_create(&dblkmap_key, NULL); pthread_key_create(&ablkmap_key, NULL); } static void increase_rlimit(void) { struct rlimit rl; /* Increase limits */ if (getrlimit(RLIMIT_FSIZE, &rl) == -1) { perror("getrlimit"); fprintf(stderr, _("getrlimit(RLIMIT_FSIZE) failed!\n")); exit(1); } if (rl.rlim_cur != RLIM_INFINITY) { rl.rlim_max = rl.rlim_cur = RLIM_INFINITY; if (setrlimit(RLIMIT_FSIZE, &rl) == -1) { perror("setrlimit"); fprintf(stderr, _("setrlimit failed - current: %lld, max: %lld\n"), (unsigned long long)rl.rlim_cur, (unsigned long long)rl.rlim_max); exit(1); } } } void xfs_init(libxfs_init_t *args) { memset(args, 0, sizeof(libxfs_init_t)); if (isa_file) { args->disfile = 1; args->dname = fs_name; args->volname = NULL; } else { args->disfile = 0; args->volname = fs_name; args->dname = NULL; } if (log_spec) { /* External log specified */ args->logname = log_name; args->lisfile = (isa_file?1:0); /* XXX assume data file also means log file */ /* REVISIT: Need to do fs sanity / log validity checking */ } if (rt_spec) { /* RT device specified */ args->rtname = rt_name; args->risfile = (isa_file?1:0); /* XXX assume data file also means rt file */ } args->usebuflock = do_prefetch; args->setblksize = 0; args->isdirect = LIBXFS_DIRECT; if (no_modify) args->isreadonly = (LIBXFS_ISREADONLY | LIBXFS_ISINACTIVE); else if (dangerously) args->isreadonly = (LIBXFS_ISINACTIVE | LIBXFS_DANGEROUSLY); else args->isreadonly = LIBXFS_EXCLUSIVELY; if (!libxfs_init(args)) { /* would -d be an option? */ if (!no_modify && !dangerously) { args->isreadonly = (LIBXFS_ISINACTIVE | LIBXFS_DANGEROUSLY); if (libxfs_init(args)) fprintf(stderr, _("Unmount or use the dangerous (-d) option to repair a read-only mounted filesystem\n")); } do_error(_("couldn't initialize XFS library\n")); } ts_create(); increase_rlimit(); pftrace_init(); } xfsprogs-5.3.0/repair/phase1.c0000644000175000017500000000737613435336037016077 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "globals.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" static void no_sb(void) { do_warn(_("Sorry, could not find valid secondary superblock\n")); do_warn(_("Exiting now.\n")); exit(1); } char * alloc_ag_buf(int size) { char *bp; bp = (char *)memalign(libxfs_device_alignment(), size); if (!bp) do_error(_("could not allocate ag header buffer (%d bytes)\n"), size); return(bp); } /* * this has got to be big enough to hold 4 sectors */ #define MAX_SECTSIZE (512 * 1024) /* ARGSUSED */ void phase1(xfs_mount_t *mp) { xfs_sb_t *sb; char *ag_bp; int rval; do_log(_("Phase 1 - find and verify superblock...\n")); primary_sb_modified = 0; need_root_inode = 0; need_root_dotdot = 0; need_rbmino = 0; need_rsumino = 0; lost_quotas = 0; /* * get AG 0 into ag header buf */ ag_bp = alloc_ag_buf(MAX_SECTSIZE); sb = (xfs_sb_t *) ag_bp; rval = get_sb(sb, 0LL, MAX_SECTSIZE, 0); if (rval == XR_EOF) do_error(_("error reading primary superblock\n")); /* * is this really an sb, verify internal consistency */ if (rval != XR_OK) { do_warn(_("bad primary superblock - %s !!!\n"), err_string(rval)); if (!find_secondary_sb(sb)) no_sb(); primary_sb_modified = 1; } else if ((rval = verify_set_primary_sb(sb, 0, &primary_sb_modified)) != XR_OK) { do_warn(_("couldn't verify primary superblock - %s !!!\n"), err_string(rval)); if (!find_secondary_sb(sb)) no_sb(); primary_sb_modified = 1; } /* * Check bad_features2 and make sure features2 the same as * bad_features (ORing the two together). Leave bad_features2 * set so older kernels can still use it and not mount unsupported * filesystems when it reads bad_features2. */ if (sb->sb_bad_features2 != 0 && sb->sb_bad_features2 != sb->sb_features2) { sb->sb_features2 |= sb->sb_bad_features2; sb->sb_bad_features2 = sb->sb_features2; primary_sb_modified = 1; do_warn(_("superblock has a features2 mismatch, correcting\n")); } /* * apply any version changes or conversions after the primary * superblock has been verified or repaired * * Send output to stdout as do_log and everything else in repair * is sent to stderr and there is no "quiet" option. xfs_admin * will filter stderr but not stdout. This situation must be improved. */ if (convert_lazy_count) { if (lazy_count && !xfs_sb_version_haslazysbcount(sb)) { sb->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; sb->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; sb->sb_bad_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; primary_sb_modified = 1; printf(_("Enabling lazy-counters\n")); } else if (!lazy_count && xfs_sb_version_haslazysbcount(sb)) { if (XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_5) { printf( _("Cannot disable lazy-counters on V5 fs\n")); exit(1); } sb->sb_features2 &= ~XFS_SB_VERSION2_LAZYSBCOUNTBIT; sb->sb_bad_features2 &= ~XFS_SB_VERSION2_LAZYSBCOUNTBIT; printf(_("Disabling lazy-counters\n")); primary_sb_modified = 1; } else { printf(_("Lazy-counters are already %s\n"), lazy_count ? _("enabled") : _("disabled")); exit(0); /* no conversion required, exit */ } } /* shared_vn should be zero */ if (sb->sb_shared_vn) { do_warn(_("resetting shared_vn to zero\n")); sb->sb_shared_vn = 0; primary_sb_modified = 1; } if (primary_sb_modified) { if (!no_modify) { do_warn(_("writing modified primary superblock\n")); write_primary_sb(sb, sb->sb_sectsize); } else { do_warn(_("would write modified primary superblock\n")); } } /* * misc. global var initialization */ sb_ifree = sb_icount = sb_fdblocks = sb_frextents = 0; free(sb); } xfsprogs-5.3.0/repair/phase2.c0000644000175000017500000001513013570057155016064 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "protos.h" #include "err_protos.h" #include "incore.h" #include "progress.h" #include "scan.h" /* workaround craziness in the xlog routines */ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p) { return 0; } static void zero_log( struct xfs_mount *mp) { int error; xfs_daddr_t head_blk; xfs_daddr_t tail_blk; struct xlog *log = mp->m_log; memset(log, 0, sizeof(struct xlog)); x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); x.lbsize = BBSIZE; if (xfs_sb_version_hassector(&mp->m_sb)) x.lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT); log->l_dev = mp->m_logdev_targp; log->l_logBBsize = x.logBBsize; log->l_logBBstart = x.logBBstart; log->l_sectBBsize = BTOBB(x.lbsize); log->l_mp = mp; if (xfs_sb_version_hassector(&mp->m_sb)) { log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; ASSERT(log->l_sectbb_log <= mp->m_sectbb_log); /* for larger sector sizes, must have v2 or external log */ ASSERT(log->l_sectbb_log == 0 || log->l_logBBstart == 0 || xfs_sb_version_haslogv2(&mp->m_sb)); ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); } log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1; /* * Find the log head and tail and alert the user to the situation if the * log appears corrupted or contains data. In either case, we do not * proceed past this point unless the user explicitly requests to zap * the log. */ error = xlog_find_tail(log, &head_blk, &tail_blk); if (error) { do_warn( _("zero_log: cannot find log head/tail (xlog_find_tail=%d)\n"), error); if (!no_modify && !zap_log) { do_warn(_( "ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n" "filesystem to replay the log or use the -L option to destroy the log and\n" "attempt a repair.\n")); exit(2); } } else { if (verbose) { do_log( _("zero_log: head block %" PRId64 " tail block %" PRId64 "\n"), head_blk, tail_blk); } if (head_blk != tail_blk) { if (!no_modify && zap_log) { do_warn(_( "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "destroyed because the -L option was used.\n")); } else if (no_modify) { do_warn(_( "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "ignored because the -n option was used. Expect spurious inconsistencies\n" "which may be resolved by first mounting the filesystem to replay the log.\n")); } else { do_warn(_( "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running xfs_repair. If you are unable to mount the filesystem, then use\n" "the -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n")); exit(2); } } } /* * Only clear the log when explicitly requested. Doing so is unnecessary * unless something is wrong. Further, this resets the current LSN of * the filesystem and creates more work for repair of v5 superblock * filesystems. */ if (!no_modify && zap_log) { libxfs_log_clear(log->l_dev, NULL, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), &mp->m_sb.sb_uuid, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE, true); /* update the log data structure with new state */ error = xlog_find_tail(log, &head_blk, &tail_blk); if (error || head_blk != tail_blk) do_error(_("failed to clear log")); } /* * Finally, seed the max LSN from the current state of the log if this * is a v5 filesystem. */ if (xfs_sb_version_hascrc(&mp->m_sb)) libxfs_max_lsn = log->l_last_sync_lsn; } /* * ok, at this point, the fs is mounted but the root inode may be * trashed and the ag headers haven't been checked. So we have * a valid xfs_mount_t and superblock but that's about it. That * means we can use macros that use mount/sb fields in calculations * but I/O or btree routines that depend on space maps or inode maps * being correct are verboten. */ void phase2( struct xfs_mount *mp, int scan_threads) { int j; ino_tree_node_t *ino_rec; /* now we can start using the buffer cache routines */ set_mp(mp); /* Check whether this fs has internal or external log */ if (mp->m_sb.sb_logstart == 0) { if (!x.logname) do_error(_("This filesystem has an external log. " "Specify log device with the -l option.\n")); do_log(_("Phase 2 - using external log on %s\n"), x.logname); } else do_log(_("Phase 2 - using internal log\n")); /* Zero log if applicable */ do_log(_(" - zero log...\n")); zero_log(mp); do_log(_(" - scan filesystem freespace and inode maps...\n")); bad_ino_btree = 0; set_progress_msg(PROG_FMT_SCAN_AG, (uint64_t) glob_agcount); scan_ags(mp, scan_threads); print_final_rpt(); /* * make sure we know about the root inode chunk */ if ((ino_rec = find_inode_rec(mp, 0, mp->m_sb.sb_rootino)) == NULL) { ASSERT(mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 && mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2); do_warn(_("root inode chunk not found\n")); /* * mark the first 3 used, the rest are free */ ino_rec = set_inode_used_alloc(mp, 0, (xfs_agino_t) mp->m_sb.sb_rootino); set_inode_used(ino_rec, 1); set_inode_used(ino_rec, 2); for (j = 3; j < XFS_INODES_PER_CHUNK; j++) set_inode_free(ino_rec, j); /* * also mark blocks */ set_bmap_ext(0, XFS_INO_TO_AGBNO(mp, mp->m_sb.sb_rootino), M_IGEO(mp)->ialloc_blks, XR_E_INO); } else { do_log(_(" - found root inode chunk\n")); /* * blocks are marked, just make sure they're in use */ if (is_inode_free(ino_rec, 0)) { do_warn(_("root inode marked free, ")); set_inode_used(ino_rec, 0); if (!no_modify) do_warn(_("correcting\n")); else do_warn(_("would correct\n")); } if (is_inode_free(ino_rec, 1)) { do_warn(_("realtime bitmap inode marked free, ")); set_inode_used(ino_rec, 1); if (!no_modify) do_warn(_("correcting\n")); else do_warn(_("would correct\n")); } if (is_inode_free(ino_rec, 2)) { do_warn(_("realtime summary inode marked free, ")); set_inode_used(ino_rec, 2); if (!no_modify) do_warn(_("correcting\n")); else do_warn(_("would correct\n")); } } } xfsprogs-5.3.0/repair/phase3.c0000644000175000017500000000725513435336037016075 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "threads.h" #include "prefetch.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "progress.h" #include "bmap.h" #include "threads.h" static void process_agi_unlinked( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_buf *bp; struct xfs_agi *agip; xfs_agnumber_t i; int agi_dirty = 0; bp = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE, 0, &xfs_agi_buf_ops); if (!bp) do_error(_("cannot read agi block %" PRId64 " for ag %u\n"), XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), agno); agip = XFS_BUF_TO_AGI(bp); ASSERT(be32_to_cpu(agip->agi_seqno) == agno); for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { if (agip->agi_unlinked[i] != cpu_to_be32(NULLAGINO)) { agip->agi_unlinked[i] = cpu_to_be32(NULLAGINO); agi_dirty = 1; } } if (agi_dirty) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); } static void process_ag_func( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { /* * turn on directory processing (inode discovery) and * attribute processing (extra_attr_check) */ wait_for_inode_prefetch(arg); do_log(_(" - agno = %d\n"), agno); process_aginodes(wq->wq_ctx, arg, agno, 1, 0, 1); blkmap_free_final(); cleanup_inode_prefetch(arg); } static void process_ags( xfs_mount_t *mp) { do_inode_prefetch(mp, ag_stride, process_ag_func, false, false); } static void do_uncertain_aginodes( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { int *count = arg; *count = process_uncertain_aginodes(wq->wq_ctx, agno); #ifdef XR_INODE_TRACE fprintf(stderr, "\t\t phase 3 - ag %d process_uncertain_inodes returns %d\n", *count, j); #endif PROG_RPT_INC(prog_rpt_done[agno], 1); } void phase3( struct xfs_mount *mp, int scan_threads) { int i, j; int *counts; struct workqueue wq; do_log(_("Phase 3 - for each AG...\n")); if (!no_modify) do_log(_(" - scan and clear agi unlinked lists...\n")); else do_log(_(" - scan (but don't clear) agi unlinked lists...\n")); set_progress_msg(PROG_FMT_AGI_UNLINKED, (uint64_t) glob_agcount); /* first clear the agi unlinked AGI list */ if (!no_modify) { for (i = 0; i < mp->m_sb.sb_agcount; i++) process_agi_unlinked(mp, i); } /* now look at possibly bogus inodes */ for (i = 0; i < mp->m_sb.sb_agcount; i++) { check_uncertain_aginodes(mp, i); PROG_RPT_INC(prog_rpt_done[i], 1); } print_final_rpt(); /* ok, now that the tree's ok, let's take a good look */ do_log(_( " - process known inodes and perform inode discovery...\n")); set_progress_msg(PROG_FMT_PROCESS_INO, (uint64_t) mp->m_sb.sb_icount); process_ags(mp); print_final_rpt(); /* * process newly discovered inode chunks */ do_log(_(" - process newly discovered inodes...\n")); set_progress_msg(PROG_FMT_NEW_INODES, (uint64_t) glob_agcount); counts = calloc(sizeof(*counts), mp->m_sb.sb_agcount); if (!counts) { do_abort(_("no memory for uncertain inode counts\n")); return; } do { /* * have to loop until no ag has any uncertain * inodes */ j = 0; memset(counts, 0, mp->m_sb.sb_agcount * sizeof(*counts)); create_work_queue(&wq, mp, scan_threads); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&wq, do_uncertain_aginodes, i, &counts[i]); destroy_work_queue(&wq); /* tally up the counts */ for (i = 0; i < mp->m_sb.sb_agcount; i++) j += counts[i]; } while (j != 0); free(counts); print_final_rpt(); } xfsprogs-5.3.0/repair/phase4.c0000644000175000017500000002365513570057155016101 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "threads.h" #include "prefetch.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "bmap.h" #include "versions.h" #include "dir2.h" #include "progress.h" #include "slab.h" #include "rmap.h" bool collect_rmaps; /* * null out quota inode fields in sb if they point to non-existent inodes. * this isn't as redundant as it looks since it's possible that the sb field * might be set but the imap and inode(s) agree that the inode is * free in which case they'd never be cleared so the fields wouldn't * be cleared by process_dinode(). */ static void quotino_check(xfs_mount_t *mp) { ino_tree_node_t *irec; if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) { if (verify_inum(mp, mp->m_sb.sb_uquotino)) irec = NULL; else irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)); if (irec == NULL || is_inode_free(irec, mp->m_sb.sb_uquotino - irec->ino_startnum)) { mp->m_sb.sb_uquotino = NULLFSINO; lost_uquotino = 1; } else lost_uquotino = 0; } if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) { if (verify_inum(mp, mp->m_sb.sb_gquotino)) irec = NULL; else irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)); if (irec == NULL || is_inode_free(irec, mp->m_sb.sb_gquotino - irec->ino_startnum)) { mp->m_sb.sb_gquotino = NULLFSINO; lost_gquotino = 1; } else lost_gquotino = 0; } if (mp->m_sb.sb_pquotino != NULLFSINO && mp->m_sb.sb_pquotino != 0) { if (verify_inum(mp, mp->m_sb.sb_pquotino)) irec = NULL; else irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_pquotino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino)); if (irec == NULL || is_inode_free(irec, mp->m_sb.sb_pquotino - irec->ino_startnum)) { mp->m_sb.sb_pquotino = NULLFSINO; lost_pquotino = 1; } else lost_pquotino = 0; } } static void quota_sb_check(xfs_mount_t *mp) { /* * if the sb says we have quotas and we lost both, * signal a superblock downgrade. that will cause * the quota flags to get zeroed. (if we only lost * one quota inode, do nothing and complain later.) * * if the sb says we have quotas but we didn't start out * with any quota inodes, signal a superblock downgrade. * * The sb downgrades are so that older systems can mount * the filesystem. * * if the sb says we don't have quotas but it looks like * we do have quota inodes, then signal a superblock upgrade. * * if the sb says we don't have quotas and we have no * quota inodes, then leave will enough alone. */ if (fs_quotas && (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) && (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0) && (mp->m_sb.sb_pquotino == NULLFSINO || mp->m_sb.sb_pquotino == 0)) { lost_quotas = 1; fs_quotas = 0; } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) && !verify_inum(mp, mp->m_sb.sb_gquotino) && !verify_inum(mp, mp->m_sb.sb_pquotino)) { fs_quotas = 1; } } static void process_ag_func( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { wait_for_inode_prefetch(arg); do_log(_(" - agno = %d\n"), agno); process_aginodes(wq->wq_ctx, arg, agno, 0, 1, 0); blkmap_free_final(); cleanup_inode_prefetch(arg); /* * now recycle the per-AG duplicate extent records */ release_dup_extent_tree(agno); } static void process_ags( xfs_mount_t *mp) { xfs_agnumber_t i; int error; do_inode_prefetch(mp, ag_stride, process_ag_func, true, false); for (i = 0; i < mp->m_sb.sb_agcount; i++) { error = rmap_finish_collecting_fork_recs(mp, i); if (error) do_error( _("unable to finish adding attr/data fork reverse-mapping data for AG %u.\n"), i); } } static void check_rmap_btrees( struct workqueue*wq, xfs_agnumber_t agno, void *arg) { int error; error = rmap_add_fixed_ag_rec(wq->wq_ctx, agno); if (error) do_error( _("unable to add AG %u metadata reverse-mapping data.\n"), agno); error = rmap_fold_raw_recs(wq->wq_ctx, agno); if (error) do_error( _("unable to merge AG %u metadata reverse-mapping data.\n"), agno); error = rmaps_verify_btree(wq->wq_ctx, agno); if (error) do_error( _("%s while checking reverse-mappings"), strerror(-error)); } static void compute_ag_refcounts( struct workqueue*wq, xfs_agnumber_t agno, void *arg) { int error; error = compute_refcounts(wq->wq_ctx, agno); if (error) do_error( _("%s while computing reference count records.\n"), strerror(-error)); } static void process_inode_reflink_flags( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { int error; error = fix_inode_reflink_flags(wq->wq_ctx, agno); if (error) do_error( _("%s while fixing inode reflink flags.\n"), strerror(-error)); } static void check_refcount_btrees( struct workqueue*wq, xfs_agnumber_t agno, void *arg) { int error; error = check_refcounts(wq->wq_ctx, agno); if (error) do_error( _("%s while checking reference counts"), strerror(-error)); } static void process_rmap_data( struct xfs_mount *mp) { struct workqueue wq; xfs_agnumber_t i; if (!rmap_needs_work(mp)) return; create_work_queue(&wq, mp, platform_nproc()); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&wq, check_rmap_btrees, i, NULL); destroy_work_queue(&wq); if (!xfs_sb_version_hasreflink(&mp->m_sb)) return; create_work_queue(&wq, mp, platform_nproc()); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&wq, compute_ag_refcounts, i, NULL); destroy_work_queue(&wq); create_work_queue(&wq, mp, platform_nproc()); for (i = 0; i < mp->m_sb.sb_agcount; i++) { queue_work(&wq, process_inode_reflink_flags, i, NULL); queue_work(&wq, check_refcount_btrees, i, NULL); } destroy_work_queue(&wq); } void phase4(xfs_mount_t *mp) { ino_tree_node_t *irec; xfs_rtblock_t bno; xfs_rtblock_t rt_start; xfs_extlen_t rt_len; xfs_agnumber_t i; xfs_agblock_t j; xfs_agblock_t ag_end; xfs_extlen_t blen; int ag_hdr_len = 4 * mp->m_sb.sb_sectsize; int ag_hdr_block; int bstate; if (rmap_needs_work(mp)) collect_rmaps = true; ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize); do_log(_("Phase 4 - check for duplicate blocks...\n")); do_log(_(" - setting up duplicate extent list...\n")); set_progress_msg(PROG_FMT_DUP_EXTENT, (uint64_t) glob_agcount); irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); /* * we always have a root inode, even if it's free... * if the root is free, forget it, lost+found is already gone */ if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) { need_root_inode = 1; if (no_modify) do_warn(_("root inode would be lost\n")); else do_warn(_("root inode lost\n")); } for (i = 0; i < mp->m_sb.sb_agcount; i++) { ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i; /* * set up duplicate extent list for this ag */ for (j = ag_hdr_block; j < ag_end; j += blen) { bstate = get_bmap_ext(i, j, ag_end, &blen); switch (bstate) { case XR_E_BAD_STATE: default: do_warn( _("unknown block state, ag %d, block %d\n"), i, j); /* fall through .. */ case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: case XR_E_INUSE: case XR_E_INUSE_FS: case XR_E_INO: case XR_E_FS_MAP: break; case XR_E_MULT: add_dup_extent(i, j, blen); break; } } PROG_RPT_INC(prog_rpt_done[i], 1); } print_final_rpt(); /* * initialize realtime bitmap */ rt_start = 0; rt_len = 0; for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) { bstate = get_rtbmap(bno); switch (bstate) { case XR_E_BAD_STATE: default: do_warn( _("unknown rt extent state, extent %" PRIu64 "\n"), bno); /* fall through .. */ case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: case XR_E_INUSE: case XR_E_INUSE_FS: case XR_E_INO: case XR_E_FS_MAP: if (rt_start == 0) continue; else { /* * add extent and reset extent state */ add_rt_dup_extent(rt_start, rt_len); rt_start = 0; rt_len = 0; } break; case XR_E_MULT: if (rt_start == 0) { rt_start = bno; rt_len = 1; } else if (rt_len == MAXEXTLEN) { /* * large extent case */ add_rt_dup_extent(rt_start, rt_len); rt_start = bno; rt_len = 1; } else rt_len++; break; } } /* * catch tail-case, extent hitting the end of the ag */ if (rt_start != 0) add_rt_dup_extent(rt_start, rt_len); /* * initialize bitmaps for all AGs */ reset_bmaps(mp); do_log(_(" - check for inodes claiming duplicate blocks...\n")); set_progress_msg(PROG_FMT_DUP_BLOCKS, (uint64_t) mp->m_sb.sb_icount); /* * ok, now process the inodes -- signal 2-pass check per inode. * first pass checks if the inode conflicts with a known * duplicate extent. if so, the inode is cleared and second * pass is skipped. second pass sets the block bitmap * for all blocks claimed by the inode. directory * and attribute processing is turned OFF since we did that * already in phase 3. */ process_ags(mp); /* * Process all the reverse-mapping data that we collected. This * involves checking the rmap data against the btree, computing * reference counts based on the rmap data, and checking the counts * against the refcount btree. */ process_rmap_data(mp); print_final_rpt(); /* * free up memory used to track trealtime duplicate extents */ if (rt_start != 0) free_rt_dup_extent_tree(mp); /* * ensure consistency of quota inode pointers in superblock, * make sure they point to real inodes */ quotino_check(mp); quota_sb_check(mp); } xfsprogs-5.3.0/repair/phase5.c0000644000175000017500000021103113570057155016065 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "rt.h" #include "versions.h" #include "threads.h" #include "progress.h" #include "slab.h" #include "rmap.h" /* * we maintain the current slice (path from root to leaf) * of the btree incore. when we need a new block, we ask * the block allocator for the address of a block on that * level, map the block in, and set up the appropriate * pointers (child, silbing, etc.) and keys that should * point to the new block. */ typedef struct bt_stat_level { /* * set in setup_cursor routine and maintained in the tree-building * routines */ xfs_buf_t *buf_p; /* 2 buffer pointers to ... */ xfs_buf_t *prev_buf_p; xfs_agblock_t agbno; /* current block being filled */ xfs_agblock_t prev_agbno; /* previous block */ /* * set in calculate/init cursor routines for each btree level */ int num_recs_tot; /* # tree recs in level */ int num_blocks; /* # tree blocks in level */ int num_recs_pb; /* num_recs_tot / num_blocks */ int modulo; /* num_recs_tot % num_blocks */ } bt_stat_level_t; typedef struct bt_status { int init; /* cursor set up once? */ int num_levels; /* # of levels in btree */ xfs_extlen_t num_tot_blocks; /* # blocks alloc'ed for tree */ xfs_extlen_t num_free_blocks;/* # blocks currently unused */ xfs_agblock_t root; /* root block */ /* * list of blocks to be used to set up this tree * and pointer to the first unused block on the list */ xfs_agblock_t *btree_blocks; /* block list */ xfs_agblock_t *free_btree_blocks; /* first unused block */ /* * per-level status info */ bt_stat_level_t level[XFS_BTREE_MAXLEVELS]; uint64_t owner; /* owner */ } bt_status_t; /* * extra metadata for the agi */ struct agi_stat { xfs_agino_t first_agino; xfs_agino_t count; xfs_agino_t freecount; }; static uint64_t *sb_icount_ag; /* allocated inodes per ag */ static uint64_t *sb_ifree_ag; /* free inodes per ag */ static uint64_t *sb_fdblocks_ag; /* free data blocks per ag */ static int mk_incore_fstree(xfs_mount_t *mp, xfs_agnumber_t agno) { int in_extent; int num_extents; xfs_agblock_t extent_start; xfs_extlen_t extent_len; xfs_agblock_t agbno; xfs_agblock_t ag_end; uint free_blocks; xfs_extlen_t blen; int bstate; /* * scan the bitmap for the ag looking for continuous * extents of free blocks. At this point, we know * that blocks in the bitmap are either set to an * "in use" state or set to unknown (0) since the * bmaps were zero'ed in phase 4 and only blocks * being used by inodes, inode bmaps, ag headers, * and the files themselves were put into the bitmap. * */ ASSERT(agno < mp->m_sb.sb_agcount); extent_start = extent_len = 0; in_extent = 0; num_extents = free_blocks = 0; if (agno < mp->m_sb.sb_agcount - 1) ag_end = mp->m_sb.sb_agblocks; else ag_end = mp->m_sb.sb_dblocks - (xfs_rfsblock_t)mp->m_sb.sb_agblocks * (mp->m_sb.sb_agcount - 1); /* * ok, now find the number of extents, keep track of the * largest extent. */ for (agbno = 0; agbno < ag_end; agbno += blen) { bstate = get_bmap_ext(agno, agbno, ag_end, &blen); if (bstate < XR_E_INUSE) { free_blocks += blen; if (in_extent == 0) { /* * found the start of a free extent */ in_extent = 1; num_extents++; extent_start = agbno; extent_len = blen; } else { extent_len += blen; } } else { if (in_extent) { /* * free extent ends here, add extent to the * 2 incore extent (avl-to-be-B+) trees */ in_extent = 0; #if defined(XR_BLD_FREE_TRACE) && defined(XR_BLD_ADD_EXTENT) fprintf(stderr, "adding extent %u [%u %u]\n", agno, extent_start, extent_len); #endif add_bno_extent(agno, extent_start, extent_len); add_bcnt_extent(agno, extent_start, extent_len); } } } if (in_extent) { /* * free extent ends here */ #if defined(XR_BLD_FREE_TRACE) && defined(XR_BLD_ADD_EXTENT) fprintf(stderr, "adding extent %u [%u %u]\n", agno, extent_start, extent_len); #endif add_bno_extent(agno, extent_start, extent_len); add_bcnt_extent(agno, extent_start, extent_len); } return(num_extents); } static xfs_agblock_t get_next_blockaddr(xfs_agnumber_t agno, int level, bt_status_t *curs) { ASSERT(curs->free_btree_blocks < curs->btree_blocks + curs->num_tot_blocks); ASSERT(curs->num_free_blocks > 0); curs->num_free_blocks--; return(*curs->free_btree_blocks++); } /* * set up the dynamically allocated block allocation data in the btree * cursor that depends on the info in the static portion of the cursor. * allocates space from the incore bno/bcnt extent trees and sets up * the first path up the left side of the tree. Also sets up the * cursor pointer to the btree root. called by init_freespace_cursor() * and init_ino_cursor() */ static void setup_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *curs) { int j; unsigned int u; xfs_extlen_t big_extent_len; xfs_agblock_t big_extent_start; extent_tree_node_t *ext_ptr; extent_tree_node_t *bno_ext_ptr; xfs_extlen_t blocks_allocated; xfs_agblock_t *agb_ptr; int error; /* * get the number of blocks we need to allocate, then * set up block number array, set the free block pointer * to the first block in the array, and null the array */ big_extent_len = curs->num_tot_blocks; blocks_allocated = 0; ASSERT(big_extent_len > 0); if ((curs->btree_blocks = malloc(sizeof(xfs_agblock_t) * big_extent_len)) == NULL) do_error(_("could not set up btree block array\n")); agb_ptr = curs->free_btree_blocks = curs->btree_blocks; for (j = 0; j < curs->num_free_blocks; j++, agb_ptr++) *agb_ptr = NULLAGBLOCK; /* * grab the smallest extent and use it up, then get the * next smallest. This mimics the init_*_cursor code. */ ext_ptr = findfirst_bcnt_extent(agno); agb_ptr = curs->btree_blocks; /* * set up the free block array */ while (blocks_allocated < big_extent_len) { if (!ext_ptr) do_error( _("error - not enough free space in filesystem\n")); /* * use up the extent we've got */ for (u = 0; u < ext_ptr->ex_blockcount && blocks_allocated < big_extent_len; u++) { ASSERT(agb_ptr < curs->btree_blocks + curs->num_tot_blocks); *agb_ptr++ = ext_ptr->ex_startblock + u; blocks_allocated++; } error = rmap_add_ag_rec(mp, agno, ext_ptr->ex_startblock, u, curs->owner); if (error) do_error(_("could not set up btree rmaps: %s\n"), strerror(-error)); /* * if we only used part of this last extent, then we * need only to reset the extent in the extent * trees and we're done */ if (u < ext_ptr->ex_blockcount) { big_extent_start = ext_ptr->ex_startblock + u; big_extent_len = ext_ptr->ex_blockcount - u; ASSERT(big_extent_len > 0); bno_ext_ptr = find_bno_extent(agno, ext_ptr->ex_startblock); ASSERT(bno_ext_ptr != NULL); get_bno_extent(agno, bno_ext_ptr); release_extent_tree_node(bno_ext_ptr); ext_ptr = get_bcnt_extent(agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); release_extent_tree_node(ext_ptr); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "releasing extent: %u [%u %u]\n", agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); fprintf(stderr, "blocks_allocated = %d\n", blocks_allocated); #endif add_bno_extent(agno, big_extent_start, big_extent_len); add_bcnt_extent(agno, big_extent_start, big_extent_len); return; } /* * delete the used-up extent from both extent trees and * find next biggest extent */ #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "releasing extent: %u [%u %u]\n", agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); #endif bno_ext_ptr = find_bno_extent(agno, ext_ptr->ex_startblock); ASSERT(bno_ext_ptr != NULL); get_bno_extent(agno, bno_ext_ptr); release_extent_tree_node(bno_ext_ptr); ext_ptr = get_bcnt_extent(agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); ASSERT(ext_ptr != NULL); release_extent_tree_node(ext_ptr); ext_ptr = findfirst_bcnt_extent(agno); } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "blocks_allocated = %d\n", blocks_allocated); #endif } static void write_cursor(bt_status_t *curs) { int i; for (i = 0; i < curs->num_levels; i++) { #if defined(XR_BLD_FREE_TRACE) || defined(XR_BLD_INO_TRACE) fprintf(stderr, "writing bt block %u\n", curs->level[i].agbno); #endif if (curs->level[i].prev_buf_p != NULL) { ASSERT(curs->level[i].prev_agbno != NULLAGBLOCK); #if defined(XR_BLD_FREE_TRACE) || defined(XR_BLD_INO_TRACE) fprintf(stderr, "writing bt prev block %u\n", curs->level[i].prev_agbno); #endif libxfs_writebuf(curs->level[i].prev_buf_p, 0); } libxfs_writebuf(curs->level[i].buf_p, 0); } } static void finish_cursor(bt_status_t *curs) { ASSERT(curs->num_free_blocks == 0); free(curs->btree_blocks); } /* * We need to leave some free records in the tree for the corner case of * setting up the AGFL. This may require allocation of blocks, and as * such can require insertion of new records into the tree (e.g. moving * a record in the by-count tree when a long extent is shortened). If we * pack the records into the leaves with no slack space, this requires a * leaf split to occur and a block to be allocated from the free list. * If we don't have any blocks on the free list (because we are setting * it up!), then we fail, and the filesystem will fail with the same * failure at runtime. Hence leave a couple of records slack space in * each block to allow immediate modification of the tree without * requiring splits to be done. * * XXX(hch): any reason we don't just look at mp->m_alloc_mxr? */ #define XR_ALLOC_BLOCK_MAXRECS(mp, level) \ (libxfs_allocbt_maxrecs((mp), (mp)->m_sb.sb_blocksize, (level) == 0) - 2) /* * this calculates a freespace cursor for an ag. * btree_curs is an in/out. returns the number of * blocks that will show up in the AGFL. */ static int calculate_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t *extents, bt_status_t *btree_curs) { xfs_extlen_t blocks_needed; /* a running count */ xfs_extlen_t blocks_allocated_pt; /* per tree */ xfs_extlen_t blocks_allocated_total; /* for both trees */ xfs_agblock_t num_extents; int i; int extents_used; int extra_blocks; bt_stat_level_t *lptr; bt_stat_level_t *p_lptr; extent_tree_node_t *ext_ptr; int level; num_extents = *extents; extents_used = 0; ASSERT(num_extents != 0); lptr = &btree_curs->level[0]; btree_curs->init = 1; /* * figure out how much space we need for the leaf level * of the tree and set up the cursor for the leaf level * (note that the same code is duplicated further down) */ lptr->num_blocks = howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0)); lptr->num_recs_pb = num_extents / lptr->num_blocks; lptr->modulo = num_extents % lptr->num_blocks; lptr->num_recs_tot = num_extents; level = 1; #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "%s 0 %d %d %d %d\n", __func__, lptr->num_blocks, lptr->num_recs_pb, lptr->modulo, lptr->num_recs_tot); #endif /* * if we need more levels, set them up. # of records * per level is the # of blocks in the level below it */ if (lptr->num_blocks > 1) { for (; btree_curs->level[level - 1].num_blocks > 1 && level < XFS_BTREE_MAXLEVELS; level++) { lptr = &btree_curs->level[level]; p_lptr = &btree_curs->level[level - 1]; lptr->num_blocks = howmany(p_lptr->num_blocks, XR_ALLOC_BLOCK_MAXRECS(mp, level)); lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; lptr->num_recs_pb = p_lptr->num_blocks / lptr->num_blocks; lptr->num_recs_tot = p_lptr->num_blocks; #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "%s %d %d %d %d %d\n", __func__, level, lptr->num_blocks, lptr->num_recs_pb, lptr->modulo, lptr->num_recs_tot); #endif } } ASSERT(lptr->num_blocks == 1); btree_curs->num_levels = level; /* * ok, now we have a hypothetical cursor that * will work for both the bno and bcnt trees. * now figure out if using up blocks to set up the * trees will perturb the shape of the freespace tree. * if so, we've over-allocated. the freespace trees * as they will be *after* accounting for the free space * we've used up will need fewer blocks to to represent * than we've allocated. We can use the AGFL to hold * xfs_agfl_size (sector/xfs_agfl_t) blocks but that's it. * Thus we limit things to xfs_agfl_size/2 for each of the 2 btrees. * if the number of extra blocks is more than that, * we'll have to be called again. */ for (blocks_needed = 0, i = 0; i < level; i++) { blocks_needed += btree_curs->level[i].num_blocks; } /* * record the # of blocks we've allocated */ blocks_allocated_pt = blocks_needed; blocks_needed *= 2; blocks_allocated_total = blocks_needed; /* * figure out how many free extents will be used up by * our space allocation */ if ((ext_ptr = findfirst_bcnt_extent(agno)) == NULL) do_error(_("can't rebuild fs trees -- not enough free space " "on ag %u\n"), agno); while (ext_ptr != NULL && blocks_needed > 0) { if (ext_ptr->ex_blockcount <= blocks_needed) { blocks_needed -= ext_ptr->ex_blockcount; extents_used++; } else { blocks_needed = 0; } ext_ptr = findnext_bcnt_extent(agno, ext_ptr); #ifdef XR_BLD_FREE_TRACE if (ext_ptr != NULL) { fprintf(stderr, "got next extent [%u %u]\n", ext_ptr->ex_startblock, ext_ptr->ex_blockcount); } else { fprintf(stderr, "out of extents\n"); } #endif } if (blocks_needed > 0) do_error(_("ag %u - not enough free space to build freespace " "btrees\n"), agno); ASSERT(num_extents >= extents_used); num_extents -= extents_used; /* * see if the number of leaf blocks will change as a result * of the number of extents changing */ if (howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0)) != btree_curs->level[0].num_blocks) { /* * yes -- recalculate the cursor. If the number of * excess (overallocated) blocks is < xfs_agfl_size/2, we're ok. * we can put those into the AGFL. we don't try * and get things to converge exactly (reach a * state with zero excess blocks) because there * exist pathological cases which will never * converge. first, check for the zero-case. */ if (num_extents == 0) { /* * ok, we've used up all the free blocks * trying to lay out the leaf level. go * to a one block (empty) btree and put the * already allocated blocks into the AGFL */ if (btree_curs->level[0].num_blocks != 1) { /* * we really needed more blocks because * the old tree had more than one level. * this is bad. */ do_warn(_("not enough free blocks left to " "describe all free blocks in AG " "%u\n"), agno); } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "ag %u -- no free extents, alloc'ed %d\n", agno, blocks_allocated_pt); #endif lptr->num_blocks = 1; lptr->modulo = 0; lptr->num_recs_pb = 0; lptr->num_recs_tot = 0; btree_curs->num_levels = 1; /* * don't reset the allocation stats, assume * they're all extra blocks * don't forget to return the total block count * not the per-tree block count. these are the * extras that will go into the AGFL. subtract * two for the root blocks. */ btree_curs->num_tot_blocks = blocks_allocated_pt; btree_curs->num_free_blocks = blocks_allocated_pt; *extents = 0; return(blocks_allocated_total - 2); } lptr = &btree_curs->level[0]; lptr->num_blocks = howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0)); lptr->num_recs_pb = num_extents / lptr->num_blocks; lptr->modulo = num_extents % lptr->num_blocks; lptr->num_recs_tot = num_extents; level = 1; /* * if we need more levels, set them up */ if (lptr->num_blocks > 1) { for (level = 1; btree_curs->level[level-1].num_blocks > 1 && level < XFS_BTREE_MAXLEVELS; level++) { lptr = &btree_curs->level[level]; p_lptr = &btree_curs->level[level-1]; lptr->num_blocks = howmany(p_lptr->num_blocks, XR_ALLOC_BLOCK_MAXRECS(mp, level)); lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; lptr->num_recs_pb = p_lptr->num_blocks / lptr->num_blocks; lptr->num_recs_tot = p_lptr->num_blocks; } } ASSERT(lptr->num_blocks == 1); btree_curs->num_levels = level; /* * now figure out the number of excess blocks */ for (blocks_needed = 0, i = 0; i < level; i++) { blocks_needed += btree_curs->level[i].num_blocks; } blocks_needed *= 2; ASSERT(blocks_allocated_total >= blocks_needed); extra_blocks = blocks_allocated_total - blocks_needed; } else { if (extents_used > 0) { /* * reset the leaf level geometry to account * for consumed extents. we can leave the * rest of the cursor alone since the number * of leaf blocks hasn't changed. */ lptr = &btree_curs->level[0]; lptr->num_recs_pb = num_extents / lptr->num_blocks; lptr->modulo = num_extents % lptr->num_blocks; lptr->num_recs_tot = num_extents; } extra_blocks = 0; } btree_curs->num_tot_blocks = blocks_allocated_pt; btree_curs->num_free_blocks = blocks_allocated_pt; *extents = num_extents; return(extra_blocks); } /* Map btnum to buffer ops for the types that need it. */ static const struct xfs_buf_ops * btnum_to_ops( xfs_btnum_t btnum) { switch (btnum) { case XFS_BTNUM_BNO: return &xfs_bnobt_buf_ops; case XFS_BTNUM_CNT: return &xfs_cntbt_buf_ops; case XFS_BTNUM_INO: return &xfs_inobt_buf_ops; case XFS_BTNUM_FINO: return &xfs_finobt_buf_ops; case XFS_BTNUM_RMAP: return &xfs_rmapbt_buf_ops; case XFS_BTNUM_REFC: return &xfs_refcountbt_buf_ops; default: ASSERT(0); return NULL; } } static void prop_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_agblock_t startblock, xfs_extlen_t blockcount, int level, xfs_btnum_t btnum) { struct xfs_btree_block *bt_hdr; xfs_alloc_key_t *bt_key; xfs_alloc_ptr_t *bt_ptr; xfs_agblock_t agbno; bt_stat_level_t *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(btnum); ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); level++; if (level >= btree_curs->num_levels) return; lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); if (be16_to_cpu(bt_hdr->bb_numrecs) == 0) { /* * only happens once when initializing the * left-hand side of the tree. */ prop_freespace_cursor(mp, agno, btree_curs, startblock, blockcount, level, btnum); } if (be16_to_cpu(bt_hdr->bb_numrecs) == lptr->num_recs_pb + (lptr->modulo > 0)) { /* * write out current prev block, grab us a new block, * and set the rightsib pointer of current block */ #ifdef XR_BLD_FREE_TRACE fprintf(stderr, " %d ", lptr->prev_agbno); #endif if (lptr->prev_agbno != NULLAGBLOCK) { ASSERT(lptr->prev_buf_p != NULL); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_agbno = lptr->agbno;; lptr->prev_buf_p = lptr->buf_p; agbno = get_next_blockaddr(agno, level, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); lptr->agbno = agbno; if (lptr->modulo) lptr->modulo--; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, btnum, level, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); /* * propagate extent record for first extent in new block up */ prop_freespace_cursor(mp, agno, btree_curs, startblock, blockcount, level, btnum); } /* * add extent info to current block */ be16_add_cpu(&bt_hdr->bb_numrecs, 1); bt_key = XFS_ALLOC_KEY_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs)); bt_ptr = XFS_ALLOC_PTR_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs), mp->m_alloc_mxr[1]); bt_key->ar_startblock = cpu_to_be32(startblock); bt_key->ar_blockcount = cpu_to_be32(blockcount); *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); } /* * rebuilds a freespace tree given a cursor and type * of tree to build (bno or bcnt). returns the number of free blocks * represented by the tree. */ static xfs_extlen_t build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_btnum_t btnum) { xfs_agnumber_t i; xfs_agblock_t j; struct xfs_btree_block *bt_hdr; xfs_alloc_rec_t *bt_rec; int level; xfs_agblock_t agbno; extent_tree_node_t *ext_ptr; bt_stat_level_t *lptr; xfs_extlen_t freeblks; const struct xfs_buf_ops *ops = btnum_to_ops(btnum); ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "in build_freespace_tree, agno = %d\n", agno); #endif level = btree_curs->num_levels; freeblks = 0; ASSERT(level > 0); /* * initialize the first block on each btree level */ for (i = 0; i < level; i++) { lptr = &btree_curs->level[i]; agbno = get_next_blockaddr(agno, i, btree_curs); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); if (i == btree_curs->num_levels - 1) btree_curs->root = agbno; lptr->agbno = agbno; lptr->prev_agbno = NULLAGBLOCK; lptr->prev_buf_p = NULL; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, btnum, i, 0, agno); } /* * run along leaf, setting up records. as we have to switch * blocks, call the prop_freespace_cursor routine to set up the new * pointers for the parent. that can recurse up to the root * if required. set the sibling pointers for leaf level here. */ if (btnum == XFS_BTNUM_BNO) ext_ptr = findfirst_bno_extent(agno); else ext_ptr = findfirst_bcnt_extent(agno); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "bft, agno = %d, start = %u, count = %u\n", agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); #endif lptr = &btree_curs->level[0]; for (i = 0; i < btree_curs->level[0].num_blocks; i++) { /* * block initialization, lay in block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, btnum, 0, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb + (lptr->modulo > 0)); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "bft, bb_numrecs = %d\n", be16_to_cpu(bt_hdr->bb_numrecs)); #endif if (lptr->modulo > 0) lptr->modulo--; /* * initialize values in the path up to the root if * this is a multi-level btree */ if (btree_curs->num_levels > 1) prop_freespace_cursor(mp, agno, btree_curs, ext_ptr->ex_startblock, ext_ptr->ex_blockcount, 0, btnum); bt_rec = (xfs_alloc_rec_t *) ((char *)bt_hdr + XFS_ALLOC_BLOCK_LEN(mp)); for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) { ASSERT(ext_ptr != NULL); bt_rec[j].ar_startblock = cpu_to_be32( ext_ptr->ex_startblock); bt_rec[j].ar_blockcount = cpu_to_be32( ext_ptr->ex_blockcount); freeblks += ext_ptr->ex_blockcount; if (btnum == XFS_BTNUM_BNO) ext_ptr = findnext_bno_extent(ext_ptr); else ext_ptr = findnext_bcnt_extent(agno, ext_ptr); #if 0 #ifdef XR_BLD_FREE_TRACE if (ext_ptr == NULL) fprintf(stderr, "null extent pointer, j = %d\n", j); else fprintf(stderr, "bft, agno = %d, start = %u, count = %u\n", agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); #endif #endif } if (ext_ptr != NULL) { /* * get next leaf level block */ if (lptr->prev_buf_p != NULL) { #ifdef XR_BLD_FREE_TRACE fprintf(stderr, " writing fst agbno %u\n", lptr->prev_agbno); #endif ASSERT(lptr->prev_agbno != NULLAGBLOCK); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_buf_p = lptr->buf_p; lptr->prev_agbno = lptr->agbno; lptr->agbno = get_next_blockaddr(agno, 0, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(lptr->agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), XFS_FSB_TO_BB(mp, 1)); } } return(freeblks); } /* * XXX(hch): any reason we don't just look at mp->m_inobt_mxr? */ #define XR_INOBT_BLOCK_MAXRECS(mp, level) \ libxfs_inobt_maxrecs((mp), (mp)->m_sb.sb_blocksize, \ (level) == 0) /* * we don't have to worry here about how chewing up free extents * may perturb things because inode tree building happens before * freespace tree building. */ static void init_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, uint64_t *num_inos, uint64_t *num_free_inos, int finobt) { uint64_t ninos; uint64_t nfinos; int rec_nfinos; int rec_ninos; ino_tree_node_t *ino_rec; int num_recs; int level; bt_stat_level_t *lptr; bt_stat_level_t *p_lptr; xfs_extlen_t blocks_allocated; int i; *num_inos = *num_free_inos = 0; ninos = nfinos = 0; lptr = &btree_curs->level[0]; btree_curs->init = 1; btree_curs->owner = XFS_RMAP_OWN_INOBT; /* * build up statistics */ ino_rec = findfirst_inode_rec(agno); for (num_recs = 0; ino_rec != NULL; ino_rec = next_ino_rec(ino_rec)) { rec_ninos = 0; rec_nfinos = 0; for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { ASSERT(is_inode_confirmed(ino_rec, i)); /* * sparse inodes are not factored into superblock (free) * inode counts */ if (is_inode_sparse(ino_rec, i)) continue; if (is_inode_free(ino_rec, i)) rec_nfinos++; rec_ninos++; } /* * finobt only considers records with free inodes */ if (finobt && !rec_nfinos) continue; nfinos += rec_nfinos; ninos += rec_ninos; num_recs++; } if (num_recs == 0) { /* * easy corner-case -- no inode records */ lptr->num_blocks = 1; lptr->modulo = 0; lptr->num_recs_pb = 0; lptr->num_recs_tot = 0; btree_curs->num_levels = 1; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = 1; setup_cursor(mp, agno, btree_curs); return; } blocks_allocated = lptr->num_blocks = howmany(num_recs, XR_INOBT_BLOCK_MAXRECS(mp, 0)); lptr->modulo = num_recs % lptr->num_blocks; lptr->num_recs_pb = num_recs / lptr->num_blocks; lptr->num_recs_tot = num_recs; level = 1; if (lptr->num_blocks > 1) { for (; btree_curs->level[level-1].num_blocks > 1 && level < XFS_BTREE_MAXLEVELS; level++) { lptr = &btree_curs->level[level]; p_lptr = &btree_curs->level[level - 1]; lptr->num_blocks = howmany(p_lptr->num_blocks, XR_INOBT_BLOCK_MAXRECS(mp, level)); lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; lptr->num_recs_pb = p_lptr->num_blocks / lptr->num_blocks; lptr->num_recs_tot = p_lptr->num_blocks; blocks_allocated += lptr->num_blocks; } } ASSERT(lptr->num_blocks == 1); btree_curs->num_levels = level; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = blocks_allocated; setup_cursor(mp, agno, btree_curs); *num_inos = ninos; *num_free_inos = nfinos; return; } static void prop_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_btnum_t btnum, xfs_agino_t startino, int level) { struct xfs_btree_block *bt_hdr; xfs_inobt_key_t *bt_key; xfs_inobt_ptr_t *bt_ptr; xfs_agblock_t agbno; bt_stat_level_t *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(btnum); level++; if (level >= btree_curs->num_levels) return; lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); if (be16_to_cpu(bt_hdr->bb_numrecs) == 0) { /* * this only happens once to initialize the * first path up the left side of the tree * where the agbno's are already set up */ prop_ino_cursor(mp, agno, btree_curs, btnum, startino, level); } if (be16_to_cpu(bt_hdr->bb_numrecs) == lptr->num_recs_pb + (lptr->modulo > 0)) { /* * write out current prev block, grab us a new block, * and set the rightsib pointer of current block */ #ifdef XR_BLD_INO_TRACE fprintf(stderr, " ino prop agbno %d ", lptr->prev_agbno); #endif if (lptr->prev_agbno != NULLAGBLOCK) { ASSERT(lptr->prev_buf_p != NULL); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_agbno = lptr->agbno;; lptr->prev_buf_p = lptr->buf_p; agbno = get_next_blockaddr(agno, level, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); lptr->agbno = agbno; if (lptr->modulo) lptr->modulo--; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, btnum, level, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); /* * propagate extent record for first extent in new block up */ prop_ino_cursor(mp, agno, btree_curs, btnum, startino, level); } /* * add inode info to current block */ be16_add_cpu(&bt_hdr->bb_numrecs, 1); bt_key = XFS_INOBT_KEY_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs)); bt_ptr = XFS_INOBT_PTR_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs), M_IGEO(mp)->inobt_mxr[1]); bt_key->ir_startino = cpu_to_be32(startino); *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); } /* * XXX: yet more code that can be shared with mkfs, growfs. */ static void build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, bt_status_t *finobt_curs, struct agi_stat *agi_stat) { xfs_buf_t *agi_buf; xfs_agi_t *agi; int i; agi_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); agi_buf->b_ops = &xfs_agi_buf_ops; agi = XFS_BUF_TO_AGI(agi_buf); memset(agi, 0, mp->m_sb.sb_sectsize); agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); agi->agi_seqno = cpu_to_be32(agno); if (agno < mp->m_sb.sb_agcount - 1) agi->agi_length = cpu_to_be32(mp->m_sb.sb_agblocks); else agi->agi_length = cpu_to_be32(mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno); agi->agi_count = cpu_to_be32(agi_stat->count); agi->agi_root = cpu_to_be32(btree_curs->root); agi->agi_level = cpu_to_be32(btree_curs->num_levels); agi->agi_freecount = cpu_to_be32(agi_stat->freecount); agi->agi_newino = cpu_to_be32(agi_stat->first_agino); agi->agi_dirino = cpu_to_be32(NULLAGINO); for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO); if (xfs_sb_version_hascrc(&mp->m_sb)) platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); if (xfs_sb_version_hasfinobt(&mp->m_sb)) { agi->agi_free_root = cpu_to_be32(finobt_curs->root); agi->agi_free_level = cpu_to_be32(finobt_curs->num_levels); } libxfs_writebuf(agi_buf, 0); } /* * rebuilds an inode tree given a cursor. We're lazy here and call * the routine that builds the agi */ static void build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_btnum_t btnum, struct agi_stat *agi_stat) { xfs_agnumber_t i; xfs_agblock_t j; xfs_agblock_t agbno; xfs_agino_t first_agino; struct xfs_btree_block *bt_hdr; xfs_inobt_rec_t *bt_rec; ino_tree_node_t *ino_rec; bt_stat_level_t *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(btnum); xfs_agino_t count = 0; xfs_agino_t freecount = 0; int inocnt; uint8_t finocnt; int k; int level = btree_curs->num_levels; int spmask; uint64_t sparse; uint16_t holemask; ASSERT(btnum == XFS_BTNUM_INO || btnum == XFS_BTNUM_FINO); for (i = 0; i < level; i++) { lptr = &btree_curs->level[i]; agbno = get_next_blockaddr(agno, i, btree_curs); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); if (i == btree_curs->num_levels - 1) btree_curs->root = agbno; lptr->agbno = agbno; lptr->prev_agbno = NULLAGBLOCK; lptr->prev_buf_p = NULL; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, btnum, i, 0, agno); } /* * run along leaf, setting up records. as we have to switch * blocks, call the prop_ino_cursor routine to set up the new * pointers for the parent. that can recurse up to the root * if required. set the sibling pointers for leaf level here. */ if (btnum == XFS_BTNUM_FINO) ino_rec = findfirst_free_inode_rec(agno); else ino_rec = findfirst_inode_rec(agno); if (ino_rec != NULL) first_agino = ino_rec->ino_startnum; else first_agino = NULLAGINO; lptr = &btree_curs->level[0]; for (i = 0; i < lptr->num_blocks; i++) { /* * block initialization, lay in block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, btnum, 0, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb + (lptr->modulo > 0)); if (lptr->modulo > 0) lptr->modulo--; if (lptr->num_recs_pb > 0) prop_ino_cursor(mp, agno, btree_curs, btnum, ino_rec->ino_startnum, 0); bt_rec = (xfs_inobt_rec_t *) ((char *)bt_hdr + XFS_INOBT_BLOCK_LEN(mp)); for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) { ASSERT(ino_rec != NULL); bt_rec[j].ir_startino = cpu_to_be32(ino_rec->ino_startnum); bt_rec[j].ir_free = cpu_to_be64(ino_rec->ir_free); inocnt = finocnt = 0; for (k = 0; k < sizeof(xfs_inofree_t)*NBBY; k++) { ASSERT(is_inode_confirmed(ino_rec, k)); if (is_inode_sparse(ino_rec, k)) continue; if (is_inode_free(ino_rec, k)) finocnt++; inocnt++; } /* * Set the freecount and check whether we need to update * the sparse format fields. Otherwise, skip to the next * record. */ inorec_set_freecount(mp, &bt_rec[j], finocnt); if (!xfs_sb_version_hassparseinodes(&mp->m_sb)) goto nextrec; /* * Convert the 64-bit in-core sparse inode state to the * 16-bit on-disk holemask. */ holemask = 0; spmask = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1; sparse = ino_rec->ir_sparse; for (k = 0; k < XFS_INOBT_HOLEMASK_BITS; k++) { if (sparse & spmask) { ASSERT((sparse & spmask) == spmask); holemask |= (1 << k); } else ASSERT((sparse & spmask) == 0); sparse >>= XFS_INODES_PER_HOLEMASK_BIT; } bt_rec[j].ir_u.sp.ir_count = inocnt; bt_rec[j].ir_u.sp.ir_holemask = cpu_to_be16(holemask); nextrec: freecount += finocnt; count += inocnt; if (btnum == XFS_BTNUM_FINO) ino_rec = next_free_ino_rec(ino_rec); else ino_rec = next_ino_rec(ino_rec); } if (ino_rec != NULL) { /* * get next leaf level block */ if (lptr->prev_buf_p != NULL) { #ifdef XR_BLD_INO_TRACE fprintf(stderr, "writing inobt agbno %u\n", lptr->prev_agbno); #endif ASSERT(lptr->prev_agbno != NULLAGBLOCK); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_buf_p = lptr->buf_p; lptr->prev_agbno = lptr->agbno; lptr->agbno = get_next_blockaddr(agno, 0, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(lptr->agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), XFS_FSB_TO_BB(mp, 1)); } } if (agi_stat) { agi_stat->first_agino = first_agino; agi_stat->count = count; agi_stat->freecount = freecount; } } /* rebuild the rmap tree */ /* * we don't have to worry here about how chewing up free extents * may perturb things because rmap tree building happens before * freespace tree building. */ static void init_rmapbt_cursor( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs) { size_t num_recs; int level; struct bt_stat_level *lptr; struct bt_stat_level *p_lptr; xfs_extlen_t blocks_allocated; int maxrecs; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) { memset(btree_curs, 0, sizeof(struct bt_status)); return; } lptr = &btree_curs->level[0]; btree_curs->init = 1; btree_curs->owner = XFS_RMAP_OWN_AG; /* * build up statistics */ num_recs = rmap_record_count(mp, agno); if (num_recs == 0) { /* * easy corner-case -- no rmap records */ lptr->num_blocks = 1; lptr->modulo = 0; lptr->num_recs_pb = 0; lptr->num_recs_tot = 0; btree_curs->num_levels = 1; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = 1; setup_cursor(mp, agno, btree_curs); return; } /* * Leave enough slack in the rmapbt that we can insert the * metadata AG entries without too many splits. */ maxrecs = mp->m_rmap_mxr[0]; if (num_recs > maxrecs) maxrecs -= 10; blocks_allocated = lptr->num_blocks = howmany(num_recs, maxrecs); lptr->modulo = num_recs % lptr->num_blocks; lptr->num_recs_pb = num_recs / lptr->num_blocks; lptr->num_recs_tot = num_recs; level = 1; if (lptr->num_blocks > 1) { for (; btree_curs->level[level-1].num_blocks > 1 && level < XFS_BTREE_MAXLEVELS; level++) { lptr = &btree_curs->level[level]; p_lptr = &btree_curs->level[level - 1]; lptr->num_blocks = howmany(p_lptr->num_blocks, mp->m_rmap_mxr[1]); lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; lptr->num_recs_pb = p_lptr->num_blocks / lptr->num_blocks; lptr->num_recs_tot = p_lptr->num_blocks; blocks_allocated += lptr->num_blocks; } } ASSERT(lptr->num_blocks == 1); btree_curs->num_levels = level; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = blocks_allocated; setup_cursor(mp, agno, btree_curs); } static void prop_rmap_cursor( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs, struct xfs_rmap_irec *rm_rec, int level) { struct xfs_btree_block *bt_hdr; struct xfs_rmap_key *bt_key; xfs_rmap_ptr_t *bt_ptr; xfs_agblock_t agbno; struct bt_stat_level *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(XFS_BTNUM_RMAP); level++; if (level >= btree_curs->num_levels) return; lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); if (be16_to_cpu(bt_hdr->bb_numrecs) == 0) { /* * this only happens once to initialize the * first path up the left side of the tree * where the agbno's are already set up */ prop_rmap_cursor(mp, agno, btree_curs, rm_rec, level); } if (be16_to_cpu(bt_hdr->bb_numrecs) == lptr->num_recs_pb + (lptr->modulo > 0)) { /* * write out current prev block, grab us a new block, * and set the rightsib pointer of current block */ #ifdef XR_BLD_INO_TRACE fprintf(stderr, " rmap prop agbno %d ", lptr->prev_agbno); #endif if (lptr->prev_agbno != NULLAGBLOCK) { ASSERT(lptr->prev_buf_p != NULL); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_agbno = lptr->agbno; lptr->prev_buf_p = lptr->buf_p; agbno = get_next_blockaddr(agno, level, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); lptr->agbno = agbno; if (lptr->modulo) lptr->modulo--; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_RMAP, level, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); /* * propagate extent record for first extent in new block up */ prop_rmap_cursor(mp, agno, btree_curs, rm_rec, level); } /* * add rmap info to current block */ be16_add_cpu(&bt_hdr->bb_numrecs, 1); bt_key = XFS_RMAP_KEY_ADDR(bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs)); bt_ptr = XFS_RMAP_PTR_ADDR(bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs), mp->m_rmap_mxr[1]); bt_key->rm_startblock = cpu_to_be32(rm_rec->rm_startblock); bt_key->rm_owner = cpu_to_be64(rm_rec->rm_owner); bt_key->rm_offset = cpu_to_be64(rm_rec->rm_offset); *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); } static void prop_rmap_highkey( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs, struct xfs_rmap_irec *rm_highkey) { struct xfs_btree_block *bt_hdr; struct xfs_rmap_key *bt_key; struct bt_stat_level *lptr; struct xfs_rmap_irec key = {0}; struct xfs_rmap_irec high_key; int level; int i; int numrecs; high_key = *rm_highkey; for (level = 1; level < btree_curs->num_levels; level++) { lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); numrecs = be16_to_cpu(bt_hdr->bb_numrecs); bt_key = XFS_RMAP_HIGH_KEY_ADDR(bt_hdr, numrecs); bt_key->rm_startblock = cpu_to_be32(high_key.rm_startblock); bt_key->rm_owner = cpu_to_be64(high_key.rm_owner); bt_key->rm_offset = cpu_to_be64( libxfs_rmap_irec_offset_pack(&high_key)); for (i = 1; i <= numrecs; i++) { bt_key = XFS_RMAP_HIGH_KEY_ADDR(bt_hdr, i); key.rm_startblock = be32_to_cpu(bt_key->rm_startblock); key.rm_owner = be64_to_cpu(bt_key->rm_owner); key.rm_offset = be64_to_cpu(bt_key->rm_offset); if (rmap_diffkeys(&key, &high_key) > 0) high_key = key; } } } /* * rebuilds a rmap btree given a cursor. */ static void build_rmap_tree( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs) { xfs_agnumber_t i; xfs_agblock_t j; xfs_agblock_t agbno; struct xfs_btree_block *bt_hdr; struct xfs_rmap_irec *rm_rec; struct xfs_slab_cursor *rmap_cur; struct xfs_rmap_rec *bt_rec; struct xfs_rmap_irec highest_key = {0}; struct xfs_rmap_irec hi_key = {0}; struct bt_stat_level *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(XFS_BTNUM_RMAP); int numrecs; int level = btree_curs->num_levels; int error; highest_key.rm_flags = 0; for (i = 0; i < level; i++) { lptr = &btree_curs->level[i]; agbno = get_next_blockaddr(agno, i, btree_curs); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); if (i == btree_curs->num_levels - 1) btree_curs->root = agbno; lptr->agbno = agbno; lptr->prev_agbno = NULLAGBLOCK; lptr->prev_buf_p = NULL; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_RMAP, i, 0, agno); } /* * run along leaf, setting up records. as we have to switch * blocks, call the prop_rmap_cursor routine to set up the new * pointers for the parent. that can recurse up to the root * if required. set the sibling pointers for leaf level here. */ error = rmap_init_cursor(agno, &rmap_cur); if (error) do_error( _("Insufficient memory to construct reverse-map cursor.")); rm_rec = pop_slab_cursor(rmap_cur); lptr = &btree_curs->level[0]; for (i = 0; i < lptr->num_blocks; i++) { numrecs = lptr->num_recs_pb + (lptr->modulo > 0); ASSERT(rm_rec != NULL || numrecs == 0); /* * block initialization, lay in block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_RMAP, 0, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); bt_hdr->bb_numrecs = cpu_to_be16(numrecs); if (lptr->modulo > 0) lptr->modulo--; if (lptr->num_recs_pb > 0) { ASSERT(rm_rec != NULL); prop_rmap_cursor(mp, agno, btree_curs, rm_rec, 0); } bt_rec = (struct xfs_rmap_rec *) ((char *)bt_hdr + XFS_RMAP_BLOCK_LEN); highest_key.rm_startblock = 0; highest_key.rm_owner = 0; highest_key.rm_offset = 0; for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) { ASSERT(rm_rec != NULL); bt_rec[j].rm_startblock = cpu_to_be32(rm_rec->rm_startblock); bt_rec[j].rm_blockcount = cpu_to_be32(rm_rec->rm_blockcount); bt_rec[j].rm_owner = cpu_to_be64(rm_rec->rm_owner); bt_rec[j].rm_offset = cpu_to_be64( libxfs_rmap_irec_offset_pack(rm_rec)); rmap_high_key_from_rec(rm_rec, &hi_key); if (rmap_diffkeys(&hi_key, &highest_key) > 0) highest_key = hi_key; rm_rec = pop_slab_cursor(rmap_cur); } /* Now go set the parent key */ prop_rmap_highkey(mp, agno, btree_curs, &highest_key); if (rm_rec != NULL) { /* * get next leaf level block */ if (lptr->prev_buf_p != NULL) { #ifdef XR_BLD_RL_TRACE fprintf(stderr, "writing rmapbt agbno %u\n", lptr->prev_agbno); #endif ASSERT(lptr->prev_agbno != NULLAGBLOCK); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_buf_p = lptr->buf_p; lptr->prev_agbno = lptr->agbno; lptr->agbno = get_next_blockaddr(agno, 0, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(lptr->agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), XFS_FSB_TO_BB(mp, 1)); } } free_slab_cursor(&rmap_cur); } /* rebuild the refcount tree */ /* * we don't have to worry here about how chewing up free extents * may perturb things because reflink tree building happens before * freespace tree building. */ static void init_refc_cursor( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs) { size_t num_recs; int level; struct bt_stat_level *lptr; struct bt_stat_level *p_lptr; xfs_extlen_t blocks_allocated; if (!xfs_sb_version_hasreflink(&mp->m_sb)) { memset(btree_curs, 0, sizeof(struct bt_status)); return; } lptr = &btree_curs->level[0]; btree_curs->init = 1; btree_curs->owner = XFS_RMAP_OWN_REFC; /* * build up statistics */ num_recs = refcount_record_count(mp, agno); if (num_recs == 0) { /* * easy corner-case -- no refcount records */ lptr->num_blocks = 1; lptr->modulo = 0; lptr->num_recs_pb = 0; lptr->num_recs_tot = 0; btree_curs->num_levels = 1; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = 1; setup_cursor(mp, agno, btree_curs); return; } blocks_allocated = lptr->num_blocks = howmany(num_recs, mp->m_refc_mxr[0]); lptr->modulo = num_recs % lptr->num_blocks; lptr->num_recs_pb = num_recs / lptr->num_blocks; lptr->num_recs_tot = num_recs; level = 1; if (lptr->num_blocks > 1) { for (; btree_curs->level[level-1].num_blocks > 1 && level < XFS_BTREE_MAXLEVELS; level++) { lptr = &btree_curs->level[level]; p_lptr = &btree_curs->level[level - 1]; lptr->num_blocks = howmany(p_lptr->num_blocks, mp->m_refc_mxr[1]); lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; lptr->num_recs_pb = p_lptr->num_blocks / lptr->num_blocks; lptr->num_recs_tot = p_lptr->num_blocks; blocks_allocated += lptr->num_blocks; } } ASSERT(lptr->num_blocks == 1); btree_curs->num_levels = level; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = blocks_allocated; setup_cursor(mp, agno, btree_curs); } static void prop_refc_cursor( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs, xfs_agblock_t startbno, int level) { struct xfs_btree_block *bt_hdr; struct xfs_refcount_key *bt_key; xfs_refcount_ptr_t *bt_ptr; xfs_agblock_t agbno; struct bt_stat_level *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(XFS_BTNUM_REFC); level++; if (level >= btree_curs->num_levels) return; lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); if (be16_to_cpu(bt_hdr->bb_numrecs) == 0) { /* * this only happens once to initialize the * first path up the left side of the tree * where the agbno's are already set up */ prop_refc_cursor(mp, agno, btree_curs, startbno, level); } if (be16_to_cpu(bt_hdr->bb_numrecs) == lptr->num_recs_pb + (lptr->modulo > 0)) { /* * write out current prev block, grab us a new block, * and set the rightsib pointer of current block */ #ifdef XR_BLD_INO_TRACE fprintf(stderr, " ino prop agbno %d ", lptr->prev_agbno); #endif if (lptr->prev_agbno != NULLAGBLOCK) { ASSERT(lptr->prev_buf_p != NULL); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_agbno = lptr->agbno; lptr->prev_buf_p = lptr->buf_p; agbno = get_next_blockaddr(agno, level, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); lptr->agbno = agbno; if (lptr->modulo) lptr->modulo--; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_REFC, level, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); /* * propagate extent record for first extent in new block up */ prop_refc_cursor(mp, agno, btree_curs, startbno, level); } /* * add inode info to current block */ be16_add_cpu(&bt_hdr->bb_numrecs, 1); bt_key = XFS_REFCOUNT_KEY_ADDR(bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs)); bt_ptr = XFS_REFCOUNT_PTR_ADDR(bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs), mp->m_refc_mxr[1]); bt_key->rc_startblock = cpu_to_be32(startbno); *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); } /* * rebuilds a refcount btree given a cursor. */ static void build_refcount_tree( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *btree_curs) { xfs_agnumber_t i; xfs_agblock_t j; xfs_agblock_t agbno; struct xfs_btree_block *bt_hdr; struct xfs_refcount_irec *refc_rec; struct xfs_slab_cursor *refc_cur; struct xfs_refcount_rec *bt_rec; struct bt_stat_level *lptr; const struct xfs_buf_ops *ops = btnum_to_ops(XFS_BTNUM_REFC); int numrecs; int level = btree_curs->num_levels; int error; for (i = 0; i < level; i++) { lptr = &btree_curs->level[i]; agbno = get_next_blockaddr(agno, i, btree_curs); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); if (i == btree_curs->num_levels - 1) btree_curs->root = agbno; lptr->agbno = agbno; lptr->prev_agbno = NULLAGBLOCK; lptr->prev_buf_p = NULL; /* * initialize block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_REFC, i, 0, agno); } /* * run along leaf, setting up records. as we have to switch * blocks, call the prop_refc_cursor routine to set up the new * pointers for the parent. that can recurse up to the root * if required. set the sibling pointers for leaf level here. */ error = init_refcount_cursor(agno, &refc_cur); if (error) do_error( _("Insufficient memory to construct refcount cursor.")); refc_rec = pop_slab_cursor(refc_cur); lptr = &btree_curs->level[0]; for (i = 0; i < lptr->num_blocks; i++) { numrecs = lptr->num_recs_pb + (lptr->modulo > 0); ASSERT(refc_rec != NULL || numrecs == 0); /* * block initialization, lay in block header */ lptr->buf_p->b_ops = ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); libxfs_btree_init_block(mp, lptr->buf_p, XFS_BTNUM_REFC, 0, 0, agno); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); bt_hdr->bb_numrecs = cpu_to_be16(numrecs); if (lptr->modulo > 0) lptr->modulo--; if (lptr->num_recs_pb > 0) prop_refc_cursor(mp, agno, btree_curs, refc_rec->rc_startblock, 0); bt_rec = (struct xfs_refcount_rec *) ((char *)bt_hdr + XFS_REFCOUNT_BLOCK_LEN); for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) { ASSERT(refc_rec != NULL); bt_rec[j].rc_startblock = cpu_to_be32(refc_rec->rc_startblock); bt_rec[j].rc_blockcount = cpu_to_be32(refc_rec->rc_blockcount); bt_rec[j].rc_refcount = cpu_to_be32(refc_rec->rc_refcount); refc_rec = pop_slab_cursor(refc_cur); } if (refc_rec != NULL) { /* * get next leaf level block */ if (lptr->prev_buf_p != NULL) { #ifdef XR_BLD_RL_TRACE fprintf(stderr, "writing refcntbt agbno %u\n", lptr->prev_agbno); #endif ASSERT(lptr->prev_agbno != NULLAGBLOCK); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_buf_p = lptr->buf_p; lptr->prev_agbno = lptr->agbno; lptr->agbno = get_next_blockaddr(agno, 0, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(lptr->agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), XFS_FSB_TO_BB(mp, 1)); } } free_slab_cursor(&refc_cur); } /* * build both the agf and the agfl for an agno given both * btree cursors. * * XXX: yet more common code that can be shared with mkfs/growfs. */ static void build_agf_agfl( struct xfs_mount *mp, xfs_agnumber_t agno, struct bt_status *bno_bt, struct bt_status *bcnt_bt, xfs_extlen_t freeblks, /* # free blocks in tree */ int lostblocks, /* # blocks that will be lost */ struct bt_status *rmap_bt, struct bt_status *refcnt_bt, struct xfs_slab *lost_fsb) { struct extent_tree_node *ext_ptr; struct xfs_buf *agf_buf, *agfl_buf; int i; struct xfs_agfl *agfl; struct xfs_agf *agf; xfs_fsblock_t fsb; __be32 *freelist; int error; agf_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); agf_buf->b_ops = &xfs_agf_buf_ops; agf = XFS_BUF_TO_AGF(agf_buf); memset(agf, 0, mp->m_sb.sb_sectsize); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "agf = %p, agf_buf->b_addr = %p\n", agf, agf_buf->b_addr); #endif /* * set up fixed part of agf */ agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); agf->agf_seqno = cpu_to_be32(agno); if (agno < mp->m_sb.sb_agcount - 1) agf->agf_length = cpu_to_be32(mp->m_sb.sb_agblocks); else agf->agf_length = cpu_to_be32(mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno); agf->agf_roots[XFS_BTNUM_BNO] = cpu_to_be32(bno_bt->root); agf->agf_levels[XFS_BTNUM_BNO] = cpu_to_be32(bno_bt->num_levels); agf->agf_roots[XFS_BTNUM_CNT] = cpu_to_be32(bcnt_bt->root); agf->agf_levels[XFS_BTNUM_CNT] = cpu_to_be32(bcnt_bt->num_levels); agf->agf_roots[XFS_BTNUM_RMAP] = cpu_to_be32(rmap_bt->root); agf->agf_levels[XFS_BTNUM_RMAP] = cpu_to_be32(rmap_bt->num_levels); agf->agf_freeblks = cpu_to_be32(freeblks); agf->agf_rmap_blocks = cpu_to_be32(rmap_bt->num_tot_blocks - rmap_bt->num_free_blocks); agf->agf_refcount_root = cpu_to_be32(refcnt_bt->root); agf->agf_refcount_level = cpu_to_be32(refcnt_bt->num_levels); agf->agf_refcount_blocks = cpu_to_be32(refcnt_bt->num_tot_blocks - refcnt_bt->num_free_blocks); /* * Count and record the number of btree blocks consumed if required. */ if (xfs_sb_version_haslazysbcount(&mp->m_sb)) { unsigned int blks; /* * Don't count the root blocks as they are already * accounted for. */ blks = (bno_bt->num_tot_blocks - bno_bt->num_free_blocks) + (bcnt_bt->num_tot_blocks - bcnt_bt->num_free_blocks) - 2; if (xfs_sb_version_hasrmapbt(&mp->m_sb)) blks += rmap_bt->num_tot_blocks - rmap_bt->num_free_blocks - 1; agf->agf_btreeblks = cpu_to_be32(blks); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "agf->agf_btreeblks = %u\n", be32_to_cpu(agf->agf_btreeblks)); #endif } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "bno root = %u, bcnt root = %u, indices = %u %u\n", be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]), XFS_BTNUM_BNO, XFS_BTNUM_CNT); #endif if (xfs_sb_version_hascrc(&mp->m_sb)) platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); /* initialise the AGFL, then fill it if there are blocks left over. */ agfl_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); agfl_buf->b_ops = &xfs_agfl_buf_ops; agfl = XFS_BUF_TO_AGFL(agfl_buf); /* setting to 0xff results in initialisation to NULLAGBLOCK */ memset(agfl, 0xff, mp->m_sb.sb_sectsize); if (xfs_sb_version_hascrc(&mp->m_sb)) { agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); agfl->agfl_seqno = cpu_to_be32(agno); platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); for (i = 0; i < libxfs_agfl_size(mp); i++) agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK); } freelist = XFS_BUF_TO_AGFL_BNO(mp, agfl_buf); /* * do we have left-over blocks in the btree cursors that should * be used to fill the AGFL? */ if (bno_bt->num_free_blocks > 0 || bcnt_bt->num_free_blocks > 0) { /* * yes, now grab as many blocks as we can */ i = 0; while (bno_bt->num_free_blocks > 0 && i < libxfs_agfl_size(mp)) { freelist[i] = cpu_to_be32( get_next_blockaddr(agno, 0, bno_bt)); i++; } while (bcnt_bt->num_free_blocks > 0 && i < libxfs_agfl_size(mp)) { freelist[i] = cpu_to_be32( get_next_blockaddr(agno, 0, bcnt_bt)); i++; } /* * now throw the rest of the blocks away and complain */ while (bno_bt->num_free_blocks > 0) { fsb = XFS_AGB_TO_FSB(mp, agno, get_next_blockaddr(agno, 0, bno_bt)); error = slab_add(lost_fsb, &fsb); if (error) do_error( _("Insufficient memory saving lost blocks.\n")); } while (bcnt_bt->num_free_blocks > 0) { fsb = XFS_AGB_TO_FSB(mp, agno, get_next_blockaddr(agno, 0, bcnt_bt)); error = slab_add(lost_fsb, &fsb); if (error) do_error( _("Insufficient memory saving lost blocks.\n")); } agf->agf_flfirst = 0; agf->agf_fllast = cpu_to_be32(i - 1); agf->agf_flcount = cpu_to_be32(i); rmap_store_agflcount(mp, agno, i); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "writing agfl for ag %u\n", agno); #endif } else { agf->agf_flfirst = 0; agf->agf_fllast = cpu_to_be32(libxfs_agfl_size(mp) - 1); agf->agf_flcount = 0; } libxfs_writebuf(agfl_buf, 0); ext_ptr = findbiggest_bcnt_extent(agno); agf->agf_longest = cpu_to_be32((ext_ptr != NULL) ? ext_ptr->ex_blockcount : 0); ASSERT(be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi]) != be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); ASSERT(be32_to_cpu(agf->agf_refcount_root) != be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi])); ASSERT(be32_to_cpu(agf->agf_refcount_root) != be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); libxfs_writebuf(agf_buf, 0); /* * now fix up the free list appropriately */ fix_freelist(mp, agno, true); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "wrote agf for ag %u\n", agno); #endif } /* * update the superblock counters, sync the sb version numbers and * feature bits to the filesystem, and sync up the on-disk superblock * to match the incore superblock. */ static void sync_sb(xfs_mount_t *mp) { xfs_buf_t *bp; bp = libxfs_getsb(mp); if (!bp) do_error(_("couldn't get superblock\n")); mp->m_sb.sb_icount = sb_icount; mp->m_sb.sb_ifree = sb_ifree; mp->m_sb.sb_fdblocks = sb_fdblocks; mp->m_sb.sb_frextents = sb_frextents; update_sb_version(mp); libxfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); libxfs_writebuf(bp, 0); } /* * make sure the root and realtime inodes show up allocated * even if they've been freed. they get reinitialized in phase6. */ static void keep_fsinos(xfs_mount_t *mp) { ino_tree_node_t *irec; int i; irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); for (i = 0; i < 3; i++) set_inode_used(irec, i); } static void phase5_func( xfs_mount_t *mp, xfs_agnumber_t agno, struct xfs_slab *lost_fsb) { uint64_t num_inos; uint64_t num_free_inos; uint64_t finobt_num_inos; uint64_t finobt_num_free_inos; bt_status_t bno_btree_curs; bt_status_t bcnt_btree_curs; bt_status_t ino_btree_curs; bt_status_t fino_btree_curs; bt_status_t rmap_btree_curs; bt_status_t refcnt_btree_curs; int extra_blocks = 0; uint num_freeblocks; xfs_extlen_t freeblks1; #ifdef DEBUG xfs_extlen_t freeblks2; #endif xfs_agblock_t num_extents; struct agi_stat agi_stat = {0,}; if (verbose) do_log(_(" - agno = %d\n"), agno); { /* * build up incore bno and bcnt extent btrees */ num_extents = mk_incore_fstree(mp, agno); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of bno extents is %d\n", count_bno_extents(agno)); #endif if (num_extents == 0) { /* * XXX - what we probably should do here is pick an * inode for a regular file in the allocation group * that has space allocated and shoot it by traversing * the bmap list and putting all its extents on the * incore freespace trees, clearing the inode, * and clearing the in-use bit in the incore inode * tree. Then try mk_incore_fstree() again. */ do_error(_("unable to rebuild AG %u. " "Not enough free space in on-disk AG.\n"), agno); } /* * ok, now set up the btree cursors for the * on-disk btrees (includs pre-allocating all * required blocks for the trees themselves) */ init_ino_cursor(mp, agno, &ino_btree_curs, &num_inos, &num_free_inos, 0); if (xfs_sb_version_hasfinobt(&mp->m_sb)) init_ino_cursor(mp, agno, &fino_btree_curs, &finobt_num_inos, &finobt_num_free_inos, 1); sb_icount_ag[agno] += num_inos; sb_ifree_ag[agno] += num_free_inos; /* * Set up the btree cursors for the on-disk rmap btrees, * which includes pre-allocating all required blocks. */ init_rmapbt_cursor(mp, agno, &rmap_btree_curs); /* * Set up the btree cursors for the on-disk refcount btrees, * which includes pre-allocating all required blocks. */ init_refc_cursor(mp, agno, &refcnt_btree_curs); num_extents = count_bno_extents_blocks(agno, &num_freeblocks); /* * lose two blocks per AG -- the space tree roots * are counted as allocated since the space trees * always have roots */ sb_fdblocks_ag[agno] += num_freeblocks - 2; if (num_extents == 0) { /* * XXX - what we probably should do here is pick an * inode for a regular file in the allocation group * that has space allocated and shoot it by traversing * the bmap list and putting all its extents on the * incore freespace trees, clearing the inode, * and clearing the in-use bit in the incore inode * tree. Then try mk_incore_fstree() again. */ do_error( _("unable to rebuild AG %u. No free space.\n"), agno); } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of bno extents is %d\n", num_extents); #endif /* * track blocks that we might really lose */ extra_blocks = calculate_freespace_cursor(mp, agno, &num_extents, &bno_btree_curs); /* * freespace btrees live in the "free space" but * the filesystem treats AGFL blocks as allocated * since they aren't described by the freespace trees */ /* * see if we can fit all the extra blocks into the AGFL */ extra_blocks = (extra_blocks - libxfs_agfl_size(mp) > 0) ? extra_blocks - libxfs_agfl_size(mp) : 0; if (extra_blocks > 0) sb_fdblocks_ag[agno] -= extra_blocks; bcnt_btree_curs = bno_btree_curs; bno_btree_curs.owner = XFS_RMAP_OWN_AG; bcnt_btree_curs.owner = XFS_RMAP_OWN_AG; setup_cursor(mp, agno, &bno_btree_curs); setup_cursor(mp, agno, &bcnt_btree_curs); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of bno extents is %d\n", count_bno_extents(agno)); fprintf(stderr, "# of bcnt extents is %d\n", count_bcnt_extents(agno)); #endif /* * now rebuild the freespace trees */ freeblks1 = build_freespace_tree(mp, agno, &bno_btree_curs, XFS_BTNUM_BNO); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of free blocks == %d\n", freeblks1); #endif write_cursor(&bno_btree_curs); #ifdef DEBUG freeblks2 = build_freespace_tree(mp, agno, &bcnt_btree_curs, XFS_BTNUM_CNT); #else (void) build_freespace_tree(mp, agno, &bcnt_btree_curs, XFS_BTNUM_CNT); #endif write_cursor(&bcnt_btree_curs); ASSERT(freeblks1 == freeblks2); if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { build_rmap_tree(mp, agno, &rmap_btree_curs); write_cursor(&rmap_btree_curs); sb_fdblocks_ag[agno] += (rmap_btree_curs.num_tot_blocks - rmap_btree_curs.num_free_blocks) - 1; } if (xfs_sb_version_hasreflink(&mp->m_sb)) { build_refcount_tree(mp, agno, &refcnt_btree_curs); write_cursor(&refcnt_btree_curs); } /* * set up agf and agfl */ build_agf_agfl(mp, agno, &bno_btree_curs, &bcnt_btree_curs, freeblks1, extra_blocks, &rmap_btree_curs, &refcnt_btree_curs, lost_fsb); /* * build inode allocation tree. */ build_ino_tree(mp, agno, &ino_btree_curs, XFS_BTNUM_INO, &agi_stat); write_cursor(&ino_btree_curs); /* * build free inode tree */ if (xfs_sb_version_hasfinobt(&mp->m_sb)) { build_ino_tree(mp, agno, &fino_btree_curs, XFS_BTNUM_FINO, NULL); write_cursor(&fino_btree_curs); } /* build the agi */ build_agi(mp, agno, &ino_btree_curs, &fino_btree_curs, &agi_stat); /* * tear down cursors */ finish_cursor(&bno_btree_curs); finish_cursor(&ino_btree_curs); if (xfs_sb_version_hasrmapbt(&mp->m_sb)) finish_cursor(&rmap_btree_curs); if (xfs_sb_version_hasreflink(&mp->m_sb)) finish_cursor(&refcnt_btree_curs); if (xfs_sb_version_hasfinobt(&mp->m_sb)) finish_cursor(&fino_btree_curs); finish_cursor(&bcnt_btree_curs); /* * release the incore per-AG bno/bcnt trees so * the extent nodes can be recycled */ release_agbno_extent_tree(agno); release_agbcnt_extent_tree(agno); } PROG_RPT_INC(prog_rpt_done[agno], 1); } /* Inject lost blocks back into the filesystem. */ static int inject_lost_blocks( struct xfs_mount *mp, struct xfs_slab *lost_fsbs) { struct xfs_trans *tp = NULL; struct xfs_slab_cursor *cur = NULL; xfs_fsblock_t *fsb; int error; error = init_slab_cursor(lost_fsbs, NULL, &cur); if (error) return error; while ((fsb = pop_slab_cursor(cur)) != NULL) { error = -libxfs_trans_alloc_rollable(mp, 16, &tp); if (error) goto out_cancel; error = -libxfs_free_extent(tp, *fsb, 1, &XFS_RMAP_OINFO_AG, XFS_AG_RESV_NONE); if (error) goto out_cancel; error = -libxfs_trans_commit(tp); if (error) goto out_cancel; tp = NULL; } out_cancel: if (tp) libxfs_trans_cancel(tp); free_slab_cursor(&cur); return error; } void phase5(xfs_mount_t *mp) { struct xfs_slab *lost_fsb; xfs_agnumber_t agno; int error; do_log(_("Phase 5 - rebuild AG headers and trees...\n")); set_progress_msg(PROG_FMT_REBUILD_AG, (uint64_t)glob_agcount); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "inobt level 1, maxrec = %d, minrec = %d\n", libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0), libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2); fprintf(stderr, "inobt level 0 (leaf), maxrec = %d, minrec = %d\n", libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1), libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2); fprintf(stderr, "xr inobt level 0 (leaf), maxrec = %d\n", XR_INOBT_BLOCK_MAXRECS(mp, 0)); fprintf(stderr, "xr inobt level 1 (int), maxrec = %d\n", XR_INOBT_BLOCK_MAXRECS(mp, 1)); fprintf(stderr, "bnobt level 1, maxrec = %d, minrec = %d\n", libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0), libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2); fprintf(stderr, "bnobt level 0 (leaf), maxrec = %d, minrec = %d\n", libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1), libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2); #endif /* * make sure the root and realtime inodes show up allocated */ keep_fsinos(mp); /* allocate per ag counters */ sb_icount_ag = calloc(mp->m_sb.sb_agcount, sizeof(uint64_t)); if (sb_icount_ag == NULL) do_error(_("cannot alloc sb_icount_ag buffers\n")); sb_ifree_ag = calloc(mp->m_sb.sb_agcount, sizeof(uint64_t)); if (sb_ifree_ag == NULL) do_error(_("cannot alloc sb_ifree_ag buffers\n")); sb_fdblocks_ag = calloc(mp->m_sb.sb_agcount, sizeof(uint64_t)); if (sb_fdblocks_ag == NULL) do_error(_("cannot alloc sb_fdblocks_ag buffers\n")); error = init_slab(&lost_fsb, sizeof(xfs_fsblock_t)); if (error) do_error(_("cannot alloc lost block slab\n")); for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) phase5_func(mp, agno, lost_fsb); print_final_rpt(); /* aggregate per ag counters */ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { sb_icount += sb_icount_ag[agno]; sb_ifree += sb_ifree_ag[agno]; sb_fdblocks += sb_fdblocks_ag[agno]; } free(sb_icount_ag); free(sb_ifree_ag); free(sb_fdblocks_ag); if (mp->m_sb.sb_rblocks) { do_log( _(" - generate realtime summary info and bitmap...\n")); rtinit(mp); generate_rtinfo(mp, btmcompute, sumcompute); } do_log(_(" - reset superblock...\n")); /* * sync superblock counter and set version bits correctly */ sync_sb(mp); /* * Put the per-AG btree rmap data into the rmapbt now that we've reset * the superblock counters. */ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { error = rmap_store_ag_btree_rec(mp, agno); if (error) do_error( _("unable to add AG %u reverse-mapping data to btree.\n"), agno); } /* * Put blocks that were unnecessarily reserved for btree * reconstruction back into the filesystem free space data. */ error = inject_lost_blocks(mp, lost_fsb); if (error) do_error(_("Unable to reinsert lost blocks into filesystem.\n")); free_slab(&lost_fsb); bad_ino_btree = 0; } xfsprogs-5.3.0/repair/phase6.c0000644000175000017500000024742013570057155016101 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "threads.h" #include "prefetch.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "dir2.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "progress.h" #include "versions.h" static struct cred zerocr; static struct fsxattr zerofsx; static xfs_ino_t orphanage_ino; static struct xfs_name xfs_name_dot = {(unsigned char *)".", 1, XFS_DIR3_FT_DIR}; /* * When we're checking directory inodes, we're allowed to set a directory's * dotdot entry to zero to signal that the parent needs to be reconnected * during phase 6. If we're handling a shortform directory the ifork * verifiers will fail, so temporarily patch out this canary so that we can * verify the rest of the fork and move on to fixing the dir. */ static xfs_failaddr_t phase6_verify_dir( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; const struct xfs_dir_ops *dops; struct xfs_ifork *ifp; struct xfs_dir2_sf_hdr *sfp; xfs_failaddr_t fa; xfs_ino_t old_parent; bool parent_bypass = false; int size; dops = libxfs_dir_get_ops(mp, NULL); ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data; size = ifp->if_bytes; /* * If this is a shortform directory, phase4 may have set the parent * inode to zero to indicate that it must be fixed. Temporarily * set a valid parent so that the directory verifier will pass. */ if (size > offsetof(struct xfs_dir2_sf_hdr, parent) && size >= xfs_dir2_sf_hdr_size(sfp->i8count)) { old_parent = dops->sf_get_parent_ino(sfp); if (old_parent == 0) { dops->sf_put_parent_ino(sfp, mp->m_sb.sb_rootino); parent_bypass = true; } } fa = libxfs_default_ifork_ops.verify_dir(ip); /* Put it back. */ if (parent_bypass) dops->sf_put_parent_ino(sfp, old_parent); return fa; } static struct xfs_ifork_ops phase6_ifork_ops = { .verify_attr = xfs_attr_shortform_verify, .verify_dir = phase6_verify_dir, .verify_symlink = xfs_symlink_shortform_verify, }; /* * Data structures used to keep track of directories where the ".." * entries are updated. These must be rebuilt after the initial pass */ typedef struct dotdot_update { struct list_head list; ino_tree_node_t *irec; xfs_agnumber_t agno; int ino_offset; } dotdot_update_t; static LIST_HEAD(dotdot_update_list); static int dotdot_update; static void add_dotdot_update( xfs_agnumber_t agno, ino_tree_node_t *irec, int ino_offset) { dotdot_update_t *dir = malloc(sizeof(dotdot_update_t)); if (!dir) do_error(_("malloc failed add_dotdot_update (%zu bytes)\n"), sizeof(dotdot_update_t)); INIT_LIST_HEAD(&dir->list); dir->irec = irec; dir->agno = agno; dir->ino_offset = ino_offset; list_add(&dir->list, &dotdot_update_list); } /* * Data structures and routines to keep track of directory entries * and whether their leaf entry has been seen. Also used for name * duplicate checking and rebuilding step if required. */ typedef struct dir_hash_ent { struct dir_hash_ent *nextbyaddr; /* next in addr bucket */ struct dir_hash_ent *nextbyhash; /* next in name bucket */ struct dir_hash_ent *nextbyorder; /* next in order added */ xfs_dahash_t hashval; /* hash value of name */ uint32_t address; /* offset of data entry */ xfs_ino_t inum; /* inode num of entry */ short junkit; /* name starts with / */ short seen; /* have seen leaf entry */ struct xfs_name name; } dir_hash_ent_t; typedef struct dir_hash_tab { int size; /* size of hash tables */ int names_duped; /* 1 = ent names malloced */ dir_hash_ent_t *first; /* ptr to first added entry */ dir_hash_ent_t *last; /* ptr to last added entry */ dir_hash_ent_t **byhash; /* ptr to name hash buckets */ dir_hash_ent_t **byaddr; /* ptr to addr hash buckets */ } dir_hash_tab_t; #define DIR_HASH_TAB_SIZE(n) \ (sizeof(dir_hash_tab_t) + (sizeof(dir_hash_ent_t *) * (n) * 2)) #define DIR_HASH_FUNC(t,a) ((a) % (t)->size) /* * Track the contents of the freespace table in a directory. */ typedef struct freetab { int naents; /* expected number of data blocks */ int nents; /* number of data blocks processed */ struct freetab_ent { xfs_dir2_data_off_t v; short s; } ents[1]; } freetab_t; #define FREETAB_SIZE(n) \ (offsetof(freetab_t, ents) + (sizeof(struct freetab_ent) * (n))) #define DIR_HASH_CK_OK 0 #define DIR_HASH_CK_DUPLEAF 1 #define DIR_HASH_CK_BADHASH 2 #define DIR_HASH_CK_NODATA 3 #define DIR_HASH_CK_NOLEAF 4 #define DIR_HASH_CK_BADSTALE 5 #define DIR_HASH_CK_TOTAL 6 /* * Need to handle CRC and validation errors specially here. If there is a * validator error, re-read without the verifier so that we get a buffer we can * check and repair. Re-attach the ops to the buffer after the read so that when * it is rewritten the CRC is recalculated. * * If the buffer was not read, we return an error. If the buffer was read but * had a CRC or corruption error, we reread it without the verifier and if it is * read successfully we increment *crc_error and return 0. Otherwise we * return the read error. */ static int dir_read_buf( struct xfs_inode *ip, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, const struct xfs_buf_ops *ops, int *crc_error) { int error; int error2; error = -libxfs_da_read_buf(NULL, ip, bno, mappedbno, bpp, XFS_DATA_FORK, ops); if (error != EFSBADCRC && error != EFSCORRUPTED) return error; error2 = -libxfs_da_read_buf(NULL, ip, bno, mappedbno, bpp, XFS_DATA_FORK, NULL); if (error2) return error2; (*crc_error)++; (*bpp)->b_ops = ops; return 0; } /* * Returns 0 if the name already exists (ie. a duplicate) */ static int dir_hash_add( xfs_mount_t *mp, dir_hash_tab_t *hashtab, uint32_t addr, xfs_ino_t inum, int namelen, unsigned char *name, uint8_t ftype) { xfs_dahash_t hash = 0; int byaddr; int byhash = 0; dir_hash_ent_t *p; int dup; short junk; struct xfs_name xname; ASSERT(!hashtab->names_duped); xname.name = name; xname.len = namelen; xname.type = ftype; junk = name[0] == '/'; byaddr = DIR_HASH_FUNC(hashtab, addr); dup = 0; if (!junk) { hash = mp->m_dirnameops->hashname(&xname); byhash = DIR_HASH_FUNC(hashtab, hash); /* * search hash bucket for existing name. */ for (p = hashtab->byhash[byhash]; p; p = p->nextbyhash) { if (p->hashval == hash && p->name.len == namelen) { if (memcmp(p->name.name, name, namelen) == 0) { dup = 1; junk = 1; break; } } } } if ((p = malloc(sizeof(*p))) == NULL) do_error(_("malloc failed in dir_hash_add (%zu bytes)\n"), sizeof(*p)); p->nextbyaddr = hashtab->byaddr[byaddr]; hashtab->byaddr[byaddr] = p; if (hashtab->last) hashtab->last->nextbyorder = p; else hashtab->first = p; p->nextbyorder = NULL; hashtab->last = p; if (!(p->junkit = junk)) { p->hashval = hash; p->nextbyhash = hashtab->byhash[byhash]; hashtab->byhash[byhash] = p; } p->address = addr; p->inum = inum; p->seen = 0; p->name = xname; return !dup; } /* * checks to see if any data entries are not in the leaf blocks */ static int dir_hash_unseen( dir_hash_tab_t *hashtab) { int i; dir_hash_ent_t *p; for (i = 0; i < hashtab->size; i++) { for (p = hashtab->byaddr[i]; p; p = p->nextbyaddr) { if (p->seen == 0) return 1; } } return 0; } static int dir_hash_check( dir_hash_tab_t *hashtab, xfs_inode_t *ip, int seeval) { static char *seevalstr[DIR_HASH_CK_TOTAL]; static int done; if (!done) { seevalstr[DIR_HASH_CK_OK] = _("ok"); seevalstr[DIR_HASH_CK_DUPLEAF] = _("duplicate leaf"); seevalstr[DIR_HASH_CK_BADHASH] = _("hash value mismatch"); seevalstr[DIR_HASH_CK_NODATA] = _("no data entry"); seevalstr[DIR_HASH_CK_NOLEAF] = _("no leaf entry"); seevalstr[DIR_HASH_CK_BADSTALE] = _("bad stale count"); done = 1; } if (seeval == DIR_HASH_CK_OK && dir_hash_unseen(hashtab)) seeval = DIR_HASH_CK_NOLEAF; if (seeval == DIR_HASH_CK_OK) return 0; do_warn(_("bad hash table for directory inode %" PRIu64 " (%s): "), ip->i_ino, seevalstr[seeval]); if (!no_modify) do_warn(_("rebuilding\n")); else do_warn(_("would rebuild\n")); return 1; } static void dir_hash_done( dir_hash_tab_t *hashtab) { int i; dir_hash_ent_t *n; dir_hash_ent_t *p; for (i = 0; i < hashtab->size; i++) { for (p = hashtab->byaddr[i]; p; p = n) { n = p->nextbyaddr; if (hashtab->names_duped) free((void *)p->name.name); free(p); } } free(hashtab); } static dir_hash_tab_t * dir_hash_init( xfs_fsize_t size) { dir_hash_tab_t *hashtab; int hsize; hsize = size / (16 * 4); if (hsize > 65536) hsize = 63336; else if (hsize < 16) hsize = 16; if ((hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1)) == NULL) do_error(_("calloc failed in dir_hash_init\n")); hashtab->size = hsize; hashtab->byhash = (dir_hash_ent_t**)((char *)hashtab + sizeof(dir_hash_tab_t)); hashtab->byaddr = (dir_hash_ent_t**)((char *)hashtab + sizeof(dir_hash_tab_t) + sizeof(dir_hash_ent_t*) * hsize); return hashtab; } static int dir_hash_see( dir_hash_tab_t *hashtab, xfs_dahash_t hash, xfs_dir2_dataptr_t addr) { int i; dir_hash_ent_t *p; i = DIR_HASH_FUNC(hashtab, addr); for (p = hashtab->byaddr[i]; p; p = p->nextbyaddr) { if (p->address != addr) continue; if (p->seen) return DIR_HASH_CK_DUPLEAF; if (p->junkit == 0 && p->hashval != hash) return DIR_HASH_CK_BADHASH; p->seen = 1; return DIR_HASH_CK_OK; } return DIR_HASH_CK_NODATA; } static void dir_hash_update_ftype( dir_hash_tab_t *hashtab, xfs_dir2_dataptr_t addr, uint8_t ftype) { int i; dir_hash_ent_t *p; i = DIR_HASH_FUNC(hashtab, addr); for (p = hashtab->byaddr[i]; p; p = p->nextbyaddr) { if (p->address != addr) continue; p->name.type = ftype; } } /* * checks to make sure leafs match a data entry, and that the stale * count is valid. */ static int dir_hash_see_all( dir_hash_tab_t *hashtab, xfs_dir2_leaf_entry_t *ents, int count, int stale) { int i; int j; int rval; for (i = j = 0; i < count; i++) { if (be32_to_cpu(ents[i].address) == XFS_DIR2_NULL_DATAPTR) { j++; continue; } rval = dir_hash_see(hashtab, be32_to_cpu(ents[i].hashval), be32_to_cpu(ents[i].address)); if (rval != DIR_HASH_CK_OK) return rval; } return j == stale ? DIR_HASH_CK_OK : DIR_HASH_CK_BADSTALE; } /* * Convert name pointers into locally allocated memory. * This must only be done after all the entries have been added. */ static void dir_hash_dup_names(dir_hash_tab_t *hashtab) { unsigned char *name; dir_hash_ent_t *p; if (hashtab->names_duped) return; for (p = hashtab->first; p; p = p->nextbyorder) { name = malloc(p->name.len); memcpy(name, p->name.name, p->name.len); p->name.name = name; } hashtab->names_duped = 1; } /* * Given a block number in a fork, return the next valid block number * (not a hole). * If this is the last block number then NULLFILEOFF is returned. * * This was originally in the kernel, but only used in xfs_repair. */ static int bmap_next_offset( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode */ xfs_fileoff_t *bnop, /* current block */ int whichfork) /* data or attr fork */ { xfs_fileoff_t bno; /* current block */ int error; /* error return value */ xfs_bmbt_irec_t got; /* current extent value */ struct xfs_ifork *ifp; /* inode fork pointer */ struct xfs_iext_cursor icur; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) return EIO; if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { *bnop = NULLFILEOFF; return 0; } ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = -libxfs_iread_extents(tp, ip, whichfork))) return error; bno = *bnop + 1; if (!libxfs_iext_lookup_extent(ip, ifp, bno, &icur, &got)) *bnop = NULLFILEOFF; else *bnop = got.br_startoff < bno ? bno : got.br_startoff; return 0; } static void res_failed( int err) { if (err == ENOSPC) { do_error(_("ran out of disk space!\n")); } else do_error(_("xfs_trans_reserve returned %d\n"), err); } static void mk_rbmino(xfs_mount_t *mp) { xfs_trans_t *tp; xfs_inode_t *ip; xfs_bmbt_irec_t *ep; int i; int nmap; int error; xfs_fileoff_t bno; xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; int vers; int times; uint blocks; /* * first set up inode */ i = -libxfs_trans_alloc_rollable(mp, 10, &tp); if (i) res_failed(i); error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip, &xfs_default_ifork_ops); if (error) { do_error( _("couldn't iget realtime bitmap inode -- error - %d\n"), error); } vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2; memset(&ip->i_d, 0, sizeof(ip->i_d)); VFS_I(ip)->i_mode = S_IFREG; ip->i_d.di_version = vers; ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; set_nlink(VFS_I(ip), 1); /* account for sb ptr */ times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD; if (ip->i_d.di_version == 3) { VFS_I(ip)->i_version = 1; ip->i_d.di_flags2 = 0; times |= XFS_ICHGTIME_CREATE; } libxfs_trans_ichgtime(tp, ip, times); /* * now the ifork */ ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_bytes = 0; ip->i_df.if_u1.if_root = NULL; ip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; /* * commit changes */ libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); /* * then allocate blocks for file and fill with zeroes (stolen * from mkfs) */ blocks = mp->m_sb.sb_rbmblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; error = -libxfs_trans_alloc_rollable(mp, blocks, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); bno = 0; while (bno < mp->m_sb.sb_rbmblocks) { nmap = XFS_BMAP_MAX_NMAP; error = -libxfs_bmapi_write(tp, ip, bno, (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), 0, mp->m_sb.sb_rbmblocks, map, &nmap); if (error) { do_error( _("couldn't allocate realtime bitmap, error = %d\n"), error); } for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, ep->br_startblock), XFS_FSB_TO_BB(mp, ep->br_blockcount)); bno += ep->br_blockcount; } } error = -libxfs_trans_commit(tp); if (error) { do_error( _("allocation of the realtime bitmap failed, error = %d\n"), error); } libxfs_irele(ip); } static int fill_rbmino(xfs_mount_t *mp) { xfs_buf_t *bp; xfs_trans_t *tp; xfs_inode_t *ip; xfs_rtword_t *bmp; int nmap; int error; xfs_fileoff_t bno; xfs_bmbt_irec_t map; bmp = btmcompute; bno = 0; error = -libxfs_trans_alloc_rollable(mp, 10, &tp); if (error) res_failed(error); error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip, &xfs_default_ifork_ops); if (error) { do_error( _("couldn't iget realtime bitmap inode -- error - %d\n"), error); } while (bno < mp->m_sb.sb_rbmblocks) { /* * fill the file one block at a time */ libxfs_trans_ijoin(tp, ip, 0); nmap = 1; error = -libxfs_bmapi_write(tp, ip, bno, 1, 0, 1, &map, &nmap); if (error || nmap != 1) { do_error( _("couldn't map realtime bitmap block %" PRIu64 ", error = %d\n"), bno, error); } ASSERT(map.br_startblock != HOLESTARTBLOCK); error = -libxfs_trans_read_buf( mp, tp, mp->m_dev, XFS_FSB_TO_DADDR(mp, map.br_startblock), XFS_FSB_TO_BB(mp, 1), 1, &bp, NULL); if (error) { do_warn( _("can't access block %" PRIu64 " (fsbno %" PRIu64 ") of realtime bitmap inode %" PRIu64 "\n"), bno, map.br_startblock, mp->m_sb.sb_rbmino); return(1); } memmove(bp->b_addr, bmp, mp->m_sb.sb_blocksize); libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); bmp = (xfs_rtword_t *)((intptr_t) bmp + mp->m_sb.sb_blocksize); bno++; } error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); libxfs_irele(ip); return(0); } static int fill_rsumino(xfs_mount_t *mp) { xfs_buf_t *bp; xfs_trans_t *tp; xfs_inode_t *ip; xfs_suminfo_t *smp; int nmap; int error; xfs_fileoff_t bno; xfs_fileoff_t end_bno; xfs_bmbt_irec_t map; smp = sumcompute; bno = 0; end_bno = mp->m_rsumsize >> mp->m_sb.sb_blocklog; error = -libxfs_trans_alloc_rollable(mp, 10, &tp); if (error) res_failed(error); error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip, &xfs_default_ifork_ops); if (error) { do_error( _("couldn't iget realtime summary inode -- error - %d\n"), error); } while (bno < end_bno) { /* * fill the file one block at a time */ libxfs_trans_ijoin(tp, ip, 0); nmap = 1; error = -libxfs_bmapi_write(tp, ip, bno, 1, 0, 1, &map, &nmap); if (error || nmap != 1) { do_error( _("couldn't map realtime summary inode block %" PRIu64 ", error = %d\n"), bno, error); } ASSERT(map.br_startblock != HOLESTARTBLOCK); error = -libxfs_trans_read_buf( mp, tp, mp->m_dev, XFS_FSB_TO_DADDR(mp, map.br_startblock), XFS_FSB_TO_BB(mp, 1), 1, &bp, NULL); if (error) { do_warn( _("can't access block %" PRIu64 " (fsbno %" PRIu64 ") of realtime summary inode %" PRIu64 "\n"), bno, map.br_startblock, mp->m_sb.sb_rsumino); libxfs_irele(ip); return(1); } memmove(bp->b_addr, smp, mp->m_sb.sb_blocksize); libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); smp = (xfs_suminfo_t *)((intptr_t)smp + mp->m_sb.sb_blocksize); bno++; } error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); libxfs_irele(ip); return(0); } static void mk_rsumino(xfs_mount_t *mp) { xfs_trans_t *tp; xfs_inode_t *ip; xfs_bmbt_irec_t *ep; int i; int nmap; int error; int nsumblocks; xfs_fileoff_t bno; xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; int vers; int times; uint blocks; /* * first set up inode */ i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp); if (i) res_failed(i); error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip, &xfs_default_ifork_ops); if (error) { do_error( _("couldn't iget realtime summary inode -- error - %d\n"), error); } vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2; memset(&ip->i_d, 0, sizeof(ip->i_d)); VFS_I(ip)->i_mode = S_IFREG; ip->i_d.di_version = vers; ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; set_nlink(VFS_I(ip), 1); /* account for sb ptr */ times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD; if (ip->i_d.di_version == 3) { VFS_I(ip)->i_version = 1; ip->i_d.di_flags2 = 0; times |= XFS_ICHGTIME_CREATE; } libxfs_trans_ichgtime(tp, ip, times); /* * now the ifork */ ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_bytes = 0; ip->i_df.if_u1.if_root = NULL; ip->i_d.di_size = mp->m_rsumsize; /* * commit changes */ libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); /* * then allocate blocks for file and fill with zeroes (stolen * from mkfs) */ nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; error = -libxfs_trans_alloc_rollable(mp, blocks, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); bno = 0; while (bno < nsumblocks) { nmap = XFS_BMAP_MAX_NMAP; error = -libxfs_bmapi_write(tp, ip, bno, (xfs_extlen_t)(nsumblocks - bno), 0, nsumblocks, map, &nmap); if (error) { do_error( _("couldn't allocate realtime summary inode, error = %d\n"), error); } for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, ep->br_startblock), XFS_FSB_TO_BB(mp, ep->br_blockcount)); bno += ep->br_blockcount; } } error = -libxfs_trans_commit(tp); if (error) { do_error( _("allocation of the realtime summary ino failed, error = %d\n"), error); } libxfs_irele(ip); } /* * makes a new root directory. */ static void mk_root_dir(xfs_mount_t *mp) { xfs_trans_t *tp; xfs_inode_t *ip; int i; int error; const mode_t mode = 0755; ino_tree_node_t *irec; int vers; int times; ip = NULL; i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp); if (i) res_failed(i); error = -libxfs_iget(mp, tp, mp->m_sb.sb_rootino, 0, &ip, &xfs_default_ifork_ops); if (error) { do_error(_("could not iget root inode -- error - %d\n"), error); } /* * take care of the core -- initialization from xfs_ialloc() */ vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2; memset(&ip->i_d, 0, sizeof(ip->i_d)); VFS_I(ip)->i_mode = mode|S_IFDIR; ip->i_d.di_version = vers; ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; set_nlink(VFS_I(ip), 2); /* account for . and .. */ times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD; if (ip->i_d.di_version == 3) { VFS_I(ip)->i_version = 1; ip->i_d.di_flags2 = 0; times |= XFS_ICHGTIME_CREATE; } libxfs_trans_ichgtime(tp, ip, times); libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); /* * now the ifork */ ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_bytes = 0; ip->i_df.if_u1.if_root = NULL; /* * initialize the directory */ ip->d_ops = mp->m_dir_inode_ops; libxfs_dir_init(tp, ip, ip); error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); libxfs_irele(ip); irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); set_inode_isadir(irec, XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino) - irec->ino_startnum); } /* * orphanage name == lost+found */ static xfs_ino_t mk_orphanage(xfs_mount_t *mp) { xfs_ino_t ino; xfs_trans_t *tp; xfs_inode_t *ip; xfs_inode_t *pip; ino_tree_node_t *irec; int ino_offset = 0; int i; int error; const int mode = 0755; int nres; struct xfs_name xname; /* * check for an existing lost+found first, if it exists, return * its inode. Otherwise, we can create it. Bad lost+found inodes * would have been cleared in phase3 and phase4. */ i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, &xfs_default_ifork_ops); if (i) do_error(_("%d - couldn't iget root inode to obtain %s\n"), i, ORPHANAGE); xname.name = (unsigned char *)ORPHANAGE; xname.len = strlen(ORPHANAGE); xname.type = XFS_DIR3_FT_DIR; if (libxfs_dir_lookup(NULL, pip, &xname, &ino, NULL) == 0) return ino; /* * could not be found, create it */ nres = XFS_MKDIR_SPACE_RES(mp, xname.len); i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); if (i) res_failed(i); /* * use iget/ijoin instead of trans_iget because the ialloc * wrapper can commit the transaction and start a new one */ /* i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, &xfs_default_ifork_ops); if (i) do_error(_("%d - couldn't iget root inode to make %s\n"), i, ORPHANAGE);*/ error = -libxfs_inode_alloc(&tp, pip, mode|S_IFDIR, 1, 0, &zerocr, &zerofsx, &ip); if (error) { do_error(_("%s inode allocation failed %d\n"), ORPHANAGE, error); } inc_nlink(VFS_I(ip)); /* account for . */ ino = ip->i_ino; irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ino), XFS_INO_TO_AGINO(mp, ino)); if (irec == NULL) { /* * This inode is allocated from a newly created inode * chunk and therefore did not exist when inode chunks * were processed in phase3. Add this group of inodes to * the entry avl tree as if they were discovered in phase3. */ irec = set_inode_free_alloc(mp, XFS_INO_TO_AGNO(mp, ino), XFS_INO_TO_AGINO(mp, ino)); alloc_ex_data(irec); for (i = 0; i < XFS_INODES_PER_CHUNK; i++) set_inode_free(irec, i); } ino_offset = get_inode_offset(mp, ino, irec); /* * Mark the inode allocated to lost+found as used in the AVL tree * so it is not skipped in phase 7 */ set_inode_used(irec, ino_offset); add_inode_ref(irec, ino_offset); add_inode_reached(irec, ino_offset); /* * now that we know the transaction will stay around, * add the root inode to it */ libxfs_trans_ijoin(tp, pip, 0); /* * create the actual entry */ error = -libxfs_dir_createname(tp, pip, &xname, ip->i_ino, nres); if (error) do_error( _("can't make %s, createname error %d\n"), ORPHANAGE, error); /* * bump up the link count in the root directory to account * for .. in the new directory, and update the irec copy of the * on-disk nlink so we don't fail the link count check later. */ inc_nlink(VFS_I(pip)); irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); add_inode_ref(irec, 0); set_inode_disk_nlinks(irec, 0, get_inode_disk_nlinks(irec, 0) + 1); libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE); libxfs_dir_init(tp, ip, pip); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); if (error) { do_error(_("%s directory creation failed -- bmapf error %d\n"), ORPHANAGE, error); } libxfs_irele(ip); libxfs_irele(pip); return(ino); } /* * move a file to the orphange. */ static void mv_orphanage( xfs_mount_t *mp, xfs_ino_t ino, /* inode # to be moved */ int isa_dir) /* 1 if inode is a directory */ { xfs_inode_t *orphanage_ip; xfs_ino_t entry_ino_num; xfs_inode_t *ino_p; xfs_trans_t *tp; int err; unsigned char fname[MAXPATHLEN + 1]; int nres; int incr; ino_tree_node_t *irec; int ino_offset = 0; struct xfs_name xname; xname.name = fname; xname.len = snprintf((char *)fname, sizeof(fname), "%llu", (unsigned long long)ino); err = -libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip, &xfs_default_ifork_ops); if (err) do_error(_("%d - couldn't iget orphanage inode\n"), err); /* * Make sure the filename is unique in the lost+found */ incr = 0; while (libxfs_dir_lookup(NULL, orphanage_ip, &xname, &entry_ino_num, NULL) == 0) xname.len = snprintf((char *)fname, sizeof(fname), "%llu.%d", (unsigned long long)ino, ++incr); /* Orphans may not have a proper parent, so use custom ops here */ err = -libxfs_iget(mp, NULL, ino, 0, &ino_p, &phase6_ifork_ops); if (err) do_error(_("%d - couldn't iget disconnected inode\n"), err); xname.type = libxfs_mode_to_ftype(VFS_I(ino_p)->i_mode); if (isa_dir) { irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, orphanage_ino), XFS_INO_TO_AGINO(mp, orphanage_ino)); if (irec) ino_offset = XFS_INO_TO_AGINO(mp, orphanage_ino) - irec->ino_startnum; nres = XFS_DIRENTER_SPACE_RES(mp, fnamelen) + XFS_DIRENTER_SPACE_RES(mp, 2); err = -libxfs_dir_lookup(NULL, ino_p, &xfs_name_dotdot, &entry_ino_num, NULL); if (err) { ASSERT(err == ENOENT); err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_rename, nres, 0, 0, &tp); if (err) do_error( _("space reservation failed (%d), filesystem may be out of space\n"), err); libxfs_trans_ijoin(tp, orphanage_ip, 0); libxfs_trans_ijoin(tp, ino_p, 0); err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino, nres); if (err) do_error( _("name create failed in %s (%d), filesystem may be out of space\n"), ORPHANAGE, err); if (irec) add_inode_ref(irec, ino_offset); else inc_nlink(VFS_I(orphanage_ip)); libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE); err = -libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot, orphanage_ino, nres); if (err) do_error( _("creation of .. entry failed (%d), filesystem may be out of space\n"), err); inc_nlink(VFS_I(ino_p)); libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE); err = -libxfs_trans_commit(tp); if (err) do_error( _("creation of .. entry failed (%d)\n"), err); } else { err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_rename, nres, 0, 0, &tp); if (err) do_error( _("space reservation failed (%d), filesystem may be out of space\n"), err); libxfs_trans_ijoin(tp, orphanage_ip, 0); libxfs_trans_ijoin(tp, ino_p, 0); err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino, nres); if (err) do_error( _("name create failed in %s (%d), filesystem may be out of space\n"), ORPHANAGE, err); if (irec) add_inode_ref(irec, ino_offset); else inc_nlink(VFS_I(orphanage_ip)); libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE); /* * don't replace .. value if it already points * to us. that'll pop a libxfs/kernel ASSERT. */ if (entry_ino_num != orphanage_ino) { err = -libxfs_dir_replace(tp, ino_p, &xfs_name_dotdot, orphanage_ino, nres); if (err) do_error( _("name replace op failed (%d), filesystem may be out of space\n"), err); } err = -libxfs_trans_commit(tp); if (err) do_error( _("orphanage name replace op failed (%d)\n"), err); } } else { /* * use the remove log reservation as that's * more accurate. we're only creating the * links, we're not doing the inode allocation * also accounted for in the create */ nres = XFS_DIRENTER_SPACE_RES(mp, xname.len); err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (err) do_error( _("space reservation failed (%d), filesystem may be out of space\n"), err); libxfs_trans_ijoin(tp, orphanage_ip, 0); libxfs_trans_ijoin(tp, ino_p, 0); err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino, nres); if (err) do_error( _("name create failed in %s (%d), filesystem may be out of space\n"), ORPHANAGE, err); ASSERT(err == 0); set_nlink(VFS_I(ino_p), 1); libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE); err = -libxfs_trans_commit(tp); if (err) do_error( _("orphanage name create failed (%d)\n"), err); } libxfs_irele(ino_p); libxfs_irele(orphanage_ip); } static int entry_junked( const char *msg, const char *iname, xfs_ino_t ino1, xfs_ino_t ino2) { do_warn(msg, iname, ino1, ino2); if (!no_modify) { if (verbose) do_warn(_(", marking entry to be junked\n")); else do_warn("\n"); } else do_warn(_(", would junk entry\n")); return !no_modify; } /* Find and invalidate all the directory's buffers. */ static int dir_binval( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork) { struct xfs_iext_cursor icur; struct xfs_bmbt_irec rec; struct xfs_ifork *ifp; struct xfs_da_geometry *geo; struct xfs_buf *bp; xfs_dablk_t dabno, end_dabno; int error = 0; if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && ip->i_d.di_format != XFS_DINODE_FMT_BTREE) return 0; geo = tp->t_mountp->m_dir_geo; ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); for_each_xfs_iext(ifp, &icur, &rec) { dabno = xfs_dir2_db_to_da(geo, rec.br_startoff + geo->fsbcount - 1); end_dabno = xfs_dir2_db_to_da(geo, rec.br_startoff + rec.br_blockcount); for (; dabno <= end_dabno; dabno += geo->fsbcount) { bp = NULL; error = -libxfs_da_get_buf(tp, ip, dabno, -2, &bp, whichfork); if (error) return error; if (!bp) continue; libxfs_trans_binval(tp, bp); libxfs_trans_brelse(tp, bp); } } return error; } /* * Unexpected failure during the rebuild will leave the entries in * lost+found on the next run */ static void longform_dir2_rebuild( xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip, ino_tree_node_t *irec, int ino_offset, dir_hash_tab_t *hashtab) { int error; int nres; xfs_trans_t *tp; xfs_fileoff_t lastblock; xfs_inode_t pip; dir_hash_ent_t *p; int done = 0; /* * trash directory completely and rebuild from scratch using the * name/inode pairs in the hash table */ do_warn(_("rebuilding directory inode %" PRIu64 "\n"), ino); /* * first attempt to locate the parent inode, if it can't be * found, set it to the root inode and it'll be moved to the * orphanage later (the inode number here needs to be valid * for the libxfs_dir_init() call). */ pip.i_ino = get_inode_parent(irec, ino_offset); if (pip.i_ino == NULLFSINO || libxfs_dir_ino_validate(mp, pip.i_ino)) pip.i_ino = mp->m_sb.sb_rootino; nres = XFS_REMOVE_SPACE_RES(mp); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); error = dir_binval(tp, ip, XFS_DATA_FORK); if (error) do_error(_("error %d invalidating directory %llu blocks\n"), error, (unsigned long long)ip->i_ino); if ((error = -libxfs_bmap_last_offset(ip, &lastblock, XFS_DATA_FORK))) do_error(_("xfs_bmap_last_offset failed -- error - %d\n"), error); /* free all data, leaf, node and freespace blocks */ while (!done) { error = -libxfs_bunmapi(tp, ip, 0, lastblock, XFS_BMAPI_METADATA, 0, &done); if (error) { do_warn(_("xfs_bunmapi failed -- error - %d\n"), error); goto out_bmap_cancel; } error = -libxfs_defer_finish(&tp); if (error) { do_warn(("defer_finish failed -- error - %d\n"), error); goto out_bmap_cancel; } /* * Close out trans and start the next one in the chain. */ error = -libxfs_trans_roll_inode(&tp, ip); if (error) goto out_bmap_cancel; } error = -libxfs_dir_init(tp, ip, &pip); if (error) { do_warn(_("xfs_dir_init failed -- error - %d\n"), error); goto out_bmap_cancel; } error = -libxfs_trans_commit(tp); if (error) do_error( _("dir init failed (%d)\n"), error); if (ino == mp->m_sb.sb_rootino) need_root_dotdot = 0; /* go through the hash list and re-add the inodes */ for (p = hashtab->first; p; p = p->nextbyorder) { if (p->name.name[0] == '/' || (p->name.name[0] == '.' && (p->name.len == 1 || (p->name.len == 2 && p->name.name[1] == '.')))) continue; nres = XFS_CREATE_SPACE_RES(mp, p->name.len); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_create, nres, 0, 0, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); error = -libxfs_dir_createname(tp, ip, &p->name, p->inum, nres); if (error) { do_warn( _("name create failed in ino %" PRIu64 " (%d), filesystem may be out of space\n"), ino, error); goto out_bmap_cancel; } error = -libxfs_trans_commit(tp); if (error) do_error( _("name create failed (%d) during rebuild\n"), error); } return; out_bmap_cancel: libxfs_trans_cancel(tp); return; } /* * Kill a block in a version 2 inode. * Makes its own transaction. */ static void dir2_kill_block( xfs_mount_t *mp, xfs_inode_t *ip, xfs_dablk_t da_bno, struct xfs_buf *bp) { xfs_da_args_t args; int error; int nres; xfs_trans_t *tp; nres = XFS_REMOVE_SPACE_RES(mp); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_bjoin(tp, bp); memset(&args, 0, sizeof(args)); args.dp = ip; args.trans = tp; args.whichfork = XFS_DATA_FORK; args.geo = mp->m_dir_geo; if (da_bno >= mp->m_dir_geo->leafblk && da_bno < mp->m_dir_geo->freeblk) error = -libxfs_da_shrink_inode(&args, da_bno, bp); else error = -libxfs_dir2_shrink_inode(&args, xfs_dir2_da_to_db(mp->m_dir_geo, da_bno), bp); if (error) do_error(_("shrink_inode failed inode %" PRIu64 " block %u\n"), ip->i_ino, da_bno); error = -libxfs_trans_commit(tp); if (error) do_error( _("directory shrink failed (%d)\n"), error); } /* * process a data block, also checks for .. entry * and corrects it to match what we think .. should be */ static void longform_dir2_entry_check_data( xfs_mount_t *mp, xfs_inode_t *ip, int *num_illegal, int *need_dot, ino_tree_node_t *current_irec, int current_ino_offset, struct xfs_buf **bpp, dir_hash_tab_t *hashtab, freetab_t **freetabp, xfs_dablk_t da_bno, int isblock) { xfs_dir2_dataptr_t addr; xfs_dir2_leaf_entry_t *blp; struct xfs_buf *bp; xfs_dir2_block_tail_t *btp; struct xfs_dir2_data_hdr *d; xfs_dir2_db_t db; xfs_dir2_data_entry_t *dep; xfs_dir2_data_unused_t *dup; struct xfs_dir2_data_free *bf; char *endptr; int error; char fname[MAXNAMELEN + 1]; freetab_t *freetab; int i; int ino_offset; xfs_ino_t inum; ino_tree_node_t *irec; int junkit; int lastfree; int len; int nbad; int needlog; int needscan; xfs_ino_t parent; char *ptr; xfs_trans_t *tp; int wantmagic; struct xfs_da_args da = { .dp = ip, .geo = mp->m_dir_geo, }; bp = *bpp; d = bp->b_addr; ptr = (char *)M_DIROPS(mp)->data_entry_p(d); nbad = 0; needscan = needlog = 0; junkit = 0; freetab = *freetabp; if (isblock) { btp = xfs_dir2_block_tail_p(mp->m_dir_geo, d); blp = xfs_dir2_block_leaf_p(btp); endptr = (char *)blp; if (endptr > (char *)btp) endptr = (char *)btp; if (xfs_sb_version_hascrc(&mp->m_sb)) wantmagic = XFS_DIR3_BLOCK_MAGIC; else wantmagic = XFS_DIR2_BLOCK_MAGIC; } else { endptr = (char *)d + mp->m_dir_geo->blksize; if (xfs_sb_version_hascrc(&mp->m_sb)) wantmagic = XFS_DIR3_DATA_MAGIC; else wantmagic = XFS_DIR2_DATA_MAGIC; } db = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno); /* check for data block beyond expected end */ if (freetab->naents <= db) { struct freetab_ent e; *freetabp = freetab = realloc(freetab, FREETAB_SIZE(db + 1)); if (!freetab) { do_error(_("realloc failed in %s (%zu bytes)\n"), __func__, FREETAB_SIZE(db + 1)); } e.v = NULLDATAOFF; e.s = 0; for (i = freetab->naents; i < db; i++) freetab->ents[i] = e; freetab->naents = db + 1; } /* check the data block */ while (ptr < endptr) { /* check for freespace */ dup = (xfs_dir2_data_unused_t *)ptr; if (XFS_DIR2_DATA_FREE_TAG == be16_to_cpu(dup->freetag)) { /* check for invalid freespace length */ if (ptr + be16_to_cpu(dup->length) > endptr || be16_to_cpu(dup->length) == 0 || (be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1))) break; /* check for invalid tag */ if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) != (char *)dup - (char *)d) break; /* check for block with no data entries */ if ((ptr == (char *)M_DIROPS(mp)->data_entry_p(d)) && (ptr + be16_to_cpu(dup->length) >= endptr)) { junkit = 1; *num_illegal += 1; break; } /* continue at the end of the freespace */ ptr += be16_to_cpu(dup->length); if (ptr >= endptr) break; } /* validate data entry size */ dep = (xfs_dir2_data_entry_t *)ptr; if (ptr + M_DIROPS(mp)->data_entsize(dep->namelen) > endptr) break; if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) != (char *)dep - (char *)d) break; ptr += M_DIROPS(mp)->data_entsize(dep->namelen); } /* did we find an empty or corrupt block? */ if (ptr != endptr) { if (junkit) { do_warn( _("empty data block %u in directory inode %" PRIu64 ": "), da_bno, ip->i_ino); } else { do_warn(_ ("corrupt block %u in directory inode %" PRIu64 ": "), da_bno, ip->i_ino); } if (!no_modify) { do_warn(_("junking block\n")); dir2_kill_block(mp, ip, da_bno, bp); } else { do_warn(_("would junk block\n")); libxfs_putbuf(bp); } freetab->ents[db].v = NULLDATAOFF; *bpp = NULL; return; } /* update number of data blocks processed */ if (freetab->nents < db + 1) freetab->nents = db + 1; error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, 0, 0, 0, &tp); if (error) res_failed(error); da.trans = tp; libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_bjoin(tp, bp); libxfs_trans_bhold(tp, bp); if (be32_to_cpu(d->magic) != wantmagic) { do_warn( _("bad directory block magic # %#x for directory inode %" PRIu64 " block %d: "), be32_to_cpu(d->magic), ip->i_ino, da_bno); if (!no_modify) { do_warn(_("fixing magic # to %#x\n"), wantmagic); d->magic = cpu_to_be32(wantmagic); needlog = 1; } else do_warn(_("would fix magic # to %#x\n"), wantmagic); } lastfree = 0; ptr = (char *)M_DIROPS(mp)->data_entry_p(d); /* * look at each entry. reference inode pointed to by each * entry in the incore inode tree. * if not a directory, set reached flag, increment link count * if a directory and reached, mark entry as to be deleted. * if a directory, check to see if recorded parent * matches current inode #, * if so, then set reached flag, increment link count * of current and child dir inodes, push the child * directory inode onto the directory stack. * if current inode != parent, then mark entry to be deleted. */ while (ptr < endptr) { dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { if (lastfree) { do_warn( _("directory inode %" PRIu64 " block %u has consecutive free entries: "), ip->i_ino, da_bno); if (!no_modify) { do_warn(_("joining together\n")); len = be16_to_cpu(dup->length); libxfs_dir2_data_use_free(&da, bp, dup, ptr - (char *)d, len, &needlog, &needscan); libxfs_dir2_data_make_free(&da, bp, ptr - (char *)d, len, &needlog, &needscan); } else do_warn(_("would join together\n")); } ptr += be16_to_cpu(dup->length); lastfree = 1; continue; } addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db, ptr - (char *)d); dep = (xfs_dir2_data_entry_t *)ptr; ptr += M_DIROPS(mp)->data_entsize(dep->namelen); inum = be64_to_cpu(dep->inumber); lastfree = 0; /* * skip bogus entries (leading '/'). they'll be deleted * later. must still log it, else we leak references to * buffers. */ if (dep->name[0] == '/') { nbad++; if (!no_modify) libxfs_dir2_data_log_entry(&da, bp, dep); continue; } memmove(fname, dep->name, dep->namelen); fname[dep->namelen] = '\0'; ASSERT(inum != NULLFSINO); irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, inum), XFS_INO_TO_AGINO(mp, inum)); if (irec == NULL) { nbad++; if (entry_junked( _("entry \"%s\" in directory inode %" PRIu64 " points to non-existent inode %" PRIu64 ""), fname, ip->i_ino, inum)) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); } continue; } ino_offset = XFS_INO_TO_AGINO(mp, inum) - irec->ino_startnum; /* * if it's a free inode, blow out the entry. * by now, any inode that we think is free * really is free. */ if (is_inode_free(irec, ino_offset)) { nbad++; if (entry_junked( _("entry \"%s\" in directory inode %" PRIu64 " points to free inode %" PRIu64), fname, ip->i_ino, inum)) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); } continue; } /* * check if this inode is lost+found dir in the root */ if (inum == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) { /* * if it's not a directory, trash it */ if (!inode_isadir(irec, ino_offset)) { nbad++; if (entry_junked( _("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"), ORPHANAGE, inum, ip->i_ino)) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); } continue; } /* * if this is a dup, it will be picked up below, * otherwise, mark it as the orphanage for later. */ if (!orphanage_ino) orphanage_ino = inum; } /* * check for duplicate names in directory. */ if (!dir_hash_add(mp, hashtab, addr, inum, dep->namelen, dep->name, M_DIROPS(mp)->data_get_ftype(dep))) { nbad++; if (entry_junked( _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"), fname, inum, ip->i_ino)) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); } if (inum == orphanage_ino) orphanage_ino = 0; continue; } /* * if just scanning to rebuild a directory due to a ".." * update, just continue */ if (dotdot_update) continue; /* * skip the '..' entry since it's checked when the * directory is reached by something else. if it never * gets reached, it'll be moved to the orphanage and we'll * take care of it then. If it doesn't exist at all, the * directory needs to be rebuilt first before being added * to the orphanage. */ if (dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.') { if (da_bno != 0) { /* ".." should be in the first block */ nbad++; if (entry_junked( _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is not in the the first block"), fname, inum, ip->i_ino)) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); } } continue; } ASSERT(no_modify || !verify_inum(mp, inum)); /* * special case the . entry. we know there's only one * '.' and only '.' points to itself because bogus entries * got trashed in phase 3 if there were > 1. * bump up link count for '.' but don't set reached * until we're actually reached by another directory * '..' is already accounted for or will be taken care * of when directory is moved to orphanage. */ if (ip->i_ino == inum) { ASSERT(no_modify || (dep->name[0] == '.' && dep->namelen == 1)); add_inode_ref(current_irec, current_ino_offset); if (da_bno != 0 || dep != M_DIROPS(mp)->data_entry_p(d)) { /* "." should be the first entry */ nbad++; if (entry_junked( _("entry \"%s\" in dir %" PRIu64 " is not the first entry"), fname, inum, ip->i_ino)) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); } } *need_dot = 0; continue; } /* * skip entries with bogus inumbers if we're in no modify mode */ if (no_modify && verify_inum(mp, inum)) continue; /* validate ftype field if supported */ if (xfs_sb_version_hasftype(&mp->m_sb)) { uint8_t dir_ftype; uint8_t ino_ftype; dir_ftype = M_DIROPS(mp)->data_get_ftype(dep); ino_ftype = get_inode_ftype(irec, ino_offset); if (dir_ftype != ino_ftype) { if (no_modify) { do_warn( _("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"), dir_ftype, ino_ftype, ip->i_ino, inum); } else { do_warn( _("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"), dir_ftype, ino_ftype, ip->i_ino, inum); M_DIROPS(mp)->data_put_ftype(dep, ino_ftype); libxfs_dir2_data_log_entry(&da, bp, dep); dir_hash_update_ftype(hashtab, addr, ino_ftype); } } } /* * check easy case first, regular inode, just bump * the link count and continue */ if (!inode_isadir(irec, ino_offset)) { add_inode_reached(irec, ino_offset); continue; } parent = get_inode_parent(irec, ino_offset); ASSERT(parent != 0); junkit = 0; /* * bump up the link counts in parent and child * directory but if the link doesn't agree with * the .. in the child, blow out the entry. * if the directory has already been reached, * blow away the entry also. */ if (is_inode_reached(irec, ino_offset)) { junkit = 1; do_warn( _("entry \"%s\" in dir %" PRIu64" points to an already connected directory inode %" PRIu64 "\n"), fname, ip->i_ino, inum); } else if (parent == ip->i_ino) { add_inode_reached(irec, ino_offset); add_inode_ref(current_irec, current_ino_offset); } else if (parent == NULLFSINO) { /* ".." was missing, but this entry refers to it, so, set it as the parent and mark for rebuild */ do_warn( _("entry \"%s\" in dir ino %" PRIu64 " doesn't have a .. entry, will set it in ino %" PRIu64 ".\n"), fname, ip->i_ino, inum); set_inode_parent(irec, ino_offset, ip->i_ino); add_inode_reached(irec, ino_offset); add_inode_ref(current_irec, current_ino_offset); add_dotdot_update(XFS_INO_TO_AGNO(mp, inum), irec, ino_offset); } else { junkit = 1; do_warn( _("entry \"%s\" in dir inode %" PRIu64 " inconsistent with .. value (%" PRIu64 ") in ino %" PRIu64 "\n"), fname, ip->i_ino, parent, inum); } if (junkit) { if (inum == orphanage_ino) orphanage_ino = 0; nbad++; if (!no_modify) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(&da, bp, dep); if (verbose) do_warn( _("\twill clear entry \"%s\"\n"), fname); } else { do_warn(_("\twould clear entry \"%s\"\n"), fname); } } } *num_illegal += nbad; if (needscan) libxfs_dir2_data_freescan_int(mp->m_dir_geo, M_DIROPS(mp), d, &i); if (needlog) libxfs_dir2_data_log_header(&da, bp); error = -libxfs_trans_commit(tp); if (error) do_error( _("directory block fixing failed (%d)\n"), error); /* record the largest free space in the freetab for later checking */ bf = M_DIROPS(mp)->data_bestfree_p(d); freetab->ents[db].v = be16_to_cpu(bf[0].length); freetab->ents[db].s = 0; } /* check v5 metadata */ static int __check_dir3_header( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino, __be64 owner, __be64 blkno, uuid_t *uuid) { /* verify owner */ if (be64_to_cpu(owner) != ino) { do_warn( _("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"), ino, (unsigned long long)be64_to_cpu(owner), bp->b_bn); return 1; } /* verify block number */ if (be64_to_cpu(blkno) != bp->b_bn) { do_warn( _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"), bp->b_bn, (unsigned long long)be64_to_cpu(blkno), ino); return 1; } /* verify uuid */ if (platform_uuid_compare(uuid, &mp->m_sb.sb_meta_uuid) != 0) { do_warn( _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"), ino, bp->b_bn); return 1; } return 0; } static int check_da3_header( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino) { struct xfs_da3_blkinfo *info = bp->b_addr; return __check_dir3_header(mp, bp, ino, info->owner, info->blkno, &info->uuid); } static int check_dir3_header( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino) { struct xfs_dir3_blk_hdr *info = bp->b_addr; return __check_dir3_header(mp, bp, ino, info->owner, info->blkno, &info->uuid); } /* * Check contents of leaf-form block. */ static int longform_dir2_check_leaf( xfs_mount_t *mp, xfs_inode_t *ip, dir_hash_tab_t *hashtab, freetab_t *freetab) { int badtail; __be16 *bestsp; struct xfs_buf *bp; xfs_dablk_t da_bno; int i; xfs_dir2_leaf_t *leaf; xfs_dir2_leaf_tail_t *ltp; int seeval; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; int error; int fixit = 0; da_bno = mp->m_dir_geo->leafblk; error = dir_read_buf(ip, da_bno, -1, &bp, &xfs_dir3_leaf1_buf_ops, &fixit); if (error == EFSBADCRC || error == EFSCORRUPTED || fixit) { do_warn( _("leaf block %u for directory inode %" PRIu64 " bad CRC\n"), da_bno, ip->i_ino); return 1; } else if (error) { do_error( _("can't read block %u for directory inode %" PRIu64 ", error %d\n"), da_bno, ip->i_ino, error); /* NOTREACHED */ } leaf = bp->b_addr; M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf); ents = M_DIROPS(mp)->leaf_ents_p(leaf); ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); bestsp = xfs_dir2_leaf_bests_p(ltp); if (!(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC || leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) || leafhdr.forw || leafhdr.back || leafhdr.count < leafhdr.stale || leafhdr.count > M_DIROPS(mp)->leaf_max_ents(mp->m_dir_geo) || (char *)&ents[leafhdr.count] > (char *)bestsp) { do_warn( _("leaf block %u for directory inode %" PRIu64 " bad header\n"), da_bno, ip->i_ino); libxfs_putbuf(bp); return 1; } if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) { error = check_da3_header(mp, bp, ip->i_ino); if (error) { libxfs_putbuf(bp); return error; } } seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale); if (dir_hash_check(hashtab, ip, seeval)) { libxfs_putbuf(bp); return 1; } badtail = freetab->nents != be32_to_cpu(ltp->bestcount); for (i = 0; !badtail && i < be32_to_cpu(ltp->bestcount); i++) { freetab->ents[i].s = 1; badtail = freetab->ents[i].v != be16_to_cpu(bestsp[i]); } if (badtail) { do_warn( _("leaf block %u for directory inode %" PRIu64 " bad tail\n"), da_bno, ip->i_ino); libxfs_putbuf(bp); return 1; } libxfs_putbuf(bp); return fixit; } /* * Check contents of the node blocks (leaves) * Looks for matching hash values for the data entries. */ static int longform_dir2_check_node( xfs_mount_t *mp, xfs_inode_t *ip, dir_hash_tab_t *hashtab, freetab_t *freetab) { struct xfs_buf *bp; xfs_dablk_t da_bno; xfs_dir2_db_t fdb; xfs_dir2_free_t *free; int i; xfs_dir2_leaf_t *leaf; xfs_fileoff_t next_da_bno; int seeval = 0; int used; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir3_icfree_hdr freehdr; __be16 *bests; int error; int fixit = 0; for (da_bno = mp->m_dir_geo->leafblk, next_da_bno = 0; next_da_bno != NULLFILEOFF && da_bno < mp->m_dir_geo->freeblk; da_bno = (xfs_dablk_t)next_da_bno) { next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1; if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) break; /* * we need to use the da3 node verifier here as it handles the * fact that reading the leaf hash tree blocks can return either * leaf or node blocks and calls the correct verifier. If we get * a node block, then we'll skip it below based on a magic * number check. */ error = dir_read_buf(ip, da_bno, -1, &bp, &xfs_da3_node_buf_ops, &fixit); if (error) { do_warn( _("can't read leaf block %u for directory inode %" PRIu64 ", error %d\n"), da_bno, ip->i_ino, error); return 1; } leaf = bp->b_addr; M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf); ents = M_DIROPS(mp)->leaf_ents_p(leaf); if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || leafhdr.magic == XFS_DA_NODE_MAGIC || leafhdr.magic == XFS_DA3_NODE_MAGIC)) { do_warn( _("unknown magic number %#x for block %u in directory inode %" PRIu64 "\n"), leafhdr.magic, da_bno, ip->i_ino); libxfs_putbuf(bp); return 1; } /* check v5 metadata */ if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || leafhdr.magic == XFS_DA3_NODE_MAGIC) { error = check_da3_header(mp, bp, ip->i_ino); if (error) { libxfs_putbuf(bp); return error; } } /* ignore nodes */ if (leafhdr.magic == XFS_DA_NODE_MAGIC || leafhdr.magic == XFS_DA3_NODE_MAGIC) { libxfs_putbuf(bp); continue; } /* * If there's a validator error, we need to ensure that we got * the right ops on the buffer for when we write it back out. */ bp->b_ops = &xfs_dir3_leafn_buf_ops; if (leafhdr.count > M_DIROPS(mp)->leaf_max_ents(mp->m_dir_geo) || leafhdr.count < leafhdr.stale) { do_warn( _("leaf block %u for directory inode %" PRIu64 " bad header\n"), da_bno, ip->i_ino); libxfs_putbuf(bp); return 1; } seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale); libxfs_putbuf(bp); if (seeval != DIR_HASH_CK_OK) return 1; } if (dir_hash_check(hashtab, ip, seeval)) return 1; for (da_bno = mp->m_dir_geo->freeblk, next_da_bno = 0; next_da_bno != NULLFILEOFF; da_bno = (xfs_dablk_t)next_da_bno) { next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1; if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) break; error = dir_read_buf(ip, da_bno, -1, &bp, &xfs_dir3_free_buf_ops, &fixit); if (error) { do_warn( _("can't read freespace block %u for directory inode %" PRIu64 ", error %d\n"), da_bno, ip->i_ino, error); return 1; } free = bp->b_addr; M_DIROPS(mp)->free_hdr_from_disk(&freehdr, free); bests = M_DIROPS(mp)->free_bests_p(free); fdb = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno); if (!(freehdr.magic == XFS_DIR2_FREE_MAGIC || freehdr.magic == XFS_DIR3_FREE_MAGIC) || freehdr.firstdb != (fdb - xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) * M_DIROPS(mp)->free_max_bests(mp->m_dir_geo) || freehdr.nvalid < freehdr.nused) { do_warn( _("free block %u for directory inode %" PRIu64 " bad header\n"), da_bno, ip->i_ino); libxfs_putbuf(bp); return 1; } if (freehdr.magic == XFS_DIR3_FREE_MAGIC) { error = check_dir3_header(mp, bp, ip->i_ino); if (error) { libxfs_putbuf(bp); return error; } } for (i = used = 0; i < freehdr.nvalid; i++) { if (i + freehdr.firstdb >= freetab->nents || freetab->ents[i + freehdr.firstdb].v != be16_to_cpu(bests[i])) { do_warn( _("free block %u entry %i for directory ino %" PRIu64 " bad\n"), da_bno, i, ip->i_ino); libxfs_putbuf(bp); return 1; } used += be16_to_cpu(bests[i]) != NULLDATAOFF; freetab->ents[i + freehdr.firstdb].s = 1; } if (used != freehdr.nused) { do_warn( _("free block %u for directory inode %" PRIu64 " bad nused\n"), da_bno, ip->i_ino); libxfs_putbuf(bp); return 1; } libxfs_putbuf(bp); } for (i = 0; i < freetab->nents; i++) { if ((freetab->ents[i].s == 0) && (freetab->ents[i].v != NULLDATAOFF)) { do_warn( _("missing freetab entry %u for directory inode %" PRIu64 "\n"), i, ip->i_ino); return 1; } } return fixit; } /* * If a directory is corrupt, we need to read in as many entries as possible, * destroy the entry and create a new one with recovered name/inode pairs. * (ie. get libxfs to do all the grunt work) */ static void longform_dir2_entry_check(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip, int *num_illegal, int *need_dot, ino_tree_node_t *irec, int ino_offset, dir_hash_tab_t *hashtab) { struct xfs_buf **bplist; xfs_dablk_t da_bno; freetab_t *freetab; int num_bps; int i; int isblock; int isleaf; xfs_fileoff_t next_da_bno; int seeval; int fixit = 0; xfs_dir2_db_t db; struct xfs_da_args args; *need_dot = 1; freetab = malloc(FREETAB_SIZE(ip->i_d.di_size / mp->m_dir_geo->blksize)); if (!freetab) { do_error(_("malloc failed in %s (%" PRId64 " bytes)\n"), __func__, FREETAB_SIZE(ip->i_d.di_size / mp->m_dir_geo->blksize)); exit(1); } freetab->naents = ip->i_d.di_size / mp->m_dir_geo->blksize; freetab->nents = 0; for (i = 0; i < freetab->naents; i++) { freetab->ents[i].v = NULLDATAOFF; freetab->ents[i].s = 0; } num_bps = freetab->naents; bplist = calloc(num_bps, sizeof(struct xfs_buf*)); if (!bplist) do_error(_("calloc failed in %s (%zu bytes)\n"), __func__, num_bps * sizeof(struct xfs_buf*)); /* is this a block, leaf, or node directory? */ args.dp = ip; args.geo = mp->m_dir_geo; libxfs_dir2_isblock(&args, &isblock); libxfs_dir2_isleaf(&args, &isleaf); /* check directory "data" blocks (ie. name/inode pairs) */ for (da_bno = 0, next_da_bno = 0; next_da_bno != NULLFILEOFF && da_bno < mp->m_dir_geo->leafblk; da_bno = (xfs_dablk_t)next_da_bno) { const struct xfs_buf_ops *ops; int error; struct xfs_dir2_data_hdr *d; next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1; if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) { /* * if this is the first block, there isn't anything we * can recover so we just trash it. */ if (da_bno == 0) { fixit++; goto out_fix; } break; } db = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno); if (db >= num_bps) { int last_size = num_bps; /* more data blocks than expected */ num_bps = db + 1; bplist = realloc(bplist, num_bps * sizeof(struct xfs_buf*)); if (!bplist) do_error(_("realloc failed in %s (%zu bytes)\n"), __func__, num_bps * sizeof(struct xfs_buf*)); /* Initialize the new elements */ for (i = last_size; i < num_bps; i++) bplist[i] = NULL; } if (isblock) ops = &xfs_dir3_block_buf_ops; else ops = &xfs_dir3_data_buf_ops; error = dir_read_buf(ip, da_bno, -1, &bplist[db], ops, &fixit); if (error) { do_warn( _("can't read data block %u for directory inode %" PRIu64 " error %d\n"), da_bno, ino, error); *num_illegal += 1; /* * we try to read all "data" blocks, but if we are in * block form and we fail, there isn't anything else to * read, and nothing we can do but trash it. */ if (isblock) { fixit++; goto out_fix; } continue; } /* check v5 metadata */ d = bplist[db]->b_addr; if (be32_to_cpu(d->magic) == XFS_DIR3_BLOCK_MAGIC || be32_to_cpu(d->magic) == XFS_DIR3_DATA_MAGIC) { struct xfs_buf *bp = bplist[db]; error = check_dir3_header(mp, bp, ino); if (error) { fixit++; continue; } } longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot, irec, ino_offset, &bplist[db], hashtab, &freetab, da_bno, isblock); } fixit |= (*num_illegal != 0) || dir2_is_badino(ino) || *need_dot; if (!dotdot_update) { /* check btree and freespace */ if (isblock) { struct xfs_dir2_data_hdr *block; xfs_dir2_block_tail_t *btp; xfs_dir2_leaf_entry_t *blp; block = bplist[0]->b_addr; btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); blp = xfs_dir2_block_leaf_p(btp); seeval = dir_hash_see_all(hashtab, blp, be32_to_cpu(btp->count), be32_to_cpu(btp->stale)); if (dir_hash_check(hashtab, ip, seeval)) fixit |= 1; } else if (isleaf) { fixit |= longform_dir2_check_leaf(mp, ip, hashtab, freetab); } else { fixit |= longform_dir2_check_node(mp, ip, hashtab, freetab); } } out_fix: if (!no_modify && (fixit || dotdot_update)) { dir_hash_dup_names(hashtab); for (i = 0; i < num_bps; i++) if (bplist[i]) libxfs_putbuf(bplist[i]); longform_dir2_rebuild(mp, ino, ip, irec, ino_offset, hashtab); *num_illegal = 0; *need_dot = 0; } else { for (i = 0; i < num_bps; i++) if (bplist[i]) libxfs_putbuf(bplist[i]); } free(bplist); free(freetab); } /* * shortform directory v2 processing routines -- entry verification and * bad entry deletion (pruning). */ static struct xfs_dir2_sf_entry * shortform_dir2_junk( struct xfs_mount *mp, struct xfs_dir2_sf_hdr *sfp, struct xfs_dir2_sf_entry *sfep, xfs_ino_t lino, int *max_size, int *index, int *bytes_deleted, int *ino_dirty) { struct xfs_dir2_sf_entry *next_sfep; int next_len; int next_elen; if (lino == orphanage_ino) orphanage_ino = 0; next_elen = M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen); next_sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep); /* * if we are just checking, simply return the pointer to the next entry * here so that the checking loop can continue. */ if (no_modify) { do_warn(_("would junk entry\n")); return next_sfep; } /* * now move all the remaining entries down over the junked entry and * clear the newly unused bytes at the tail of the directory region. */ next_len = *max_size - ((intptr_t)next_sfep - (intptr_t)sfp); *max_size -= next_elen; *bytes_deleted += next_elen; memmove(sfep, next_sfep, next_len); memset((void *)((intptr_t)sfep + next_len), 0, next_elen); sfp->count -= 1; *ino_dirty = 1; /* * WARNING: drop the index i by one so it matches the decremented count * for accurate comparisons in the loop test */ (*index)--; if (verbose) do_warn(_("junking entry\n")); else do_warn("\n"); return sfep; } static void shortform_dir2_entry_check(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip, int *ino_dirty, ino_tree_node_t *current_irec, int current_ino_offset, dir_hash_tab_t *hashtab) { xfs_ino_t lino; xfs_ino_t parent; struct xfs_dir2_sf_hdr *sfp; struct xfs_dir2_sf_entry *sfep; struct xfs_dir2_sf_entry *next_sfep; struct xfs_ifork *ifp; struct ino_tree_node *irec; int max_size; int ino_offset; int i; int bad_sfnamelen; int namelen; int bytes_deleted; char fname[MAXNAMELEN + 1]; int i8; ifp = &ip->i_df; sfp = (struct xfs_dir2_sf_hdr *) ifp->if_u1.if_data; *ino_dirty = 0; bytes_deleted = 0; max_size = ifp->if_bytes; ASSERT(ip->i_d.di_size <= ifp->if_bytes); /* * if just rebuild a directory due to a "..", update and return */ if (dotdot_update) { parent = get_inode_parent(current_irec, current_ino_offset); if (no_modify) { do_warn( _("would set .. in sf dir inode %" PRIu64 " to %" PRIu64 "\n"), ino, parent); } else { do_warn( _("setting .. in sf dir inode %" PRIu64 " to %" PRIu64 "\n"), ino, parent); M_DIROPS(mp)->sf_put_parent_ino(sfp, parent); *ino_dirty = 1; } return; } /* * no '.' entry in shortform dirs, just bump up ref count by 1 * '..' was already (or will be) accounted for and checked when * the directory is reached or will be taken care of when the * directory is moved to orphanage. */ add_inode_ref(current_irec, current_ino_offset); /* * Initialise i8 counter -- the parent inode number counts as well. */ i8 = M_DIROPS(mp)->sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM; /* * now run through entries, stop at first bad entry, don't need * to skip over '..' since that's encoded in its own field and * no need to worry about '.' since it doesn't exist. */ sfep = next_sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0; i < sfp->count && max_size > (intptr_t)next_sfep - (intptr_t)sfp; sfep = next_sfep, i++) { bad_sfnamelen = 0; lino = M_DIROPS(mp)->sf_get_ino(sfp, sfep); namelen = sfep->namelen; ASSERT(no_modify || namelen > 0); if (no_modify && namelen == 0) { /* * if we're really lucky, this is * the last entry in which case we * can use the dir size to set the * namelen value. otherwise, forget * it because we're not going to be * able to find the next entry. */ bad_sfnamelen = 1; if (i == sfp->count - 1) { namelen = ip->i_d.di_size - ((intptr_t) &sfep->name[0] - (intptr_t) sfp); } else { /* * don't process the rest of the directory, * break out of processing loop */ break; } } else if (no_modify && (intptr_t) sfep - (intptr_t) sfp + + M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen) > ip->i_d.di_size) { bad_sfnamelen = 1; if (i == sfp->count - 1) { namelen = ip->i_d.di_size - ((intptr_t) &sfep->name[0] - (intptr_t) sfp); } else { /* * don't process the rest of the directory, * break out of processing loop */ break; } } memmove(fname, sfep->name, sfep->namelen); fname[sfep->namelen] = '\0'; ASSERT(no_modify || (lino != NULLFSINO && lino != 0)); ASSERT(no_modify || !verify_inum(mp, lino)); /* * Also skip entries with bogus inode numbers if we're * in no modify mode. */ if (no_modify && verify_inum(mp, lino)) { next_sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep); continue; } irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino)); if (irec == NULL) { do_warn( _("entry \"%s\" in shortform directory %" PRIu64 " references non-existent inode %" PRIu64 "\n"), fname, ino, lino); next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, &max_size, &i, &bytes_deleted, ino_dirty); continue; } ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum; /* * if it's a free inode, blow out the entry. * by now, any inode that we think is free * really is free. */ if (is_inode_free(irec, ino_offset)) { do_warn( _("entry \"%s\" in shortform directory inode %" PRIu64 " points to free inode %" PRIu64 "\n"), fname, ino, lino); next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, &max_size, &i, &bytes_deleted, ino_dirty); continue; } /* * check if this inode is lost+found dir in the root */ if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) { /* * if it's not a directory, trash it */ if (!inode_isadir(irec, ino_offset)) { do_warn( _("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"), ORPHANAGE, lino, ino); next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, &max_size, &i, &bytes_deleted, ino_dirty); continue; } /* * if this is a dup, it will be picked up below, * otherwise, mark it as the orphanage for later. */ if (!orphanage_ino) orphanage_ino = lino; } /* * check for duplicate names in directory. */ if (!dir_hash_add(mp, hashtab, (xfs_dir2_dataptr_t) (sfep - xfs_dir2_sf_firstentry(sfp)), lino, sfep->namelen, sfep->name, M_DIROPS(mp)->sf_get_ftype(sfep))) { do_warn( _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"), fname, lino, ino); next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, &max_size, &i, &bytes_deleted, ino_dirty); continue; } if (!inode_isadir(irec, ino_offset)) { /* * check easy case first, regular inode, just bump * the link count */ add_inode_reached(irec, ino_offset); } else { parent = get_inode_parent(irec, ino_offset); /* * bump up the link counts in parent and child. * directory but if the link doesn't agree with * the .. in the child, blow out the entry */ if (is_inode_reached(irec, ino_offset)) { do_warn( _("entry \"%s\" in directory inode %" PRIu64 " references already connected inode %" PRIu64 ".\n"), fname, ino, lino); next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, &max_size, &i, &bytes_deleted, ino_dirty); continue; } else if (parent == ino) { add_inode_reached(irec, ino_offset); add_inode_ref(current_irec, current_ino_offset); } else if (parent == NULLFSINO) { /* ".." was missing, but this entry refers to it, so, set it as the parent and mark for rebuild */ do_warn( _("entry \"%s\" in dir ino %" PRIu64 " doesn't have a .. entry, will set it in ino %" PRIu64 ".\n"), fname, ino, lino); set_inode_parent(irec, ino_offset, ino); add_inode_reached(irec, ino_offset); add_inode_ref(current_irec, current_ino_offset); add_dotdot_update(XFS_INO_TO_AGNO(mp, lino), irec, ino_offset); } else { do_warn( _("entry \"%s\" in directory inode %" PRIu64 " not consistent with .. value (%" PRIu64 ") in inode %" PRIu64 ",\n"), fname, ino, parent, lino); next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, &max_size, &i, &bytes_deleted, ino_dirty); continue; } } /* validate ftype field if supported */ if (xfs_sb_version_hasftype(&mp->m_sb)) { uint8_t dir_ftype; uint8_t ino_ftype; dir_ftype = M_DIROPS(mp)->sf_get_ftype(sfep); ino_ftype = get_inode_ftype(irec, ino_offset); if (dir_ftype != ino_ftype) { if (no_modify) { do_warn( _("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"), dir_ftype, ino_ftype, ino, lino); } else { do_warn( _("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"), dir_ftype, ino_ftype, ino, lino); M_DIROPS(mp)->sf_put_ftype(sfep, ino_ftype); dir_hash_update_ftype(hashtab, (xfs_dir2_dataptr_t)(sfep - xfs_dir2_sf_firstentry(sfp)), ino_ftype); *ino_dirty = 1; } } } if (lino > XFS_DIR2_MAX_SHORT_INUM) i8++; /* * go onto next entry - we have to take entries with bad namelen * into account in no modify mode since we calculate size based * on next_sfep. */ ASSERT(no_modify || bad_sfnamelen == 0); next_sfep = (struct xfs_dir2_sf_entry *)((intptr_t)sfep + (bad_sfnamelen ? M_DIROPS(mp)->sf_entsize(sfp, namelen) : M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen))); } if (sfp->i8count != i8) { if (no_modify) { do_warn(_("would fix i8count in inode %" PRIu64 "\n"), ino); } else { if (i8 == 0) { struct xfs_dir2_sf_entry *tmp_sfep; tmp_sfep = next_sfep; process_sf_dir2_fixi8(mp, sfp, &tmp_sfep); bytes_deleted += (intptr_t)next_sfep - (intptr_t)tmp_sfep; next_sfep = tmp_sfep; } else sfp->i8count = i8; *ino_dirty = 1; do_warn(_("fixing i8count in inode %" PRIu64 "\n"), ino); } } /* * sync up sizes if required */ if (*ino_dirty && bytes_deleted > 0) { ASSERT(!no_modify); libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK); ip->i_d.di_size -= bytes_deleted; } if (ip->i_d.di_size != ip->i_df.if_bytes) { ASSERT(ip->i_df.if_bytes == (xfs_fsize_t) ((intptr_t) next_sfep - (intptr_t) sfp)); ip->i_d.di_size = (xfs_fsize_t) ((intptr_t) next_sfep - (intptr_t) sfp); do_warn( _("setting size to %" PRId64 " bytes to reflect junked entries\n"), ip->i_d.di_size); *ino_dirty = 1; } } /* * processes all reachable inodes in directories */ static void process_dir_inode( xfs_mount_t *mp, xfs_agnumber_t agno, ino_tree_node_t *irec, int ino_offset) { xfs_ino_t ino; xfs_inode_t *ip; xfs_trans_t *tp; dir_hash_tab_t *hashtab; int need_dot; int dirty, num_illegal, error, nres; ino = XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum + ino_offset); /* * open up directory inode, check all entries, * then call prune_dir_entries to remove all * remaining illegal directory entries. */ ASSERT(!is_inode_refchecked(irec, ino_offset) || dotdot_update); error = -libxfs_iget(mp, NULL, ino, 0, &ip, &phase6_ifork_ops); if (error) { if (!no_modify) do_error( _("couldn't map inode %" PRIu64 ", err = %d\n"), ino, error); else { do_warn( _("couldn't map inode %" PRIu64 ", err = %d\n"), ino, error); /* * see below for what we're doing if this * is root. Why do we need to do this here? * to ensure that the root doesn't show up * as being disconnected in the no_modify case. */ if (mp->m_sb.sb_rootino == ino) { add_inode_reached(irec, 0); add_inode_ref(irec, 0); } } add_inode_refchecked(irec, 0); return; } need_dot = dirty = num_illegal = 0; if (mp->m_sb.sb_rootino == ino) { /* * mark root inode reached and bump up * link count for root inode to account * for '..' entry since the root inode is * never reached by a parent. we know * that root's '..' is always good -- * guaranteed by phase 3 and/or below. */ add_inode_reached(irec, ino_offset); } add_inode_refchecked(irec, ino_offset); hashtab = dir_hash_init(ip->i_d.di_size); /* * look for bogus entries */ switch (ip->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: case XFS_DINODE_FMT_BTREE: /* * also check for missing '.' in longform dirs. * missing .. entries are added if required when * the directory is connected to lost+found. but * we need to create '.' entries here. */ longform_dir2_entry_check(mp, ino, ip, &num_illegal, &need_dot, irec, ino_offset, hashtab); break; case XFS_DINODE_FMT_LOCAL: /* * using the remove reservation is overkill * since at most we'll only need to log the * inode but it's easier than wedging a * new define in ourselves. */ nres = no_modify ? 0 : XFS_REMOVE_SPACE_RES(mp); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); shortform_dir2_entry_check(mp, ino, ip, &dirty, irec, ino_offset, hashtab); ASSERT(dirty == 0 || (dirty && !no_modify)); if (dirty) { libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE | XFS_ILOG_DDATA); error = -libxfs_trans_commit(tp); if (error) do_error( _("error %d fixing shortform directory %llu\n"), error, (unsigned long long)ip->i_ino); } else { libxfs_trans_cancel(tp); } break; default: break; } dir_hash_done(hashtab); /* * if we have to create a .. for /, do it now *before* * we delete the bogus entries, otherwise the directory * could transform into a shortform dir which would * probably cause the simulation to choke. Even * if the illegal entries get shifted around, it's ok * because the entries are structurally intact and in * in hash-value order so the simulation won't get confused * if it has to move them around. */ if (!no_modify && need_root_dotdot && ino == mp->m_sb.sb_rootino) { ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL); do_warn(_("recreating root directory .. entry\n")); nres = XFS_MKDIR_SPACE_RES(mp, 2); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); error = -libxfs_dir_createname(tp, ip, &xfs_name_dotdot, ip->i_ino, nres); if (error) do_error( _("can't make \"..\" entry in root inode %" PRIu64 ", createname error %d\n"), ino, error); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); if (error) do_error( _("root inode \"..\" entry recreation failed (%d)\n"), error); need_root_dotdot = 0; } else if (need_root_dotdot && ino == mp->m_sb.sb_rootino) { do_warn(_("would recreate root directory .. entry\n")); } /* * if we need to create the '.' entry, do so only if * the directory is a longform dir. if it's been * turned into a shortform dir, then the inode is ok * since shortform dirs have no '.' entry and the inode * has already been committed by prune_lf_dir_entry(). */ if (need_dot) { /* * bump up our link count but don't * bump up the inode link count. chances * are good that even though we lost '.' * the inode link counts reflect '.' so * leave the inode link count alone and if * it turns out to be wrong, we'll catch * that in phase 7. */ add_inode_ref(irec, ino_offset); if (no_modify) { do_warn( _("would create missing \".\" entry in dir ino %" PRIu64 "\n"), ino); } else if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) { /* * need to create . entry in longform dir. */ do_warn( _("creating missing \".\" entry in dir ino %" PRIu64 "\n"), ino); nres = XFS_MKDIR_SPACE_RES(mp, 1); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); if (error) res_failed(error); libxfs_trans_ijoin(tp, ip, 0); error = -libxfs_dir_createname(tp, ip, &xfs_name_dot, ip->i_ino, nres); if (error) do_error( _("can't make \".\" entry in dir ino %" PRIu64 ", createname error %d\n"), ino, error); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); if (error) do_error( _("root inode \".\" entry recreation failed (%d)\n"), error); } } libxfs_irele(ip); } /* * mark realtime bitmap and summary inodes as reached. * quota inode will be marked here as well */ static void mark_standalone_inodes(xfs_mount_t *mp) { ino_tree_node_t *irec; int offset; irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rbmino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino)); offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino) - irec->ino_startnum; add_inode_reached(irec, offset); irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rsumino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino)); offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino) - irec->ino_startnum; add_inode_reached(irec, offset); if (fs_quotas) { if (mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) { irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)); offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino) - irec->ino_startnum; add_inode_reached(irec, offset); } if (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) { irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)); offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino) - irec->ino_startnum; add_inode_reached(irec, offset); } if (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO) { irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_pquotino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino)); offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino) - irec->ino_startnum; add_inode_reached(irec, offset); } } } static void check_for_orphaned_inodes( xfs_mount_t *mp, xfs_agnumber_t agno, ino_tree_node_t *irec) { int i; xfs_ino_t ino; for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { ASSERT(is_inode_confirmed(irec, i)); if (is_inode_free(irec, i)) continue; if (is_inode_reached(irec, i)) continue; ASSERT(inode_isadir(irec, i) || num_inode_references(irec, i) == 0); ino = XFS_AGINO_TO_INO(mp, agno, i + irec->ino_startnum); if (inode_isadir(irec, i)) do_warn(_("disconnected dir inode %" PRIu64 ", "), ino); else do_warn(_("disconnected inode %" PRIu64 ", "), ino); if (!no_modify) { if (!orphanage_ino) orphanage_ino = mk_orphanage(mp); do_warn(_("moving to %s\n"), ORPHANAGE); mv_orphanage(mp, ino, inode_isadir(irec, i)); } else { do_warn(_("would move to %s\n"), ORPHANAGE); } /* * for read-only case, even though the inode isn't * really reachable, set the flag (and bump our link * count) anyway to fool phase 7 */ add_inode_reached(irec, i); } } static void traverse_function( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { ino_tree_node_t *irec; int i; prefetch_args_t *pf_args = arg; wait_for_inode_prefetch(pf_args); if (verbose) do_log(_(" - agno = %d\n"), agno); for (irec = findfirst_inode_rec(agno); irec; irec = next_ino_rec(irec)) { if (irec->ino_isa_dir == 0) continue; if (pf_args) { sem_post(&pf_args->ra_count); #ifdef XR_PF_TRACE sem_getvalue(&pf_args->ra_count, &i); pftrace( "processing inode chunk %p in AG %d (sem count = %d)", irec, agno, i); #endif } for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { if (inode_isadir(irec, i)) process_dir_inode(wq->wq_ctx, agno, irec, i); } } cleanup_inode_prefetch(pf_args); } static void update_missing_dotdot_entries( xfs_mount_t *mp) { dotdot_update_t *dir; /* * these entries parents were updated, rebuild them again * set dotdot_update flag so processing routines do not count links */ dotdot_update = 1; while (!list_empty(&dotdot_update_list)) { dir = list_entry(dotdot_update_list.prev, struct dotdot_update, list); list_del(&dir->list); process_dir_inode(mp, dir->agno, dir->irec, dir->ino_offset); free(dir); } } static void traverse_ags( struct xfs_mount *mp) { do_inode_prefetch(mp, 0, traverse_function, false, true); } void phase6(xfs_mount_t *mp) { ino_tree_node_t *irec; int i; memset(&zerocr, 0, sizeof(struct cred)); memset(&zerofsx, 0, sizeof(struct fsxattr)); orphanage_ino = 0; do_log(_("Phase 6 - check inode connectivity...\n")); incore_ext_teardown(mp); add_ino_ex_data(mp); /* * verify existence of root directory - if we have to * make one, it's ok for the incore data structs not to * know about it since everything about it (and the other * inodes in its chunk if a new chunk was created) are ok */ if (need_root_inode) { if (!no_modify) { do_warn(_("reinitializing root directory\n")); mk_root_dir(mp); need_root_inode = 0; need_root_dotdot = 0; } else { do_warn(_("would reinitialize root directory\n")); } } if (need_rbmino) { if (!no_modify) { do_warn(_("reinitializing realtime bitmap inode\n")); mk_rbmino(mp); need_rbmino = 0; } else { do_warn(_("would reinitialize realtime bitmap inode\n")); } } if (need_rsumino) { if (!no_modify) { do_warn(_("reinitializing realtime summary inode\n")); mk_rsumino(mp); need_rsumino = 0; } else { do_warn(_("would reinitialize realtime summary inode\n")); } } if (!no_modify) { do_log( _(" - resetting contents of realtime bitmap and summary inodes\n")); if (fill_rbmino(mp)) { do_warn( _("Warning: realtime bitmap may be inconsistent\n")); } if (fill_rsumino(mp)) { do_warn( _("Warning: realtime bitmap may be inconsistent\n")); } } mark_standalone_inodes(mp); do_log(_(" - traversing filesystem ...\n")); irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); /* * we always have a root inode, even if it's free... * if the root is free, forget it, lost+found is already gone */ if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) { need_root_inode = 1; } /* * then process all inodes by walking incore inode tree */ traverse_ags(mp); /* * any directories that had updated ".." entries, rebuild them now */ update_missing_dotdot_entries(mp); do_log(_(" - traversal finished ...\n")); do_log(_(" - moving disconnected inodes to %s ...\n"), ORPHANAGE); /* * move all disconnected inodes to the orphanage */ for (i = 0; i < glob_agcount; i++) { irec = findfirst_inode_rec(i); while (irec != NULL) { check_for_orphaned_inodes(mp, i, irec); irec = next_ino_rec(irec); } } } xfsprogs-5.3.0/repair/phase7.c0000644000175000017500000000577513466663244016115 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "versions.h" #include "progress.h" #include "threads.h" static void update_inode_nlinks( xfs_mount_t *mp, xfs_ino_t ino, uint32_t nlinks) { xfs_trans_t *tp; xfs_inode_t *ip; int error; int dirty; int nres; nres = no_modify ? 0 : 10; error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); ASSERT(error == 0); error = -libxfs_iget(mp, tp, ino, 0, &ip, &xfs_default_ifork_ops); if (error) { if (!no_modify) do_error( _("couldn't map inode %" PRIu64 ", err = %d\n"), ino, error); else { do_warn( _("couldn't map inode %" PRIu64 ", err = %d, can't compare link counts\n"), ino, error); return; } } dirty = 0; /* compare and set links if they differ. */ if (VFS_I(ip)->i_nlink != nlinks) { if (!no_modify) { do_warn( _("resetting inode %" PRIu64 " nlinks from %u to %u\n"), ino, VFS_I(ip)->i_nlink, nlinks); set_nlink(VFS_I(ip), nlinks); dirty = 1; } else { do_warn( _("would have reset inode %" PRIu64 " nlinks from %u to %u\n"), ino, VFS_I(ip)->i_nlink, nlinks); } } if (!dirty) { libxfs_trans_cancel(tp); } else { libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); /* * no need to do a bmap finish since * we're not allocating anything */ ASSERT(error == 0); error = -libxfs_trans_commit(tp); ASSERT(error == 0); } libxfs_irele(ip); } /* * for each ag, look at each inode 1 at a time. If the number of * links is bad, reset it, log the inode core, commit the transaction */ static void do_link_updates( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct xfs_mount *mp = wq->wq_ctx; ino_tree_node_t *irec; int j; uint32_t nrefs; for (irec = findfirst_inode_rec(agno); irec; irec = next_ino_rec(irec)) { for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { ASSERT(is_inode_confirmed(irec, j)); if (is_inode_free(irec, j)) continue; ASSERT(no_modify || is_inode_reached(irec, j)); nrefs = num_inode_references(irec, j); ASSERT(no_modify || nrefs > 0); if (get_inode_disk_nlinks(irec, j) != nrefs) update_inode_nlinks(wq->wq_ctx, XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum + j), nrefs); } } PROG_RPT_INC(prog_rpt_done[agno], 1); } void phase7( struct xfs_mount *mp, int scan_threads) { struct workqueue wq; int agno; if (!no_modify) do_log(_("Phase 7 - verify and correct link counts...\n")); else do_log(_("Phase 7 - verify link counts...\n")); set_progress_msg(PROGRESS_FMT_CORR_LINK, (uint64_t) glob_agcount); create_work_queue(&wq, mp, scan_threads); for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) queue_work(&wq, do_link_updates, agno, NULL); destroy_work_queue(&wq); print_final_rpt(); } xfsprogs-5.3.0/repair/prefetch.c0000644000175000017500000007041113570057155016505 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #include "libxfs.h" #include #include "avl.h" #include "btree.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "dir2.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "bmap.h" #include "versions.h" #include "threads.h" #include "prefetch.h" #include "progress.h" int do_prefetch = 1; /* * Performs prefetching by priming the libxfs cache by using a dedicate thread * scanning inodes and reading blocks in ahead of time they are required. * * Any I/O errors can be safely ignored. */ static xfs_mount_t *mp; static int mp_fd; static int pf_max_bytes; static int pf_max_bbs; static int pf_max_fsbs; static int pf_batch_bytes; static int pf_batch_fsbs; static void pf_read_inode_dirs(prefetch_args_t *, xfs_buf_t *); /* * Buffer priorities for the libxfs cache * * Directory metadata is ranked higher than other metadata as it's used * in phases 3, 4 and 6, while other metadata is only used in 3 & 4. */ /* intermediate directory btree nodes - can't be queued */ #define B_DIR_BMAP CACHE_PREFETCH_PRIORITY + 7 /* directory metadata in secondary queue */ #define B_DIR_META_2 CACHE_PREFETCH_PRIORITY + 6 /* dir metadata that had to fetched from the primary queue to avoid stalling */ #define B_DIR_META_H CACHE_PREFETCH_PRIORITY + 5 /* single block of directory metadata (can't batch read) */ #define B_DIR_META_S CACHE_PREFETCH_PRIORITY + 4 /* dir metadata with more than one block fetched in a single I/O */ #define B_DIR_META CACHE_PREFETCH_PRIORITY + 3 /* inode clusters with directory inodes */ #define B_DIR_INODE CACHE_PREFETCH_PRIORITY + 2 /* intermediate extent btree nodes */ #define B_BMAP CACHE_PREFETCH_PRIORITY + 1 /* inode clusters without any directory entries */ #define B_INODE CACHE_PREFETCH_PRIORITY /* * Test if bit 0 or 2 is set in the "priority tag" of the buffer to see if * the buffer is for an inode or other metadata. */ #define B_IS_INODE(f) (((f) & 5) == 0) #define DEF_BATCH_BYTES 0x10000 #define MAX_BUFS 128 #define IO_THRESHOLD (MAX_BUFS * 2) typedef enum pf_which { PF_PRIMARY, PF_SECONDARY, PF_META_ONLY } pf_which_t; static inline void pf_start_processing( prefetch_args_t *args) { if (!args->can_start_processing) { pftrace("signalling processing for AG %d", args->agno); args->can_start_processing = 1; pthread_cond_signal(&args->start_processing); } } static inline void pf_start_io_workers( prefetch_args_t *args) { if (!args->can_start_reading) { pftrace("signalling reading for AG %d", args->agno); args->can_start_reading = 1; pthread_cond_broadcast(&args->start_reading); } } static void pf_queue_io( prefetch_args_t *args, struct xfs_buf_map *map, int nmaps, int flag) { struct xfs_buf *bp; xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, map[0].bm_bn); /* * Never block on a buffer lock here, given that the actual repair * code might lock buffers in a different order from us. Given that * the lock holder is either reading it from disk himself or * completely overwriting it this behaviour is perfectly fine. */ bp = libxfs_getbuf_map(mp->m_dev, map, nmaps, LIBXFS_GETBUF_TRYLOCK); if (!bp) return; if (bp->b_flags & LIBXFS_B_UPTODATE) { if (B_IS_INODE(flag)) pf_read_inode_dirs(args, bp); XFS_BUF_SET_PRIORITY(bp, XFS_BUF_PRIORITY(bp) + CACHE_PREFETCH_PRIORITY); libxfs_putbuf(bp); return; } XFS_BUF_SET_PRIORITY(bp, flag); pthread_mutex_lock(&args->lock); btree_insert(args->io_queue, fsbno, bp); if (fsbno > args->last_bno_read) { if (B_IS_INODE(flag)) { args->inode_bufs_queued++; if (args->inode_bufs_queued == IO_THRESHOLD) pf_start_io_workers(args); } } else { ASSERT(!B_IS_INODE(flag)); XFS_BUF_SET_PRIORITY(bp, B_DIR_META_2); } pftrace("getbuf %c %p (%llu) in AG %d (fsbno = %lu) added to queue" "(inode_bufs_queued = %d, last_bno = %lu)", B_IS_INODE(flag) ? 'I' : 'M', bp, (long long)XFS_BUF_ADDR(bp), args->agno, fsbno, args->inode_bufs_queued, args->last_bno_read); pf_start_processing(args); pthread_mutex_unlock(&args->lock); } static int pf_read_bmbt_reclist( prefetch_args_t *args, xfs_bmbt_rec_t *rp, int numrecs) { int i; xfs_bmbt_irec_t irec; xfs_filblks_t cp = 0; /* prev count */ xfs_fileoff_t op = 0; /* prev offset */ #define MAP_ARRAY_SZ 4 struct xfs_buf_map map_array[MAP_ARRAY_SZ]; struct xfs_buf_map *map = map_array; int max_extents = MAP_ARRAY_SZ; int nmaps = 0; unsigned int len = 0; int ret = 0; for (i = 0; i < numrecs; i++) { libxfs_bmbt_disk_get_all(rp + i, &irec); if (((i > 0) && (op + cp > irec.br_startoff)) || (irec.br_blockcount == 0) || (irec.br_startoff >= fs_max_file_offset)) goto out_free; if (!verify_dfsbno(mp, irec.br_startblock) || !verify_dfsbno(mp, irec.br_startblock + irec.br_blockcount - 1)) goto out_free; if (!args->dirs_only && ((irec.br_startoff + irec.br_blockcount) >= mp->m_dir_geo->freeblk)) break; /* only Phase 6 reads the free blocks */ op = irec.br_startoff; cp = irec.br_blockcount; while (irec.br_blockcount) { unsigned int bm_len; pftrace("queuing dir extent in AG %d", args->agno); if (len + irec.br_blockcount >= mp->m_dir_geo->fsbcount) bm_len = mp->m_dir_geo->fsbcount - len; else bm_len = irec.br_blockcount; len += bm_len; map[nmaps].bm_bn = XFS_FSB_TO_DADDR(mp, irec.br_startblock); map[nmaps].bm_len = XFS_FSB_TO_BB(mp, bm_len); nmaps++; if (len == mp->m_dir_geo->fsbcount) { pf_queue_io(args, map, nmaps, B_DIR_META); len = 0; nmaps = 0; } irec.br_blockcount -= bm_len; irec.br_startblock += bm_len; /* * Handle very fragmented dir2 blocks with dynamically * allocated buffer maps. */ if (nmaps >= max_extents) { struct xfs_buf_map *old_map = NULL; if (map == map_array) { old_map = map; map = NULL; } max_extents *= 2; map = realloc(map, max_extents * sizeof(*map)); if (map == NULL) { do_error( _("couldn't malloc dir2 buffer list\n")); exit(1); } if (old_map) memcpy(map, old_map, sizeof(map_array)); } } } ret = 1; out_free: if (map != map_array) free(map); return ret; } /* * simplified version of the main scan_lbtree. Returns 0 to stop. */ static int pf_scan_lbtree( xfs_fsblock_t dbno, int level, int isadir, prefetch_args_t *args, int (*func)(struct xfs_btree_block *block, int level, int isadir, prefetch_args_t *args)) { xfs_buf_t *bp; int rc; bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dbno), XFS_FSB_TO_BB(mp, 1), 0, &xfs_bmbt_buf_ops); if (!bp) return 0; XFS_BUF_SET_PRIORITY(bp, isadir ? B_DIR_BMAP : B_BMAP); /* * If the verifier flagged a problem with the buffer, we can't trust * its contents for the purposes of reading ahead. Stop prefetching * the tree and mark the buffer unchecked so that the next read of the * buffer will retain the error status and be acted upon appropriately. */ if (bp->b_error) { bp->b_flags |= LIBXFS_B_UNCHECKED; libxfs_putbuf(bp); return 0; } rc = (*func)(XFS_BUF_TO_BLOCK(bp), level - 1, isadir, args); libxfs_putbuf(bp); return rc; } static int pf_scanfunc_bmap( struct xfs_btree_block *block, int level, int isadir, prefetch_args_t *args) { xfs_bmbt_ptr_t *pp; int numrecs; int i; xfs_fsblock_t dbno; /* * do some validation on the block contents */ if ((block->bb_magic != cpu_to_be32(XFS_BMAP_MAGIC) && block->bb_magic != cpu_to_be32(XFS_BMAP_CRC_MAGIC)) || (be16_to_cpu(block->bb_level) != level)) return 0; numrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (numrecs > mp->m_bmap_dmxr[0] || !isadir) return 0; return pf_read_bmbt_reclist(args, XFS_BMBT_REC_ADDR(mp, block, 1), numrecs); } if (numrecs > mp->m_bmap_dmxr[1]) return 0; pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); for (i = 0; i < numrecs; i++) { dbno = get_unaligned_be64(&pp[i]); if (!verify_dfsbno(mp, dbno)) return 0; if (!pf_scan_lbtree(dbno, level, isadir, args, pf_scanfunc_bmap)) return 0; } return 1; } static void pf_read_btinode( prefetch_args_t *args, xfs_dinode_t *dino, int isadir) { xfs_bmdr_block_t *dib; xfs_bmbt_ptr_t *pp; int i; int level; int numrecs; int dsize; xfs_fsblock_t dbno; dib = (xfs_bmdr_block_t *)XFS_DFORK_DPTR(dino); level = be16_to_cpu(dib->bb_level); numrecs = be16_to_cpu(dib->bb_numrecs); if ((numrecs == 0) || (level == 0) || (level > XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK))) return; /* * use bmdr/dfork_dsize since the root block is in the data fork */ if (XFS_BMDR_SPACE_CALC(numrecs) > XFS_DFORK_DSIZE(dino, mp)) return; dsize = XFS_DFORK_DSIZE(dino, mp); pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(dsize, 0)); for (i = 0; i < numrecs; i++) { dbno = get_unaligned_be64(&pp[i]); if (!verify_dfsbno(mp, dbno)) break; if (!pf_scan_lbtree(dbno, level, isadir, args, pf_scanfunc_bmap)) break; } } static void pf_read_exinode( prefetch_args_t *args, xfs_dinode_t *dino) { pf_read_bmbt_reclist(args, (xfs_bmbt_rec_t *)XFS_DFORK_DPTR(dino), be32_to_cpu(dino->di_nextents)); } static void pf_read_inode_dirs( prefetch_args_t *args, xfs_buf_t *bp) { xfs_dinode_t *dino; int icnt = 0; int hasdir = 0; int isadir; libxfs_readbuf_verify(bp, &xfs_inode_buf_ops); if (bp->b_error) return; for (icnt = 0; icnt < (bp->b_bcount >> mp->m_sb.sb_inodelog); icnt++) { dino = xfs_make_iptr(mp, bp, icnt); /* * We are only prefetching directory contents in extents * and btree nodes for other inodes */ isadir = (be16_to_cpu(dino->di_mode) & S_IFMT) == S_IFDIR; hasdir |= isadir; if (dino->di_format <= XFS_DINODE_FMT_LOCAL) continue; if (!isadir && (dino->di_format == XFS_DINODE_FMT_EXTENTS || args->dirs_only)) continue; /* * do some checks on the inode to see if we can prefetch * its directory data. It's a cut down version of * process_dinode_int() in dinode.c. */ if (dino->di_format > XFS_DINODE_FMT_BTREE) continue; if (be16_to_cpu(dino->di_magic) != XFS_DINODE_MAGIC) continue; if (!libxfs_dinode_good_version(mp, dino->di_version)) continue; if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp)) continue; if ((dino->di_forkoff != 0) && (dino->di_forkoff >= XFS_LITINO(mp, dino->di_version) >> 3)) continue; switch (dino->di_format) { case XFS_DINODE_FMT_EXTENTS: pf_read_exinode(args, dino); break; case XFS_DINODE_FMT_BTREE: pf_read_btinode(args, dino, isadir); break; } } if (hasdir) XFS_BUF_SET_PRIORITY(bp, B_DIR_INODE); } /* * pf_batch_read must be called with the lock locked. */ static void pf_batch_read( prefetch_args_t *args, pf_which_t which, void *buf) { xfs_buf_t *bplist[MAX_BUFS]; unsigned int num; off64_t first_off, last_off, next_off; int len, size; int i; int inode_bufs; unsigned long fsbno = 0; unsigned long max_fsbno; char *pbuf; for (;;) { num = 0; if (which == PF_SECONDARY) { bplist[0] = btree_find(args->io_queue, 0, &fsbno); max_fsbno = min(fsbno + pf_max_fsbs, args->last_bno_read); } else { bplist[0] = btree_find(args->io_queue, args->last_bno_read, &fsbno); max_fsbno = fsbno + pf_max_fsbs; } while (bplist[num] && num < MAX_BUFS && fsbno < max_fsbno) { /* * Discontiguous buffers need special handling, so stop * gathering new buffers and process the list and this * discontigous buffer immediately. This avoids the * complexity of keeping a separate discontigous buffer * list and seeking back over ranges we've already done * optimised reads for. */ if ((bplist[num]->b_flags & LIBXFS_B_DISCONTIG)) { num++; break; } if (which != PF_META_ONLY || !B_IS_INODE(XFS_BUF_PRIORITY(bplist[num]))) num++; if (num == MAX_BUFS) break; bplist[num] = btree_lookup_next(args->io_queue, &fsbno); } if (!num) return; /* * do a big read if 25% of the potential buffer is useful, * otherwise, find as many close together blocks and * read them in one read */ first_off = LIBXFS_BBTOOFF64(XFS_BUF_ADDR(bplist[0])); last_off = LIBXFS_BBTOOFF64(XFS_BUF_ADDR(bplist[num-1])) + XFS_BUF_SIZE(bplist[num-1]); while (num > 1 && last_off - first_off > pf_max_bytes) { num--; last_off = LIBXFS_BBTOOFF64(XFS_BUF_ADDR(bplist[num-1])) + XFS_BUF_SIZE(bplist[num-1]); } if (num < ((last_off - first_off) >> (mp->m_sb.sb_blocklog + 3))) { /* * not enough blocks for one big read, so determine * the number of blocks that are close enough. */ last_off = first_off + XFS_BUF_SIZE(bplist[0]); for (i = 1; i < num; i++) { next_off = LIBXFS_BBTOOFF64(XFS_BUF_ADDR(bplist[i])) + XFS_BUF_SIZE(bplist[i]); if (next_off - last_off > pf_batch_bytes) break; last_off = next_off; } num = i; } for (i = 0; i < num; i++) { if (btree_delete(args->io_queue, XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bplist[i]))) == NULL) do_error(_("prefetch corruption\n")); } if (which == PF_PRIMARY) { for (inode_bufs = 0, i = 0; i < num; i++) { if (B_IS_INODE(XFS_BUF_PRIORITY(bplist[i]))) inode_bufs++; } args->inode_bufs_queued -= inode_bufs; if (inode_bufs && (first_off >> mp->m_sb.sb_blocklog) > pf_batch_fsbs) args->last_bno_read = (first_off >> mp->m_sb.sb_blocklog); } #ifdef XR_PF_TRACE pftrace("reading bbs %llu to %llu (%d bufs) from %s queue in AG %d (last_bno = %lu, inode_bufs = %d)", (long long)XFS_BUF_ADDR(bplist[0]), (long long)XFS_BUF_ADDR(bplist[num-1]), num, (which != PF_SECONDARY) ? "pri" : "sec", args->agno, args->last_bno_read, args->inode_bufs_queued); #endif pthread_mutex_unlock(&args->lock); /* * now read the data and put into the xfs_but_t's */ len = pread(mp_fd, buf, (int)(last_off - first_off), first_off); /* * Check the last buffer on the list to see if we need to * process a discontiguous buffer. The gather above loop * guarantees that only the last buffer in the list will be a * discontiguous buffer. */ if ((bplist[num - 1]->b_flags & LIBXFS_B_DISCONTIG)) { libxfs_readbufr_map(mp->m_ddev_targp, bplist[num - 1], 0); bplist[num - 1]->b_flags |= LIBXFS_B_UNCHECKED; libxfs_putbuf(bplist[num - 1]); num--; } if (len > 0) { /* * go through the xfs_buf_t list copying from the * read buffer into the xfs_buf_t's and release them. */ for (i = 0; i < num; i++) { pbuf = ((char *)buf) + (LIBXFS_BBTOOFF64(XFS_BUF_ADDR(bplist[i])) - first_off); size = XFS_BUF_SIZE(bplist[i]); if (len < size) break; memcpy(bplist[i]->b_addr, pbuf, size); bplist[i]->b_flags |= (LIBXFS_B_UPTODATE | LIBXFS_B_UNCHECKED); len -= size; if (B_IS_INODE(XFS_BUF_PRIORITY(bplist[i]))) pf_read_inode_dirs(args, bplist[i]); else if (which == PF_META_ONLY) XFS_BUF_SET_PRIORITY(bplist[i], B_DIR_META_H); else if (which == PF_PRIMARY && num == 1) XFS_BUF_SET_PRIORITY(bplist[i], B_DIR_META_S); } } for (i = 0; i < num; i++) { pftrace("putbuf %c %p (%llu) in AG %d", B_IS_INODE(XFS_BUF_PRIORITY(bplist[i])) ? 'I' : 'M', bplist[i], (long long)XFS_BUF_ADDR(bplist[i]), args->agno); libxfs_putbuf(bplist[i]); } pthread_mutex_lock(&args->lock); if (which != PF_SECONDARY) { pftrace("inode_bufs_queued for AG %d = %d", args->agno, args->inode_bufs_queued); /* * if primary inode queue running low, process metadata * in boths queues to avoid I/O starvation as the * processing thread would be waiting for a metadata * buffer */ if (which == PF_PRIMARY && !args->queuing_done && args->inode_bufs_queued < IO_THRESHOLD) { pftrace("reading metadata bufs from primary queue for AG %d", args->agno); pf_batch_read(args, PF_META_ONLY, buf); pftrace("reading bufs from secondary queue for AG %d", args->agno); pf_batch_read(args, PF_SECONDARY, buf); } } } } static void * pf_io_worker( void *param) { prefetch_args_t *args = param; void *buf = memalign(libxfs_device_alignment(), pf_max_bytes); if (buf == NULL) return NULL; pthread_mutex_lock(&args->lock); while (!args->queuing_done || !btree_is_empty(args->io_queue)) { pftrace("waiting to start prefetch I/O for AG %d", args->agno); while (!args->can_start_reading && !args->queuing_done) pthread_cond_wait(&args->start_reading, &args->lock); pftrace("starting prefetch I/O for AG %d", args->agno); pf_batch_read(args, PF_PRIMARY, buf); pf_batch_read(args, PF_SECONDARY, buf); pftrace("ran out of bufs to prefetch for AG %d", args->agno); if (!args->queuing_done) args->can_start_reading = 0; } pthread_mutex_unlock(&args->lock); free(buf); pftrace("finished prefetch I/O for AG %d", args->agno); return NULL; } static int pf_create_prefetch_thread( prefetch_args_t *args); /* * If we fail to create the queuing thread or can't create even one * prefetch thread, we need to let processing continue without it. */ static void pf_skip_prefetch_thread(prefetch_args_t *args) { prefetch_args_t *next; pthread_mutex_lock(&args->lock); args->prefetch_done = 1; pf_start_processing(args); next = args->next_args; args->next_args = NULL; pthread_mutex_unlock(&args->lock); if (next) pf_create_prefetch_thread(next); } static void * pf_queuing_worker( void *param) { prefetch_args_t *args = param; prefetch_args_t *next_args; int num_inos; ino_tree_node_t *irec; ino_tree_node_t *cur_irec; xfs_agblock_t bno; int i; int err; uint64_t sparse; struct xfs_ino_geometry *igeo = M_IGEO(mp); unsigned long long cluster_mask; cluster_mask = (1ULL << igeo->inodes_per_cluster) - 1; for (i = 0; i < PF_THREAD_COUNT; i++) { err = pthread_create(&args->io_threads[i], NULL, pf_io_worker, args); if (err != 0) { do_warn(_("failed to create prefetch thread: %s\n"), strerror(err)); pftrace("failed to create prefetch thread for AG %d: %s", args->agno, strerror(err)); args->io_threads[i] = 0; if (i == 0) { pf_skip_prefetch_thread(args); return NULL; } /* * since we have at least one I/O thread, use them for * prefetch */ break; } } pftrace("starting prefetch for AG %d", args->agno); for (irec = findfirst_inode_rec(args->agno); irec != NULL; irec = next_ino_rec(irec)) { cur_irec = irec; num_inos = XFS_INODES_PER_CHUNK; while (num_inos < igeo->ialloc_inos && irec != NULL) { irec = next_ino_rec(irec); num_inos += XFS_INODES_PER_CHUNK; } if (args->dirs_only && cur_irec->ino_isa_dir == 0) continue; #ifdef XR_PF_TRACE sem_getvalue(&args->ra_count, &i); pftrace("queuing irec %p in AG %d, sem count = %d", irec, args->agno, i); #endif err = sem_trywait(&args->ra_count); if (err < 0 && errno == EAGAIN) { /* * Kick the queue once we have reached the limit; * without this the threads processing the inodes * might get stuck on a buffer that has been locked * and added to the I/O queue but is waiting for * the thread to be woken. * Start processing as well, in case everything so * far was already prefetched and the queue is empty. */ pf_start_io_workers(args); pf_start_processing(args); sem_wait(&args->ra_count); } num_inos = 0; bno = XFS_AGINO_TO_AGBNO(mp, cur_irec->ino_startnum); sparse = cur_irec->ir_sparse; do { struct xfs_buf_map map; map.bm_bn = XFS_AGB_TO_DADDR(mp, args->agno, bno); map.bm_len = XFS_FSB_TO_BB(mp, igeo->blocks_per_cluster); /* * Queue I/O for each non-sparse cluster. We can check * sparse state in cluster sized chunks as cluster size * is the min. granularity of sparse irec regions. */ if ((sparse & cluster_mask) == 0) pf_queue_io(args, &map, 1, (cur_irec->ino_isa_dir != 0) ? B_DIR_INODE : B_INODE); bno += igeo->blocks_per_cluster; num_inos += igeo->inodes_per_cluster; sparse >>= igeo->inodes_per_cluster; } while (num_inos < igeo->ialloc_inos); } pthread_mutex_lock(&args->lock); pftrace("finished queuing inodes for AG %d (inode_bufs_queued = %d)", args->agno, args->inode_bufs_queued); args->queuing_done = 1; pf_start_io_workers(args); pf_start_processing(args); pthread_mutex_unlock(&args->lock); /* now wait for the readers to finish */ for (i = 0; i < PF_THREAD_COUNT; i++) if (args->io_threads[i]) pthread_join(args->io_threads[i], NULL); pftrace("prefetch for AG %d finished", args->agno); pthread_mutex_lock(&args->lock); ASSERT(btree_is_empty(args->io_queue)); args->prefetch_done = 1; next_args = args->next_args; args->next_args = NULL; pthread_mutex_unlock(&args->lock); if (next_args) pf_create_prefetch_thread(next_args); return NULL; } static int pf_create_prefetch_thread( prefetch_args_t *args) { int err; pftrace("creating queue thread for AG %d", args->agno); err = pthread_create(&args->queuing_thread, NULL, pf_queuing_worker, args); if (err != 0) { do_warn(_("failed to create prefetch thread: %s\n"), strerror(err)); pftrace("failed to create prefetch thread for AG %d: %s", args->agno, strerror(err)); args->queuing_thread = 0; pf_skip_prefetch_thread(args); } return err == 0; } void init_prefetch( xfs_mount_t *pmp) { mp = pmp; mp_fd = libxfs_device_to_fd(mp->m_ddev_targp->dev); pf_max_bytes = sysconf(_SC_PAGE_SIZE) << 7; pf_max_bbs = pf_max_bytes >> BBSHIFT; pf_max_fsbs = pf_max_bytes >> mp->m_sb.sb_blocklog; pf_batch_bytes = DEF_BATCH_BYTES; pf_batch_fsbs = DEF_BATCH_BYTES >> (mp->m_sb.sb_blocklog + 1); } prefetch_args_t * start_inode_prefetch( xfs_agnumber_t agno, int dirs_only, prefetch_args_t *prev_args) { prefetch_args_t *args; long max_queue; struct xfs_ino_geometry *igeo = M_IGEO(mp); if (!do_prefetch || agno >= mp->m_sb.sb_agcount) return NULL; args = calloc(1, sizeof(prefetch_args_t)); btree_init(&args->io_queue); if (pthread_mutex_init(&args->lock, NULL) != 0) do_error(_("failed to initialize prefetch mutex\n")); if (pthread_cond_init(&args->start_reading, NULL) != 0) do_error(_("failed to initialize prefetch cond var\n")); if (pthread_cond_init(&args->start_processing, NULL) != 0) do_error(_("failed to initialize prefetch cond var\n")); args->agno = agno; args->dirs_only = dirs_only; /* * use only 1/8 of the libxfs cache as we are only counting inodes * and not any other associated metadata like directories */ max_queue = libxfs_bcache->c_maxcount / thread_count / 8; if (igeo->inode_cluster_size > mp->m_sb.sb_blocksize) max_queue = max_queue * igeo->blocks_per_cluster / igeo->ialloc_blks; sem_init(&args->ra_count, 0, max_queue); if (!prev_args) { if (!pf_create_prefetch_thread(args)) return NULL; } else { pthread_mutex_lock(&prev_args->lock); if (prev_args->prefetch_done) { pthread_mutex_unlock(&prev_args->lock); if (!pf_create_prefetch_thread(args)) args = NULL; } else { prev_args->next_args = args; pftrace("queued AG %d after AG %d", args->agno, prev_args->agno); pthread_mutex_unlock(&prev_args->lock); } } return args; } /* * prefetch_ag_range runs a prefetch-and-process loop across a range of AGs. It * begins with @start+ag, and finishes with @end_ag - 1 (i.e. does not prefetch * or process @end_ag). The function starts prefetch on the first AG, then loops * starting prefetch on the next AG and then blocks processing the current AG as * the prefetch queue brings inodes into the processing queue. * * There is only one prefetch taking place at a time, so the prefetch on the * next AG only starts once the current AG has been completely prefetched. Hence * the prefetch of the next AG will start some time before the processing of the * current AG finishes, ensuring that when we iterate an start processing the * next AG there is already a significant queue of inodes to process. * * Prefetch is done this way to prevent it from running too far ahead of the * processing. Allowing it to do so can cause cache thrashing, where new * prefetch causes previously prefetched buffers to be reclaimed before the * processing thread uses them. This results in reading all the inodes and * metadata twice per phase and it greatly slows down the processing. Hence we * have to carefully control how far ahead we prefetch... */ static void prefetch_ag_range( struct workqueue *work, xfs_agnumber_t start_ag, xfs_agnumber_t end_ag, bool dirs_only, void (*func)(struct workqueue *, xfs_agnumber_t, void *)) { int i; struct prefetch_args *pf_args[2]; pf_args[start_ag & 1] = start_inode_prefetch(start_ag, dirs_only, NULL); for (i = start_ag; i < end_ag; i++) { /* Don't prefetch end_ag */ if (i + 1 < end_ag) pf_args[(~i) & 1] = start_inode_prefetch(i + 1, dirs_only, pf_args[i & 1]); func(work, i, pf_args[i & 1]); } } struct pf_work_args { xfs_agnumber_t start_ag; xfs_agnumber_t end_ag; bool dirs_only; void (*func)(struct workqueue *, xfs_agnumber_t, void *); }; static void prefetch_ag_range_work( struct workqueue *work, xfs_agnumber_t unused, void *args) { struct pf_work_args *wargs = args; prefetch_ag_range(work, wargs->start_ag, wargs->end_ag, wargs->dirs_only, wargs->func); free(args); } /* * Do inode prefetch in the most optimal way for the context under which repair * has been run. */ void do_inode_prefetch( struct xfs_mount *mp, int stride, void (*func)(struct workqueue *, xfs_agnumber_t, void *), bool check_cache, bool dirs_only) { int i; struct workqueue queue; struct workqueue *queues; int queues_started = 0; /* * If the previous phases of repair have not overflowed the buffer * cache, then we don't need to re-read any of the metadata in the * filesystem - it's all in the cache. In that case, run a thread per * CPU to maximise parallelism of the queue to be processed. */ if (check_cache && !libxfs_bcache_overflowed()) { queue.wq_ctx = mp; create_work_queue(&queue, mp, platform_nproc()); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&queue, func, i, NULL); destroy_work_queue(&queue); return; } /* * single threaded behaviour - single prefetch thread, processed * directly after each AG is queued. */ if (!stride) { queue.wq_ctx = mp; prefetch_ag_range(&queue, 0, mp->m_sb.sb_agcount, dirs_only, func); return; } /* * create one worker thread for each segment of the volume */ queues = malloc(thread_count * sizeof(struct workqueue)); for (i = 0; i < thread_count; i++) { struct pf_work_args *wargs; wargs = malloc(sizeof(struct pf_work_args)); wargs->start_ag = i * stride; wargs->end_ag = min((i + 1) * stride, mp->m_sb.sb_agcount); wargs->dirs_only = dirs_only; wargs->func = func; create_work_queue(&queues[i], mp, 1); queue_work(&queues[i], prefetch_ag_range_work, 0, wargs); queues_started++; if (wargs->end_ag >= mp->m_sb.sb_agcount) break; } /* * wait for workers to complete */ for (i = 0; i < queues_started; i++) destroy_work_queue(&queues[i]); free(queues); } void wait_for_inode_prefetch( prefetch_args_t *args) { if (args == NULL) return; pthread_mutex_lock(&args->lock); while (!args->can_start_processing) { pftrace("waiting to start processing AG %d", args->agno); pthread_cond_wait(&args->start_processing, &args->lock); } pftrace("can start processing AG %d", args->agno); pthread_mutex_unlock(&args->lock); } void cleanup_inode_prefetch( prefetch_args_t *args) { if (args == NULL) return; pftrace("waiting AG %d prefetch to finish", args->agno); if (args->queuing_thread) pthread_join(args->queuing_thread, NULL); pftrace("AG %d prefetch done", args->agno); ASSERT(args->next_args == NULL); pthread_mutex_destroy(&args->lock); pthread_cond_destroy(&args->start_reading); pthread_cond_destroy(&args->start_processing); sem_destroy(&args->ra_count); btree_destroy(args->io_queue); free(args); } #ifdef XR_PF_TRACE static FILE *pf_trace_file; void pftrace_init(void) { pf_trace_file = fopen("/tmp/xfs_repair_prefetch.trace", "w"); setvbuf(pf_trace_file, NULL, _IOLBF, 1024); } void pftrace_done(void) { fclose(pf_trace_file); } void _pftrace(const char *func, const char *msg, ...) { char buf[200]; struct timeval tv; va_list args; gettimeofday(&tv, NULL); va_start(args, msg); vsnprintf(buf, sizeof(buf), msg, args); buf[sizeof(buf)-1] = '\0'; va_end(args); fprintf(pf_trace_file, "%lu.%06lu %s: %s\n", tv.tv_sec, tv.tv_usec, func, buf); } #endif xfsprogs-5.3.0/repair/prefetch.h0000644000175000017500000000301413435336037016504 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #ifndef _XFS_REPAIR_PREFETCH_H #define _XFS_REPAIR_PREFETCH_H #include #include "incore.h" struct workqueue; extern int do_prefetch; #define PF_THREAD_COUNT 4 typedef struct prefetch_args { pthread_mutex_t lock; pthread_t queuing_thread; pthread_t io_threads[PF_THREAD_COUNT]; struct btree_root *io_queue; pthread_cond_t start_reading; pthread_cond_t start_processing; int agno; int dirs_only; volatile int can_start_reading; volatile int can_start_processing; volatile int prefetch_done; volatile int queuing_done; volatile int inode_bufs_queued; volatile xfs_fsblock_t last_bno_read; sem_t ra_count; struct prefetch_args *next_args; } prefetch_args_t; void init_prefetch( xfs_mount_t *pmp); prefetch_args_t * start_inode_prefetch( xfs_agnumber_t agno, int dirs_only, prefetch_args_t *prev_args); void do_inode_prefetch( struct xfs_mount *mp, int stride, void (*func)(struct workqueue *, xfs_agnumber_t, void *), bool check_cache, bool dirs_only); void wait_for_inode_prefetch( prefetch_args_t *args); void cleanup_inode_prefetch( prefetch_args_t *args); #ifdef XR_PF_TRACE void pftrace_init(void); void pftrace_done(void); #define pftrace(msg...) _pftrace(__FUNCTION__, ## msg) void _pftrace(const char *, const char *, ...); #else static inline void pftrace_init(void) { }; static inline void pftrace_done(void) { }; static inline void pftrace(const char *msg, ...) { }; #endif #endif /* _XFS_REPAIR_PREFETCH_H */ xfsprogs-5.3.0/repair/progress.c0000644000175000017500000003047613435336037016557 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #include "libxfs.h" #include "globals.h" #include "progress.h" #include "err_protos.h" #include #define ONEMINUTE 60 #define ONEHOUR (60*ONEMINUTE) #define ONEDAY (24*ONEHOUR) #define ONEWEEK (7*ONEDAY) static char *rpt_types[] = { #define TYPE_INODE 0 N_("inodes"), #define TYPE_BLOCK 1 N_("blocks"), #define TYPE_DIR 2 N_("directories"), #define TYPE_AG 3 N_("allocation groups"), #define TYPE_AGI_BUCKET 4 N_("AGI unlinked buckets"), #define TYPE_EXTENTS 5 N_("extents"), #define TYPE_RTEXTENTS 6 N_("realtime extents"), #define TYPE_UNLINKED_LIST 7 N_("unlinked lists") }; static char *rpt_fmts[] = { #define FMT1 0 N_(" - %02d:%02d:%02d: %s - %llu of %llu %s done\n"), #define FMT2 1 N_(" - %02d:%02d:%02d: %s - %llu %s done\n"), }; typedef struct progress_rpt_s { short format; char *msg; char **fmt; char **type; } progress_rpt_t; static progress_rpt_t progress_rpt_reports[] = { {FMT1, N_("scanning filesystem freespace"), /* 0 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT1, N_("scanning agi unlinked lists"), /* 1 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT2, N_("check uncertain AG inodes"), /* 2 */ &rpt_fmts[FMT2], &rpt_types[TYPE_AGI_BUCKET]}, {FMT1, N_("process known inodes and inode discovery"), /* 3 */ &rpt_fmts[FMT1], &rpt_types[TYPE_INODE]}, {FMT1, N_("process newly discovered inodes"), /* 4 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT1, N_("setting up duplicate extent list"), /* 5 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT1, N_("initialize realtime bitmap"), /* 6 */ &rpt_fmts[FMT1], &rpt_types[TYPE_BLOCK]}, {FMT1, N_("reset realtime bitmaps"), /* 7 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT1, N_("check for inodes claiming duplicate blocks"), /* 8 */ &rpt_fmts[FMT1], &rpt_types[TYPE_INODE]}, {FMT1, N_("rebuild AG headers and trees"), /* 9 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT1, N_("traversing filesystem"), /* 10 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT2, N_("traversing all unattached subtrees"), /* 11 */ &rpt_fmts[FMT2], &rpt_types[TYPE_DIR]}, {FMT2, N_("moving disconnected inodes to lost+found"), /* 12 */ &rpt_fmts[FMT2], &rpt_types[TYPE_INODE]}, {FMT1, N_("verify and correct link counts"), /* 13 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]}, {FMT1, N_("verify link counts"), /* 14 */ &rpt_fmts[FMT1], &rpt_types[TYPE_AG]} }; static pthread_t report_thread; typedef struct msg_block_s { pthread_mutex_t mutex; progress_rpt_t *format; uint64_t *done; uint64_t *total; int count; int interval; } msg_block_t; static msg_block_t global_msgs; typedef struct phase_times_s { time_t start; time_t end; time_t duration; uint64_t item_counts[4]; } phase_times_t; static phase_times_t phase_times[8]; static void *progress_rpt_thread(void *); static int current_phase; static int running; static uint64_t prog_rpt_total; void init_progress_rpt (void) { /* * allocate the done vector */ if ((prog_rpt_done = (uint64_t *) malloc(sizeof(uint64_t)*glob_agcount)) == NULL) { do_error(_("cannot malloc pointer to done vector\n")); } bzero(prog_rpt_done, sizeof(uint64_t)*glob_agcount); /* * Setup comm block, start the thread */ pthread_mutex_init(&global_msgs.mutex, NULL); global_msgs.format = NULL; global_msgs.count = glob_agcount; global_msgs.interval = report_interval; global_msgs.done = prog_rpt_done; global_msgs.total = &prog_rpt_total; if (pthread_create (&report_thread, NULL, progress_rpt_thread, (void *)&global_msgs)) do_error(_("unable to create progress report thread\n")); return; } void stop_progress_rpt(void) { /* * Tell msg thread to shutdown, * wait for all threads to finished */ running = 0; pthread_kill (report_thread, SIGHUP); pthread_join (report_thread, NULL); free(prog_rpt_done); return; } static void * progress_rpt_thread (void *p) { int i; int caught; sigset_t sigs_to_catch; struct tm *tmp; time_t now, elapsed; timer_t timerid; struct itimerspec timespec; char *msgbuf; uint64_t *donep; uint64_t sum; msg_block_t *msgp = (msg_block_t *)p; uint64_t percent; /* It's possible to get here very early w/ no progress msg set */ if (!msgp->format) return NULL; if ((msgbuf = (char *)malloc(DURATION_BUF_SIZE)) == NULL) do_error (_("progress_rpt: cannot malloc progress msg buffer\n")); running = 1; /* * Specify a repeating timer that fires each MSG_INTERVAL seconds. */ memset(×pec, 0, sizeof(timespec)); timespec.it_value.tv_sec = msgp->interval; timespec.it_interval.tv_sec = msgp->interval; if (timer_create (CLOCK_REALTIME, NULL, &timerid)) do_error(_("progress_rpt: cannot create timer\n")); if (timer_settime (timerid, 0, ×pec, NULL)) do_error(_("progress_rpt: cannot set timer\n")); /* * Main loop - output messages based on periodic signal arrival * set this thread's signal mask to block out all other signals */ sigemptyset (&sigs_to_catch); sigaddset (&sigs_to_catch, SIGALRM); sigaddset (&sigs_to_catch, SIGHUP); sigwait (&sigs_to_catch, &caught); while (caught != SIGHUP) { /* * Allow the mainline to hold off messages by holding * the lock. We don't want to just skip a period in case the * reporting interval is very long... people get nervous. But, * if the interval is very short, we can't let the timer go * off again without sigwait'ing for it. So disarm the timer * while we try to get the lock and giveup the cpu... the * mainline shouldn't take that long. */ if (pthread_mutex_lock(&msgp->mutex)) { do_error(_("progress_rpt: cannot lock progress mutex\n")); } if (!running) break; now = time (NULL); tmp = localtime ((const time_t *) &now); /* * Sum the work */ sum = 0; donep = msgp->done; for (i = 0; i < msgp->count; i++) { sum += *donep++; } percent = 0; switch(msgp->format->format) { case FMT1: if (*msgp->total) percent = (sum * 100) / ( *msgp->total ); sprintf (msgbuf, *msgp->format->fmt, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, msgp->format->msg, sum, *msgp->total, *msgp->format->type); break; case FMT2: sprintf (msgbuf, *msgp->format->fmt, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, msgp->format->msg, sum, *msgp->format->type); break; } do_log(_("%s"), msgbuf); elapsed = now - phase_times[current_phase].start; if ((msgp->format->format == FMT1) && sum && elapsed && ((current_phase == 3) || (current_phase == 4) || (current_phase == 7))) { /* for inode phase report % complete */ do_log( _("\t- %02d:%02d:%02d: Phase %d: elapsed time %s - processed %d %s per minute\n"), tmp->tm_hour, tmp->tm_min, tmp->tm_sec, current_phase, duration(elapsed, msgbuf), (int) (60*sum/(elapsed)), *msgp->format->type); do_log( _("\t- %02d:%02d:%02d: Phase %d: %" PRIu64 "%% done - estimated remaining time %s\n"), tmp->tm_hour, tmp->tm_min, tmp->tm_sec, current_phase, percent, duration((int) ((*msgp->total - sum) * (elapsed)/sum), msgbuf)); } if (pthread_mutex_unlock(&msgp->mutex) != 0) { do_error( _("progress_rpt: error unlock msg mutex\n")); } sigwait (&sigs_to_catch, &caught); } if (timer_delete (timerid)) do_warn(_("cannot delete timer\n")); free (msgbuf); return (NULL); } int set_progress_msg(int report, uint64_t total) { if (!ag_stride) return (0); if (pthread_mutex_lock(&global_msgs.mutex)) do_error(_("set_progress_msg: cannot lock progress mutex\n")); prog_rpt_total = total; global_msgs.format = &progress_rpt_reports[report]; /* reset all the accumulative totals */ if (prog_rpt_done) bzero(prog_rpt_done, sizeof(uint64_t)*glob_agcount); if (pthread_mutex_unlock(&global_msgs.mutex)) do_error(_("set_progress_msg: cannot unlock progress mutex\n")); return (0); } uint64_t print_final_rpt(void) { int i; struct tm *tmp; time_t now; uint64_t *donep; uint64_t sum; msg_block_t *msgp = &global_msgs; char msgbuf[DURATION_BUF_SIZE]; if (!ag_stride) return 0; if (pthread_mutex_lock(&global_msgs.mutex)) do_error(_("print_final_rpt: cannot lock progress mutex\n")); bzero(&msgbuf, sizeof(msgbuf)); now = time (NULL); tmp = localtime ((const time_t *) &now); /* * Sum the work */ sum = 0; donep = msgp->done; for (i = 0; i < msgp->count; i++) { sum += *donep++; } if (report_interval) { switch(msgp->format->format) { case FMT1: sprintf (msgbuf, _(*msgp->format->fmt), tmp->tm_hour, tmp->tm_min, tmp->tm_sec, _(msgp->format->msg), sum, *msgp->total, _(*msgp->format->type)); break; case FMT2: sprintf (msgbuf, _(*msgp->format->fmt), tmp->tm_hour, tmp->tm_min, tmp->tm_sec, _(msgp->format->msg), sum, _(*msgp->format->type)); break; } do_log(_("%s"), msgbuf); } if (pthread_mutex_unlock(&global_msgs.mutex)) do_error(_("print_final_rpt: cannot unlock progress mutex\n")); return(sum); } static void timediff(int phase) { phase_times[phase].duration = phase_times[phase].end - phase_times[phase].start; } /* ** Get the time and save in the phase time ** array. */ char * timestamp(int end, int phase, char *buf) { time_t now; struct tm *tmp; if (verbose > 1) cache_report(stderr, "libxfs_bcache", libxfs_bcache); now = time(NULL); if (end) { phase_times[phase].end = now; timediff(phase); /* total time in slot zero */ phase_times[0].end = now; timediff(0); if (phase < 7) { phase_times[phase+1].start = now; current_phase = phase + 1; } } else { phase_times[phase].start = now; current_phase = phase; } if (buf) { tmp = localtime((const time_t *)&now); sprintf(buf, _("%02d:%02d:%02d"), tmp->tm_hour, tmp->tm_min, tmp->tm_sec); } return(buf); } char * duration(int length, char *buf) { int sum; int weeks; int days; int hours; int minutes; int seconds; char temp[128]; *buf = '\0'; weeks = days = hours = minutes = seconds = sum = 0; if (length >= ONEWEEK) { weeks = length / ONEWEEK; sum = (weeks * ONEWEEK); if (weeks) { sprintf(buf, _("%d week"), weeks); if (weeks > 1) strcat(buf, _("s")); if ((length-sum) == 0) return(buf); } } if (length >= ONEDAY) { days = (length - sum) / ONEDAY; sum += (days * ONEDAY); if (days) { sprintf(temp, _("%d day"), days); if (days > 1) strcat(temp, _("s")); if (((length-sum) == 0) && (!weeks)) { strcpy(buf, temp); return(buf); } else if (weeks) { strcat(buf, _(", ")); } strcat(buf, temp); } } if (length >= ONEHOUR) { hours = (length - sum) / ONEHOUR; sum += (hours * ONEHOUR); if (hours) { sprintf(temp, _("%d hour"), hours); if (hours > 1) strcat(temp, _("s")); if (((length-sum) == 0) && (!weeks) && (!days)) { strcpy(buf, temp); return(buf); } else if ((weeks) || (days)) { strcat(buf, _(", ")); } strcat(buf, temp); } } if (length >= ONEMINUTE) { minutes = (length - sum) / ONEMINUTE; sum += (minutes * ONEMINUTE); if (minutes) { sprintf(temp, _("%d minute"), minutes); if (minutes > 1) strcat(temp, _("s")); if (((length-sum) == 0) && (!weeks) && (!days) && (!hours)) { strcpy(buf, temp); return(buf); } else if ((weeks)||(days)||(hours)) { strcat(buf, _(", ")); } strcat(buf, temp); } } seconds = length - sum; if (seconds) { sprintf(temp, _("%d second"), seconds); if (seconds > 1) strcat(temp, _("s")); if ((weeks)||(days)||(hours)||(minutes)) strcat(buf, _(", ")); strcat(buf, temp); } return(buf); } void summary_report(void) { int i; time_t now; struct tm end; struct tm start; char msgbuf[DURATION_BUF_SIZE]; now = time(NULL); do_log(_("\n XFS_REPAIR Summary %s\n"), ctime((const time_t *)&now)); do_log(_("Phase\t\tStart\t\tEnd\t\tDuration\n")); for (i = 1; i < 8; i++) { localtime_r((const time_t *)&phase_times[i].start, &start); localtime_r((const time_t *)&phase_times[i].end, &end); if ((no_modify) && (i == 5)) { do_log(_("Phase %d:\tSkipped\n"), i); } else if ((bad_ino_btree) && ((i == 6) || (i == 7))) { do_log(_("Phase %d:\tSkipped\n"), i); } else { do_log( _("Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n"), i, start.tm_mon+1, start.tm_mday, start.tm_hour, start.tm_min, start.tm_sec, end.tm_mon+1, end.tm_mday, end.tm_hour, end.tm_min, end.tm_sec, duration(phase_times[i].duration, msgbuf)); } } do_log(_("\nTotal run time: %s\n"), duration(phase_times[0].duration, msgbuf)); } xfsprogs-5.3.0/repair/progress.h0000644000175000017500000000235213435336037016554 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #ifndef _XFS_REPAIR_PROGRESS_RPT_H_ #define _XFS_REPAIR_PROGRESS_RPT_H_ #define PROG_RPT_DEFAULT (15*60) /* default 15 minute report interval */ #define PHASE_START 0 #define PHASE_END 1 #define PROG_FMT_SCAN_AG 0 /* Phase 2 */ #define PROG_FMT_AGI_UNLINKED 1 /* Phase 3 */ #define PROG_FMT_UNCERTAIN 2 #define PROG_FMT_PROCESS_INO 3 #define PROG_FMT_NEW_INODES 4 #define PROG_FMT_DUP_EXTENT 5 /* Phase 4 */ #define PROG_FMT_INIT_RTEXT 6 #define PROG_FMT_RESET_RTBM 7 #define PROG_FMT_DUP_BLOCKS 8 #define PROG_FMT_REBUILD_AG 9 /* Phase 5 */ #define PROG_FMT_TRAVERSAL 10 /* Phase 6 */ #define PROG_FMT_TRAVERSSUB 11 #define PROG_FMT_DISCONINODE 12 #define PROGRESS_FMT_CORR_LINK 13 /* Phase 7 */ #define PROGRESS_FMT_VRFY_LINK 14 #define DURATION_BUF_SIZE 512 extern void init_progress_rpt(void); extern void stop_progress_rpt(void); extern void summary_report(void); extern int set_progress_msg(int report, uint64_t total); extern uint64_t print_final_rpt(void); extern char *timestamp(int end, int phase, char *buf); extern char *duration(int val, char *buf); extern int do_parallel; #define PROG_RPT_INC(a,b) if (ag_stride && prog_rpt_done) (a) += (b) #endif /* _XFS_REPAIR_PROGRESS_RPT_H_ */ xfsprogs-5.3.0/repair/protos.h0000644000175000017500000000210513435336037016232 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ void xfs_init(libxfs_init_t *args); int verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb); int verify_set_primary_sb(xfs_sb_t *root_sb, int sb_index, int *sb_modified); int get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno); void write_primary_sb(xfs_sb_t *sbp, int size); int find_secondary_sb(xfs_sb_t *sb); struct fs_geometry; void get_sb_geometry(struct fs_geometry *geo, xfs_sb_t *sbp); char *alloc_ag_buf(int size); void print_inode_list(xfs_agnumber_t i); char *err_string(int err_code); void thread_init(void); void phase1(struct xfs_mount *); void phase2(struct xfs_mount *, int); void phase3(struct xfs_mount *, int); void phase4(struct xfs_mount *); void phase5(struct xfs_mount *); void phase6(struct xfs_mount *); void phase7(struct xfs_mount *, int); int verify_set_agheader(struct xfs_mount *, struct xfs_buf *, struct xfs_sb *, struct xfs_agf *, struct xfs_agi *, xfs_agnumber_t); xfsprogs-5.3.0/repair/rmap.c0000644000175000017500000011521213570057155015643 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include "btree.h" #include "err_protos.h" #include "libxlog.h" #include "incore.h" #include "globals.h" #include "dinode.h" #include "slab.h" #include "rmap.h" #include "libfrog/bitmap.h" #undef RMAP_DEBUG #ifdef RMAP_DEBUG # define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) #else # define dbg_printf(f, a...) #endif /* per-AG rmap object anchor */ struct xfs_ag_rmap { struct xfs_slab *ar_rmaps; /* rmap observations, p4 */ struct xfs_slab *ar_raw_rmaps; /* unmerged rmaps */ int ar_flcount; /* agfl entries from leftover */ /* agbt allocations */ struct xfs_rmap_irec ar_last_rmap; /* last rmap seen */ struct xfs_slab *ar_refcount_items; /* refcount items, p4-5 */ }; static struct xfs_ag_rmap *ag_rmaps; static bool rmapbt_suspect; static bool refcbt_suspect; static inline int rmap_compare(const void *a, const void *b) { return libxfs_rmap_compare(a, b); } /* * Returns true if we must reconstruct either the reference count or reverse * mapping trees. */ bool rmap_needs_work( struct xfs_mount *mp) { return xfs_sb_version_hasreflink(&mp->m_sb) || xfs_sb_version_hasrmapbt(&mp->m_sb); } /* * Initialize per-AG reverse map data. */ void rmaps_init( struct xfs_mount *mp) { xfs_agnumber_t i; int error; if (!rmap_needs_work(mp)) return; ag_rmaps = calloc(mp->m_sb.sb_agcount, sizeof(struct xfs_ag_rmap)); if (!ag_rmaps) do_error(_("couldn't allocate per-AG reverse map roots\n")); for (i = 0; i < mp->m_sb.sb_agcount; i++) { error = init_slab(&ag_rmaps[i].ar_rmaps, sizeof(struct xfs_rmap_irec)); if (error) do_error( _("Insufficient memory while allocating reverse mapping slabs.")); error = init_slab(&ag_rmaps[i].ar_raw_rmaps, sizeof(struct xfs_rmap_irec)); if (error) do_error( _("Insufficient memory while allocating raw metadata reverse mapping slabs.")); ag_rmaps[i].ar_last_rmap.rm_owner = XFS_RMAP_OWN_UNKNOWN; error = init_slab(&ag_rmaps[i].ar_refcount_items, sizeof(struct xfs_refcount_irec)); if (error) do_error( _("Insufficient memory while allocating refcount item slabs.")); } } /* * Free the per-AG reverse-mapping data. */ void rmaps_free( struct xfs_mount *mp) { xfs_agnumber_t i; if (!rmap_needs_work(mp)) return; for (i = 0; i < mp->m_sb.sb_agcount; i++) { free_slab(&ag_rmaps[i].ar_rmaps); free_slab(&ag_rmaps[i].ar_raw_rmaps); free_slab(&ag_rmaps[i].ar_refcount_items); } free(ag_rmaps); ag_rmaps = NULL; } /* * Decide if two reverse-mapping records can be merged. */ bool rmaps_are_mergeable( struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2) { if (r1->rm_owner != r2->rm_owner) return false; if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock) return false; if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount > XFS_RMAP_LEN_MAX) return false; if (XFS_RMAP_NON_INODE_OWNER(r2->rm_owner)) return true; /* must be an inode owner below here */ if (r1->rm_flags != r2->rm_flags) return false; if (r1->rm_flags & XFS_RMAP_BMBT_BLOCK) return true; return r1->rm_offset + r1->rm_blockcount == r2->rm_offset; } /* * Add an observation about a block mapping in an inode's data or attribute * fork for later btree reconstruction. */ int rmap_add_rec( struct xfs_mount *mp, xfs_ino_t ino, int whichfork, struct xfs_bmbt_irec *irec) { struct xfs_rmap_irec rmap; xfs_agnumber_t agno; xfs_agblock_t agbno; struct xfs_rmap_irec *last_rmap; int error = 0; if (!rmap_needs_work(mp)) return 0; agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock); agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock); ASSERT(agno != NULLAGNUMBER); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks); ASSERT(ino != NULLFSINO); ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK); rmap.rm_owner = ino; rmap.rm_offset = irec->br_startoff; rmap.rm_flags = 0; if (whichfork == XFS_ATTR_FORK) rmap.rm_flags |= XFS_RMAP_ATTR_FORK; rmap.rm_startblock = agbno; rmap.rm_blockcount = irec->br_blockcount; if (irec->br_state == XFS_EXT_UNWRITTEN) rmap.rm_flags |= XFS_RMAP_UNWRITTEN; last_rmap = &ag_rmaps[agno].ar_last_rmap; if (last_rmap->rm_owner == XFS_RMAP_OWN_UNKNOWN) *last_rmap = rmap; else if (rmaps_are_mergeable(last_rmap, &rmap)) last_rmap->rm_blockcount += rmap.rm_blockcount; else { error = slab_add(ag_rmaps[agno].ar_rmaps, last_rmap); if (error) return error; *last_rmap = rmap; } return error; } /* Finish collecting inode data/attr fork rmaps. */ int rmap_finish_collecting_fork_recs( struct xfs_mount *mp, xfs_agnumber_t agno) { if (!rmap_needs_work(mp) || ag_rmaps[agno].ar_last_rmap.rm_owner == XFS_RMAP_OWN_UNKNOWN) return 0; return slab_add(ag_rmaps[agno].ar_rmaps, &ag_rmaps[agno].ar_last_rmap); } /* add a raw rmap; these will be merged later */ static int __rmap_add_raw_rec( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner, bool is_attr, bool is_bmbt) { struct xfs_rmap_irec rmap; ASSERT(len != 0); rmap.rm_owner = owner; rmap.rm_offset = 0; rmap.rm_flags = 0; if (is_attr) rmap.rm_flags |= XFS_RMAP_ATTR_FORK; if (is_bmbt) rmap.rm_flags |= XFS_RMAP_BMBT_BLOCK; rmap.rm_startblock = agbno; rmap.rm_blockcount = len; return slab_add(ag_rmaps[agno].ar_raw_rmaps, &rmap); } /* * Add a reverse mapping for an inode fork's block mapping btree block. */ int rmap_add_bmbt_rec( struct xfs_mount *mp, xfs_ino_t ino, int whichfork, xfs_fsblock_t fsbno) { xfs_agnumber_t agno; xfs_agblock_t agbno; if (!rmap_needs_work(mp)) return 0; agno = XFS_FSB_TO_AGNO(mp, fsbno); agbno = XFS_FSB_TO_AGBNO(mp, fsbno); ASSERT(agno != NULLAGNUMBER); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno + 1 <= mp->m_sb.sb_agblocks); return __rmap_add_raw_rec(mp, agno, agbno, 1, ino, whichfork == XFS_ATTR_FORK, true); } /* * Add a reverse mapping for a per-AG fixed metadata extent. */ int rmap_add_ag_rec( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner) { if (!rmap_needs_work(mp)) return 0; ASSERT(agno != NULLAGNUMBER); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno + len <= mp->m_sb.sb_agblocks); return __rmap_add_raw_rec(mp, agno, agbno, len, owner, false, false); } /* * Merge adjacent raw rmaps and add them to the main rmap list. */ int rmap_fold_raw_recs( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_slab_cursor *cur = NULL; struct xfs_rmap_irec *prev, *rec; size_t old_sz; int error = 0; old_sz = slab_count(ag_rmaps[agno].ar_rmaps); if (slab_count(ag_rmaps[agno].ar_raw_rmaps) == 0) goto no_raw; qsort_slab(ag_rmaps[agno].ar_raw_rmaps, rmap_compare); error = init_slab_cursor(ag_rmaps[agno].ar_raw_rmaps, rmap_compare, &cur); if (error) goto err; prev = pop_slab_cursor(cur); rec = pop_slab_cursor(cur); while (prev && rec) { if (rmaps_are_mergeable(prev, rec)) { prev->rm_blockcount += rec->rm_blockcount; rec = pop_slab_cursor(cur); continue; } error = slab_add(ag_rmaps[agno].ar_rmaps, prev); if (error) goto err; prev = rec; rec = pop_slab_cursor(cur); } if (prev) { error = slab_add(ag_rmaps[agno].ar_rmaps, prev); if (error) goto err; } free_slab(&ag_rmaps[agno].ar_raw_rmaps); error = init_slab(&ag_rmaps[agno].ar_raw_rmaps, sizeof(struct xfs_rmap_irec)); if (error) do_error( _("Insufficient memory while allocating raw metadata reverse mapping slabs.")); no_raw: if (old_sz) qsort_slab(ag_rmaps[agno].ar_rmaps, rmap_compare); err: free_slab_cursor(&cur); return error; } static int find_first_zero_bit( uint64_t mask) { int n; int b = 0; for (n = 0; n < sizeof(mask) * NBBY && (mask & 1); n++, mask >>= 1) b++; return b; } static int popcnt( uint64_t mask) { int n; int b = 0; if (mask == 0) return 0; for (n = 0; n < sizeof(mask) * NBBY; n++, mask >>= 1) if (mask & 1) b++; return b; } /* * Add an allocation group's fixed metadata to the rmap list. This includes * sb/agi/agf/agfl headers, inode chunks, and the log. */ int rmap_add_fixed_ag_rec( struct xfs_mount *mp, xfs_agnumber_t agno) { xfs_fsblock_t fsbno; xfs_agblock_t agbno; ino_tree_node_t *ino_rec; xfs_agino_t agino; int error; int startidx; int nr; if (!rmap_needs_work(mp)) return 0; /* sb/agi/agf/agfl headers */ error = rmap_add_ag_rec(mp, agno, 0, XFS_BNO_BLOCK(mp), XFS_RMAP_OWN_FS); if (error) goto out; /* inodes */ ino_rec = findfirst_inode_rec(agno); for (; ino_rec != NULL; ino_rec = next_ino_rec(ino_rec)) { if (xfs_sb_version_hassparseinodes(&mp->m_sb)) { startidx = find_first_zero_bit(ino_rec->ir_sparse); nr = XFS_INODES_PER_CHUNK - popcnt(ino_rec->ir_sparse); } else { startidx = 0; nr = XFS_INODES_PER_CHUNK; } nr /= mp->m_sb.sb_inopblock; if (nr == 0) nr = 1; agino = ino_rec->ino_startnum + startidx; agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (XFS_AGINO_TO_OFFSET(mp, agino) == 0) { error = rmap_add_ag_rec(mp, agno, agbno, nr, XFS_RMAP_OWN_INODES); if (error) goto out; } } /* log */ fsbno = mp->m_sb.sb_logstart; if (fsbno && XFS_FSB_TO_AGNO(mp, fsbno) == agno) { agbno = XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart); error = rmap_add_ag_rec(mp, agno, agbno, mp->m_sb.sb_logblocks, XFS_RMAP_OWN_LOG); if (error) goto out; } out: return error; } /* * Copy the per-AG btree reverse-mapping data into the rmapbt. * * At rmapbt reconstruction time, the rmapbt will be populated _only_ with * rmaps for file extents, inode chunks, AG headers, and bmbt blocks. While * building the AG btrees we can record all the blocks allocated for each * btree, but we cannot resolve the conflict between the fact that one has to * finish allocating the space for the rmapbt before building the bnobt and the * fact that allocating blocks for the bnobt requires adding rmapbt entries. * Therefore we record in-core the rmaps for each btree and here use the * libxfs rmap functions to finish building the rmap btree. * * During AGF/AGFL reconstruction in phase 5, rmaps for the AG btrees are * recorded in memory. The rmapbt has not been set up yet, so we need to be * able to "expand" the AGFL without updating the rmapbt. After we've written * out the new AGF header the new rmapbt is available, so this function reads * each AGFL to generate rmap entries. These entries are merged with the AG * btree rmap entries, and then we use libxfs' rmap functions to add them to * the rmapbt, after which it is fully regenerated. */ int rmap_store_ag_btree_rec( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_slab_cursor *rm_cur; struct xfs_rmap_irec *rm_rec = NULL; struct xfs_buf *agbp = NULL; struct xfs_buf *agflbp = NULL; struct xfs_trans *tp; __be32 *agfl_bno, *b; struct xfs_ag_rmap *ag_rmap = &ag_rmaps[agno]; struct bitmap *own_ag_bitmap = NULL; int error = 0; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 0; /* Release the ar_rmaps; they were put into the rmapbt during p5. */ free_slab(&ag_rmap->ar_rmaps); error = init_slab(&ag_rmap->ar_rmaps, sizeof(struct xfs_rmap_irec)); if (error) goto err; /* Add the AGFL blocks to the rmap list */ error = -libxfs_trans_read_buf( mp, NULL, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &agflbp, &xfs_agfl_buf_ops); if (error) goto err; /* * Sometimes, the blocks at the beginning of the AGFL are there * because we overestimated how many blocks we needed to rebuild * the freespace btrees. ar_flcount records the number of * blocks in this situation. Since those blocks already have an * rmap, we only need to add rmap records for AGFL blocks past * that point in the AGFL because those blocks are a result of a * no-rmap no-shrink freelist fixup that we did earlier. * * However, some blocks end up on the AGFL because the free space * btrees shed blocks as a result of allocating space to fix the * freelist. We already created in-core rmap records for the free * space btree blocks, so we must be careful not to create those * records again. Create a bitmap of already-recorded OWN_AG rmaps. */ error = init_slab_cursor(ag_rmap->ar_raw_rmaps, rmap_compare, &rm_cur); if (error) goto err; error = -bitmap_alloc(&own_ag_bitmap); if (error) goto err_slab; while ((rm_rec = pop_slab_cursor(rm_cur)) != NULL) { if (rm_rec->rm_owner != XFS_RMAP_OWN_AG) continue; error = -bitmap_set(own_ag_bitmap, rm_rec->rm_startblock, rm_rec->rm_blockcount); if (error) { /* * If this range is already set, then the incore rmap * records for the AG free space btrees overlap and * we're toast because that is not allowed. */ if (error == EEXIST) error = EFSCORRUPTED; goto err_slab; } } free_slab_cursor(&rm_cur); /* Create rmaps for any AGFL blocks that aren't already rmapped. */ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); b = agfl_bno + ag_rmap->ar_flcount; while (*b != cpu_to_be32(NULLAGBLOCK) && b - agfl_bno < libxfs_agfl_size(mp)) { xfs_agblock_t agbno; agbno = be32_to_cpu(*b); if (!bitmap_test(own_ag_bitmap, agbno, 1)) { error = rmap_add_ag_rec(mp, agno, agbno, 1, XFS_RMAP_OWN_AG); if (error) goto err; } b++; } libxfs_putbuf(agflbp); agflbp = NULL; bitmap_free(&own_ag_bitmap); /* Merge all the raw rmaps into the main list */ error = rmap_fold_raw_recs(mp, agno); if (error) goto err; /* Create cursors to refcount structures */ error = init_slab_cursor(ag_rmap->ar_rmaps, rmap_compare, &rm_cur); if (error) goto err; /* Insert rmaps into the btree one at a time */ rm_rec = pop_slab_cursor(rm_cur); while (rm_rec) { struct xfs_owner_info oinfo = {}; error = -libxfs_trans_alloc_rollable(mp, 16, &tp); if (error) goto err_slab; error = -libxfs_alloc_read_agf(mp, tp, agno, 0, &agbp); if (error) goto err_trans; ASSERT(XFS_RMAP_NON_INODE_OWNER(rm_rec->rm_owner)); oinfo.oi_owner = rm_rec->rm_owner; error = -libxfs_rmap_alloc(tp, agbp, agno, rm_rec->rm_startblock, rm_rec->rm_blockcount, &oinfo); if (error) goto err_trans; error = -libxfs_trans_commit(tp); if (error) goto err_slab; fix_freelist(mp, agno, false); rm_rec = pop_slab_cursor(rm_cur); } free_slab_cursor(&rm_cur); return 0; err_trans: libxfs_trans_cancel(tp); err_slab: free_slab_cursor(&rm_cur); err: if (agflbp) libxfs_putbuf(agflbp); if (own_ag_bitmap) bitmap_free(&own_ag_bitmap); return error; } #ifdef RMAP_DEBUG static void rmap_dump( const char *msg, xfs_agnumber_t agno, struct xfs_rmap_irec *rmap) { printf("%s: %p agno=%u pblk=%llu own=%lld lblk=%llu len=%u flags=0x%x\n", msg, rmap, (unsigned int)agno, (unsigned long long)rmap->rm_startblock, (unsigned long long)rmap->rm_owner, (unsigned long long)rmap->rm_offset, (unsigned int)rmap->rm_blockcount, (unsigned int)rmap->rm_flags); } #else # define rmap_dump(m, a, r) #endif /* * Rebuilding the Reference Count & Reverse Mapping Btrees * * The reference count (refcnt) and reverse mapping (rmap) btrees are * rebuilt during phase 5, like all other AG btrees. Therefore, reverse * mappings must be processed into reference counts at the end of phase * 4, and the rmaps must be recorded during phase 4. There is a need to * access the rmaps in physical block order, but no particular need for * random access, so the slab.c code provides a big logical array * (consisting of smaller slabs) and some inorder iterator functions. * * Once we've recorded all the reverse mappings, we're ready to * translate the rmaps into refcount entries. Imagine the rmap entries * as rectangles representing extents of physical blocks, and that the * rectangles can be laid down to allow them to overlap each other; then * we know that we must emit a refcnt btree entry wherever the amount of * overlap changes, i.e. the emission stimulus is level-triggered: * * - --- * -- ----- ---- --- ------ * -- ---- ----------- ---- --------- * -------------------------------- ----------- * ^ ^ ^^ ^^ ^ ^^ ^^^ ^^^^ ^ ^^ ^ ^ ^ * 2 1 23 21 3 43 234 2123 1 01 2 3 0 * * For our purposes, a rmap is a tuple (startblock, len, fileoff, owner). * * Note that in the actual refcnt btree we don't store the refcount < 2 * cases because the bnobt tells us which blocks are free; single-use * blocks aren't recorded in the bnobt or the refcntbt. If the rmapbt * supports storing multiple entries covering a given block we could * theoretically dispense with the refcntbt and simply count rmaps, but * that's inefficient in the (hot) write path, so we'll take the cost of * the extra tree to save time. Also there's no guarantee that rmap * will be enabled. * * Given an array of rmaps sorted by physical block number, a starting * physical block (sp), a bag to hold rmaps that cover sp, and the next * physical block where the level changes (np), we can reconstruct the * refcount btree as follows: * * While there are still unprocessed rmaps in the array, * - Set sp to the physical block (pblk) of the next unprocessed rmap. * - Add to the bag all rmaps in the array where startblock == sp. * - Set np to the physical block where the bag size will change. This * is the minimum of (the pblk of the next unprocessed rmap) and * (startblock + len of each rmap in the bag). * - Record the bag size as old_bag_size. * * - While the bag isn't empty, * - Remove from the bag all rmaps where startblock + len == np. * - Add to the bag all rmaps in the array where startblock == np. * - If the bag size isn't old_bag_size, store the refcount entry * (sp, np - sp, bag_size) in the refcnt btree. * - If the bag is empty, break out of the inner loop. * - Set old_bag_size to the bag size * - Set sp = np. * - Set np to the physical block where the bag size will change. * This is the minimum of (the pblk of the next unprocessed rmap) * and (startblock + len of each rmap in the bag). * * An implementation detail is that because this processing happens * during phase 4, the refcount entries are stored in an array so that * phase 5 can load them into the refcount btree. The rmaps can be * loaded directly into the rmap btree during phase 5 as well. */ /* * Mark all inodes in the reverse-mapping observation stack as requiring the * reflink inode flag, if the stack depth is greater than 1. */ static void mark_inode_rl( struct xfs_mount *mp, struct xfs_bag *rmaps) { xfs_agnumber_t iagno; struct xfs_rmap_irec *rmap; struct ino_tree_node *irec; int off; size_t idx; xfs_agino_t ino; if (bag_count(rmaps) < 2) return; /* Reflink flag accounting */ foreach_bag_ptr(rmaps, idx, rmap) { ASSERT(!XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner)); iagno = XFS_INO_TO_AGNO(mp, rmap->rm_owner); ino = XFS_INO_TO_AGINO(mp, rmap->rm_owner); pthread_mutex_lock(&ag_locks[iagno].lock); irec = find_inode_rec(mp, iagno, ino); off = get_inode_offset(mp, rmap->rm_owner, irec); /* lock here because we might go outside this ag */ set_inode_is_rl(irec, off); pthread_mutex_unlock(&ag_locks[iagno].lock); } } /* * Emit a refcount object for refcntbt reconstruction during phase 5. */ #define REFCOUNT_CLAMP(nr) ((nr) > MAXREFCOUNT ? MAXREFCOUNT : (nr)) static void refcount_emit( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, size_t nr_rmaps) { struct xfs_refcount_irec rlrec; int error; struct xfs_slab *rlslab; rlslab = ag_rmaps[agno].ar_refcount_items; ASSERT(nr_rmaps > 0); dbg_printf("REFL: agno=%u pblk=%u, len=%u -> refcount=%zu\n", agno, agbno, len, nr_rmaps); rlrec.rc_startblock = agbno; rlrec.rc_blockcount = len; rlrec.rc_refcount = REFCOUNT_CLAMP(nr_rmaps); error = slab_add(rlslab, &rlrec); if (error) do_error( _("Insufficient memory while recreating refcount tree.")); } #undef REFCOUNT_CLAMP /* * Transform a pile of physical block mapping observations into refcount data * for eventual rebuilding of the btrees. */ #define RMAP_END(r) ((r)->rm_startblock + (r)->rm_blockcount) int compute_refcounts( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_bag *stack_top = NULL; struct xfs_slab *rmaps; struct xfs_slab_cursor *rmaps_cur; struct xfs_rmap_irec *array_cur; struct xfs_rmap_irec *rmap; xfs_agblock_t sbno; /* first bno of this rmap set */ xfs_agblock_t cbno; /* first bno of this refcount set */ xfs_agblock_t nbno; /* next bno where rmap set changes */ size_t n, idx; size_t old_stack_nr; int error; if (!xfs_sb_version_hasreflink(&mp->m_sb)) return 0; rmaps = ag_rmaps[agno].ar_rmaps; error = init_slab_cursor(rmaps, rmap_compare, &rmaps_cur); if (error) return error; error = init_bag(&stack_top); if (error) goto err; /* While there are rmaps to be processed... */ n = 0; while (n < slab_count(rmaps)) { array_cur = peek_slab_cursor(rmaps_cur); sbno = cbno = array_cur->rm_startblock; /* Push all rmaps with pblk == sbno onto the stack */ for (; array_cur && array_cur->rm_startblock == sbno; array_cur = peek_slab_cursor(rmaps_cur)) { advance_slab_cursor(rmaps_cur); n++; rmap_dump("push0", agno, array_cur); error = bag_add(stack_top, array_cur); if (error) goto err; } mark_inode_rl(mp, stack_top); /* Set nbno to the bno of the next refcount change */ if (n < slab_count(rmaps) && array_cur) nbno = array_cur->rm_startblock; else nbno = NULLAGBLOCK; foreach_bag_ptr(stack_top, idx, rmap) { nbno = min(nbno, RMAP_END(rmap)); } /* Emit reverse mappings, if needed */ ASSERT(nbno > sbno); old_stack_nr = bag_count(stack_top); /* While stack isn't empty... */ while (bag_count(stack_top)) { /* Pop all rmaps that end at nbno */ foreach_bag_ptr_reverse(stack_top, idx, rmap) { if (RMAP_END(rmap) != nbno) continue; rmap_dump("pop", agno, rmap); error = bag_remove(stack_top, idx); if (error) goto err; } /* Push array items that start at nbno */ for (; array_cur && array_cur->rm_startblock == nbno; array_cur = peek_slab_cursor(rmaps_cur)) { advance_slab_cursor(rmaps_cur); n++; rmap_dump("push1", agno, array_cur); error = bag_add(stack_top, array_cur); if (error) goto err; } mark_inode_rl(mp, stack_top); /* Emit refcount if necessary */ ASSERT(nbno > cbno); if (bag_count(stack_top) != old_stack_nr) { if (old_stack_nr > 1) { refcount_emit(mp, agno, cbno, nbno - cbno, old_stack_nr); } cbno = nbno; } /* Stack empty, go find the next rmap */ if (bag_count(stack_top) == 0) break; old_stack_nr = bag_count(stack_top); sbno = nbno; /* Set nbno to the bno of the next refcount change */ if (n < slab_count(rmaps)) nbno = array_cur->rm_startblock; else nbno = NULLAGBLOCK; foreach_bag_ptr(stack_top, idx, rmap) { nbno = min(nbno, RMAP_END(rmap)); } /* Emit reverse mappings, if needed */ ASSERT(nbno > sbno); } } err: free_bag(&stack_top); free_slab_cursor(&rmaps_cur); return error; } #undef RMAP_END /* * Return the number of rmap objects for an AG. */ size_t rmap_record_count( struct xfs_mount *mp, xfs_agnumber_t agno) { return slab_count(ag_rmaps[agno].ar_rmaps); } /* * Return a slab cursor that will return rmap objects in order. */ int rmap_init_cursor( xfs_agnumber_t agno, struct xfs_slab_cursor **cur) { return init_slab_cursor(ag_rmaps[agno].ar_rmaps, rmap_compare, cur); } /* * Disable the refcount btree check. */ void rmap_avoid_check(void) { rmapbt_suspect = true; } /* Look for an rmap in the rmapbt that matches a given rmap. */ static int rmap_lookup( struct xfs_btree_cur *bt_cur, struct xfs_rmap_irec *rm_rec, struct xfs_rmap_irec *tmp, int *have) { int error; /* Use the regular btree retrieval routine. */ error = -libxfs_rmap_lookup_le(bt_cur, rm_rec->rm_startblock, rm_rec->rm_blockcount, rm_rec->rm_owner, rm_rec->rm_offset, rm_rec->rm_flags, have); if (error) return error; if (*have == 0) return error; return -libxfs_rmap_get_rec(bt_cur, tmp, have); } /* Look for an rmap in the rmapbt that matches a given rmap. */ static int rmap_lookup_overlapped( struct xfs_btree_cur *bt_cur, struct xfs_rmap_irec *rm_rec, struct xfs_rmap_irec *tmp, int *have) { /* Have to use our fancy version for overlapped */ return -libxfs_rmap_lookup_le_range(bt_cur, rm_rec->rm_startblock, rm_rec->rm_owner, rm_rec->rm_offset, rm_rec->rm_flags, tmp, have); } /* Does the btree rmap cover the observed rmap? */ #define NEXTP(x) ((x)->rm_startblock + (x)->rm_blockcount) #define NEXTL(x) ((x)->rm_offset + (x)->rm_blockcount) static bool rmap_is_good( struct xfs_rmap_irec *observed, struct xfs_rmap_irec *btree) { /* Can't have mismatches in the flags or the owner. */ if (btree->rm_flags != observed->rm_flags || btree->rm_owner != observed->rm_owner) return false; /* * Btree record can't physically start after the observed * record, nor can it end before the observed record. */ if (btree->rm_startblock > observed->rm_startblock || NEXTP(btree) < NEXTP(observed)) return false; /* If this is metadata or bmbt, we're done. */ if (XFS_RMAP_NON_INODE_OWNER(observed->rm_owner) || (observed->rm_flags & XFS_RMAP_BMBT_BLOCK)) return true; /* * Btree record can't logically start after the observed * record, nor can it end before the observed record. */ if (btree->rm_offset > observed->rm_offset || NEXTL(btree) < NEXTL(observed)) return false; return true; } #undef NEXTP #undef NEXTL /* * Compare the observed reverse mappings against what's in the ag btree. */ int rmaps_verify_btree( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_slab_cursor *rm_cur; struct xfs_btree_cur *bt_cur = NULL; int error; int have; struct xfs_buf *agbp = NULL; struct xfs_rmap_irec *rm_rec; struct xfs_rmap_irec tmp; struct xfs_perag *pag; /* per allocation group data */ if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 0; if (rmapbt_suspect) { if (no_modify && agno == 0) do_warn(_("would rebuild corrupt rmap btrees.\n")); return 0; } /* Create cursors to refcount structures */ error = rmap_init_cursor(agno, &rm_cur); if (error) return error; error = -libxfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); if (error) goto err; /* Leave the per-ag data "uninitialized" since we rewrite it later */ pag = libxfs_perag_get(mp, agno); pag->pagf_init = 0; libxfs_perag_put(pag); bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, agno); if (!bt_cur) { error = -ENOMEM; goto err; } rm_rec = pop_slab_cursor(rm_cur); while (rm_rec) { error = rmap_lookup(bt_cur, rm_rec, &tmp, &have); if (error) goto err; /* * Using the range query is expensive, so only do it if * the regular lookup doesn't find anything or if it doesn't * match the observed rmap. */ if (xfs_sb_version_hasreflink(&bt_cur->bc_mp->m_sb) && (!have || !rmap_is_good(rm_rec, &tmp))) { error = rmap_lookup_overlapped(bt_cur, rm_rec, &tmp, &have); if (error) goto err; } if (!have) { do_warn( _("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \ %s%soff %"PRIu64"\n"), agno, rm_rec->rm_startblock, (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN) ? _("unwritten ") : "", rm_rec->rm_blockcount, rm_rec->rm_owner, (rm_rec->rm_flags & XFS_RMAP_ATTR_FORK) ? _("attr ") : "", (rm_rec->rm_flags & XFS_RMAP_BMBT_BLOCK) ? _("bmbt ") : "", rm_rec->rm_offset); goto next_loop; } /* Compare each refcount observation against the btree's */ if (!rmap_is_good(rm_rec, &tmp)) { do_warn( _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \ %"PRIu64"; should be (%u/%u) %slen %u owner %"PRId64" %s%soff %"PRIu64"\n"), agno, tmp.rm_startblock, (tmp.rm_flags & XFS_RMAP_UNWRITTEN) ? _("unwritten ") : "", tmp.rm_blockcount, tmp.rm_owner, (tmp.rm_flags & XFS_RMAP_ATTR_FORK) ? _("attr ") : "", (tmp.rm_flags & XFS_RMAP_BMBT_BLOCK) ? _("bmbt ") : "", tmp.rm_offset, agno, rm_rec->rm_startblock, (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN) ? _("unwritten ") : "", rm_rec->rm_blockcount, rm_rec->rm_owner, (rm_rec->rm_flags & XFS_RMAP_ATTR_FORK) ? _("attr ") : "", (rm_rec->rm_flags & XFS_RMAP_BMBT_BLOCK) ? _("bmbt ") : "", rm_rec->rm_offset); goto next_loop; } next_loop: rm_rec = pop_slab_cursor(rm_cur); } err: if (bt_cur) libxfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR); if (agbp) libxfs_putbuf(agbp); free_slab_cursor(&rm_cur); return 0; } /* * Compare the key fields of two rmap records -- positive if key1 > key2, * negative if key1 < key2, and zero if equal. */ int64_t rmap_diffkeys( struct xfs_rmap_irec *kp1, struct xfs_rmap_irec *kp2) { __u64 oa; __u64 ob; int64_t d; struct xfs_rmap_irec tmp; tmp = *kp1; tmp.rm_flags &= ~XFS_RMAP_REC_FLAGS; oa = libxfs_rmap_irec_offset_pack(&tmp); tmp = *kp2; tmp.rm_flags &= ~XFS_RMAP_REC_FLAGS; ob = libxfs_rmap_irec_offset_pack(&tmp); d = (int64_t)kp1->rm_startblock - kp2->rm_startblock; if (d) return d; if (kp1->rm_owner > kp2->rm_owner) return 1; else if (kp2->rm_owner > kp1->rm_owner) return -1; if (oa > ob) return 1; else if (ob > oa) return -1; return 0; } /* Compute the high key of an rmap record. */ void rmap_high_key_from_rec( struct xfs_rmap_irec *rec, struct xfs_rmap_irec *key) { int adj; adj = rec->rm_blockcount - 1; key->rm_startblock = rec->rm_startblock + adj; key->rm_owner = rec->rm_owner; key->rm_offset = rec->rm_offset; key->rm_flags = rec->rm_flags & XFS_RMAP_KEY_FLAGS; if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)) return; key->rm_offset += adj; } /* * Record that an inode had the reflink flag set when repair started. The * inode reflink flag will be adjusted as necessary. */ void record_inode_reflink_flag( struct xfs_mount *mp, struct xfs_dinode *dino, xfs_agnumber_t agno, xfs_agino_t ino, xfs_ino_t lino) { struct ino_tree_node *irec; int off; ASSERT(XFS_AGINO_TO_INO(mp, agno, ino) == be64_to_cpu(dino->di_ino)); if (!(be64_to_cpu(dino->di_flags2) & XFS_DIFLAG2_REFLINK)) return; irec = find_inode_rec(mp, agno, ino); off = get_inode_offset(mp, lino, irec); ASSERT(!inode_was_rl(irec, off)); set_inode_was_rl(irec, off); dbg_printf("set was_rl lino=%llu was=0x%llx\n", (unsigned long long)lino, (unsigned long long)irec->ino_was_rl); } /* * Inform the user that we're clearing the reflink flag on an inode that * doesn't actually share any blocks. This is an optimization (the kernel * skips refcount checks for non-reflink files) and not a corruption repair, * so we don't need to log every time we clear a flag unless verbose mode is * enabled. */ static void warn_clearing_reflink( xfs_ino_t ino) { static bool warned = false; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; if (verbose) { do_warn(_("clearing reflink flag on inode %"PRIu64"\n"), ino); return; } if (warned) return; pthread_mutex_lock(&lock); if (!warned) { do_warn(_("clearing reflink flag on inodes when possible\n")); warned = true; } pthread_mutex_unlock(&lock); } /* * Fix an inode's reflink flag. */ static int fix_inode_reflink_flag( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino, bool set) { struct xfs_dinode *dino; struct xfs_buf *buf; if (set) do_warn( _("setting reflink flag on inode %"PRIu64"\n"), XFS_AGINO_TO_INO(mp, agno, agino)); else if (!no_modify) /* && !set */ warn_clearing_reflink(XFS_AGINO_TO_INO(mp, agno, agino)); if (no_modify) return 0; buf = get_agino_buf(mp, agno, agino, &dino); if (!buf) return 1; ASSERT(XFS_AGINO_TO_INO(mp, agno, agino) == be64_to_cpu(dino->di_ino)); if (set) dino->di_flags2 |= cpu_to_be64(XFS_DIFLAG2_REFLINK); else dino->di_flags2 &= cpu_to_be64(~XFS_DIFLAG2_REFLINK); libxfs_dinode_calc_crc(mp, dino); libxfs_writebuf(buf, 0); return 0; } /* * Fix discrepancies between the state of the inode reflink flag and our * observations as to whether or not the inode really needs it. */ int fix_inode_reflink_flags( struct xfs_mount *mp, xfs_agnumber_t agno) { struct ino_tree_node *irec; int bit; uint64_t was; uint64_t is; uint64_t diff; uint64_t mask; int error = 0; xfs_agino_t agino; /* * Update the reflink flag for any inode where there's a discrepancy * between the inode flag and whether or not we found any reflinked * extents. */ for (irec = findfirst_inode_rec(agno); irec != NULL; irec = next_ino_rec(irec)) { ASSERT((irec->ino_was_rl & irec->ir_free) == 0); ASSERT((irec->ino_is_rl & irec->ir_free) == 0); was = irec->ino_was_rl; is = irec->ino_is_rl; if (was == is) continue; diff = was ^ is; dbg_printf("mismatch ino=%llu was=0x%lx is=0x%lx dif=0x%lx\n", (unsigned long long)XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum), was, is, diff); for (bit = 0, mask = 1; bit < 64; bit++, mask <<= 1) { agino = bit + irec->ino_startnum; if (!(diff & mask)) continue; else if (was & mask) error = fix_inode_reflink_flag(mp, agno, agino, false); else if (is & mask) error = fix_inode_reflink_flag(mp, agno, agino, true); else ASSERT(0); if (error) do_error( _("Unable to fix reflink flag on inode %"PRIu64".\n"), XFS_AGINO_TO_INO(mp, agno, agino)); } } return error; } /* * Return the number of refcount objects for an AG. */ size_t refcount_record_count( struct xfs_mount *mp, xfs_agnumber_t agno) { return slab_count(ag_rmaps[agno].ar_refcount_items); } /* * Return a slab cursor that will return refcount objects in order. */ int init_refcount_cursor( xfs_agnumber_t agno, struct xfs_slab_cursor **cur) { return init_slab_cursor(ag_rmaps[agno].ar_refcount_items, NULL, cur); } /* * Disable the refcount btree check. */ void refcount_avoid_check(void) { refcbt_suspect = true; } /* * Compare the observed reference counts against what's in the ag btree. */ int check_refcounts( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_slab_cursor *rl_cur; struct xfs_btree_cur *bt_cur = NULL; int error; int have; int i; struct xfs_buf *agbp = NULL; struct xfs_refcount_irec *rl_rec; struct xfs_refcount_irec tmp; struct xfs_perag *pag; /* per allocation group data */ if (!xfs_sb_version_hasreflink(&mp->m_sb)) return 0; if (refcbt_suspect) { if (no_modify && agno == 0) do_warn(_("would rebuild corrupt refcount btrees.\n")); return 0; } /* Create cursors to refcount structures */ error = init_refcount_cursor(agno, &rl_cur); if (error) return error; error = -libxfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); if (error) goto err; /* Leave the per-ag data "uninitialized" since we rewrite it later */ pag = libxfs_perag_get(mp, agno); pag->pagf_init = 0; libxfs_perag_put(pag); bt_cur = libxfs_refcountbt_init_cursor(mp, NULL, agbp, agno); if (!bt_cur) { error = -ENOMEM; goto err; } rl_rec = pop_slab_cursor(rl_cur); while (rl_rec) { /* Look for a refcount record in the btree */ error = -libxfs_refcount_lookup_le(bt_cur, rl_rec->rc_startblock, &have); if (error) goto err; if (!have) { do_warn( _("Missing reference count record for (%u/%u) len %u count %u\n"), agno, rl_rec->rc_startblock, rl_rec->rc_blockcount, rl_rec->rc_refcount); goto next_loop; } error = -libxfs_refcount_get_rec(bt_cur, &tmp, &i); if (error) goto err; if (!i) { do_warn( _("Missing reference count record for (%u/%u) len %u count %u\n"), agno, rl_rec->rc_startblock, rl_rec->rc_blockcount, rl_rec->rc_refcount); goto next_loop; } /* Compare each refcount observation against the btree's */ if (tmp.rc_startblock != rl_rec->rc_startblock || tmp.rc_blockcount < rl_rec->rc_blockcount || tmp.rc_refcount < rl_rec->rc_refcount) do_warn( _("Incorrect reference count: saw (%u/%u) len %u nlinks %u; should be (%u/%u) len %u nlinks %u\n"), agno, tmp.rc_startblock, tmp.rc_blockcount, tmp.rc_refcount, agno, rl_rec->rc_startblock, rl_rec->rc_blockcount, rl_rec->rc_refcount); next_loop: rl_rec = pop_slab_cursor(rl_cur); } err: if (bt_cur) libxfs_btree_del_cursor(bt_cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); if (agbp) libxfs_putbuf(agbp); free_slab_cursor(&rl_cur); return 0; } /* * Regenerate the AGFL so that we don't run out of it while rebuilding the * rmap btree. If skip_rmapbt is true, don't update the rmapbt (most probably * because we're updating the rmapbt). */ void fix_freelist( struct xfs_mount *mp, xfs_agnumber_t agno, bool skip_rmapbt) { xfs_alloc_arg_t args; xfs_trans_t *tp; int flags; int error; memset(&args, 0, sizeof(args)); args.mp = mp; args.agno = agno; args.alignment = 1; args.pag = libxfs_perag_get(mp, agno); error = -libxfs_trans_alloc_rollable(mp, 0, &tp); if (error) do_error(_("failed to fix AGFL on AG %d, error %d\n"), agno, error); args.tp = tp; /* * Prior to rmapbt, all we had to do to fix the freelist is "expand" * the fresh AGFL header from empty to full. That hasn't changed. For * rmapbt, however, things change a bit. * * When we're stuffing the rmapbt with the AG btree rmaps the tree can * expand, so we need to keep the AGFL well-stocked for the expansion. * However, this expansion can cause the bnobt/cntbt to shrink, which * can make the AGFL eligible for shrinking. Shrinking involves * freeing rmapbt entries, but since we haven't finished loading the * rmapbt with the btree rmaps it's possible for the remove operation * to fail. The AGFL block is large enough at this point to absorb any * blocks freed from the bnobt/cntbt, so we can disable shrinking. * * During the initial AGFL regeneration during AGF generation in phase5 * we must also disable rmapbt modifications because the AGF that * libxfs reads does not yet point to the new rmapbt. These initial * AGFL entries are added just prior to adding the AG btree block rmaps * to the rmapbt. It's ok to pass NOSHRINK here too, since the AGFL is * empty and cannot shrink. */ flags = XFS_ALLOC_FLAG_NOSHRINK; if (skip_rmapbt) flags |= XFS_ALLOC_FLAG_NORMAP; error = -libxfs_alloc_fix_freelist(&args, flags); libxfs_perag_put(args.pag); if (error) { do_error(_("failed to fix AGFL on AG %d, error %d\n"), agno, error); } error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); } /* * Remember how many AGFL entries came from excess AG btree allocations and * therefore already have rmap entries. */ void rmap_store_agflcount( struct xfs_mount *mp, xfs_agnumber_t agno, int count) { if (!rmap_needs_work(mp)) return; ag_rmaps[agno].ar_flcount = count; } xfsprogs-5.3.0/repair/rmap.h0000644000175000017500000000413113435336037015644 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef RMAP_H_ #define RMAP_H_ extern bool collect_rmaps; extern bool rmap_needs_work(struct xfs_mount *); extern void rmaps_init(struct xfs_mount *); extern void rmaps_free(struct xfs_mount *); extern int rmap_add_rec(struct xfs_mount *, xfs_ino_t, int, struct xfs_bmbt_irec *); extern int rmap_finish_collecting_fork_recs(struct xfs_mount *mp, xfs_agnumber_t agno); extern int rmap_add_ag_rec(struct xfs_mount *, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner); extern int rmap_add_bmbt_rec(struct xfs_mount *, xfs_ino_t, int, xfs_fsblock_t); extern int rmap_fold_raw_recs(struct xfs_mount *mp, xfs_agnumber_t agno); extern bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2); extern int rmap_add_fixed_ag_rec(struct xfs_mount *, xfs_agnumber_t); extern int rmap_store_ag_btree_rec(struct xfs_mount *, xfs_agnumber_t); extern size_t rmap_record_count(struct xfs_mount *, xfs_agnumber_t); extern int rmap_init_cursor(xfs_agnumber_t, struct xfs_slab_cursor **); extern void rmap_avoid_check(void); extern int rmaps_verify_btree(struct xfs_mount *, xfs_agnumber_t); extern int64_t rmap_diffkeys(struct xfs_rmap_irec *kp1, struct xfs_rmap_irec *kp2); extern void rmap_high_key_from_rec(struct xfs_rmap_irec *rec, struct xfs_rmap_irec *key); extern int compute_refcounts(struct xfs_mount *, xfs_agnumber_t); extern size_t refcount_record_count(struct xfs_mount *, xfs_agnumber_t); extern int init_refcount_cursor(xfs_agnumber_t, struct xfs_slab_cursor **); extern void refcount_avoid_check(void); extern int check_refcounts(struct xfs_mount *, xfs_agnumber_t); extern void record_inode_reflink_flag(struct xfs_mount *, struct xfs_dinode *, xfs_agnumber_t, xfs_agino_t, xfs_ino_t); extern int fix_inode_reflink_flags(struct xfs_mount *, xfs_agnumber_t); extern void fix_freelist(struct xfs_mount *, xfs_agnumber_t, bool); extern void rmap_store_agflcount(struct xfs_mount *, xfs_agnumber_t, int); #endif /* RMAP_H_ */ xfsprogs-5.3.0/repair/rt.c0000644000175000017500000001324213435336037015330 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "dinode.h" #include "protos.h" #include "err_protos.h" #include "rt.h" #define xfs_highbit64 libxfs_highbit64 /* for XFS_RTBLOCKLOG macro */ void rtinit(xfs_mount_t *mp) { if (mp->m_sb.sb_rblocks == 0) return; /* * realtime init -- blockmap initialization is * handled by incore_init() */ /* sumfile = calloc(mp->m_rsumsize, 1); */ if ((btmcompute = calloc(mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize, 1)) == NULL) do_error( _("couldn't allocate memory for incore realtime bitmap.\n")); if ((sumcompute = calloc(mp->m_rsumsize, 1)) == NULL) do_error( _("couldn't allocate memory for incore realtime summary info.\n")); } /* * generate the real-time bitmap and summary info based on the * incore realtime extent map. */ int generate_rtinfo(xfs_mount_t *mp, xfs_rtword_t *words, xfs_suminfo_t *sumcompute) { xfs_rtblock_t extno; xfs_rtblock_t start_ext; int bitsperblock; int bmbno; xfs_rtword_t freebit; xfs_rtword_t bits; int start_bmbno; int i; int offs; int log; int len; int in_extent; ASSERT(mp->m_rbmip == NULL); bitsperblock = mp->m_sb.sb_blocksize * NBBY; extno = start_ext = 0; bmbno = in_extent = start_bmbno = 0; /* * slower but simple, don't play around with trying to set * things one word at a time, just set bit as required. * Have to * track start and end (size) of each range of * free extents to set the summary info properly. */ while (extno < mp->m_sb.sb_rextents) { freebit = 1; *words = 0; bits = 0; for (i = 0; i < sizeof(xfs_rtword_t) * NBBY && extno < mp->m_sb.sb_rextents; i++, extno++) { if (get_rtbmap(extno) == XR_E_FREE) { sb_frextents++; bits |= freebit; if (in_extent == 0) { start_ext = extno; start_bmbno = bmbno; in_extent = 1; } } else if (in_extent == 1) { len = (int) (extno - start_ext); log = XFS_RTBLOCKLOG(len); offs = XFS_SUMOFFS(mp, log, start_bmbno); sumcompute[offs]++; in_extent = 0; } freebit <<= 1; } *words = bits; words++; if (extno % bitsperblock == 0) bmbno++; } if (in_extent == 1) { len = (int) (extno - start_ext); log = XFS_RTBLOCKLOG(len); offs = XFS_SUMOFFS(mp, log, start_bmbno); sumcompute[offs]++; } return(0); } #if 0 /* * returns 1 if bad, 0 if good */ int check_summary(xfs_mount_t *mp) { xfs_rfsblock_t bno; xfs_suminfo_t *csp; xfs_suminfo_t *fsp; int log; int error = 0; error = 0; csp = sumcompute; fsp = sumfile; for (log = 0; log < mp->m_rsumlevels; log++) { for (bno = 0; bno < mp->m_sb.sb_rbmblocks; bno++, csp++, fsp++) { if (*csp != *fsp) { do_warn( _("rt summary mismatch, size %d block %llu, file: %d, computed: %d\n"), log, bno, *fsp, *csp); error = 1; } } } return(error); } /* * examine the real-time bitmap file and compute summary * info off it. Should probably be changed to compute * the summary information off the incore computed bitmap * instead of the realtime bitmap file */ void process_rtbitmap(xfs_mount_t *mp, xfs_dinode_t *dino, blkmap_t *blkmap) { int error; int bit; int bitsperblock; int bmbno; int end_bmbno; xfs_fsblock_t bno; xfs_buf_t *bp; xfs_rtblock_t extno; int i; int len; int log; int offs; int prevbit; int start_bmbno; int start_bit; xfs_rtword_t *words; ASSERT(mp->m_rbmip == NULL); bitsperblock = mp->m_sb.sb_blocksize * NBBY; prevbit = 0; extno = 0; error = 0; end_bmbno = howmany(be64_to_cpu(dino->di_size), mp->m_sb.sb_blocksize); for (bmbno = 0; bmbno < end_bmbno; bmbno++) { bno = blkmap_get(blkmap, bmbno); if (bno == NULLFSBLOCK) { do_warn(_("can't find block %d for rtbitmap inode\n"), bmbno); error = 1; continue; } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), XFS_FSB_TO_BB(mp, 1), NULL); if (!bp) { do_warn(_("can't read block %d for rtbitmap inode\n"), bmbno); error = 1; continue; } words = (xfs_rtword_t *)bp->b_un.b_addr; for (bit = 0; bit < bitsperblock && extno < mp->m_sb.sb_rextents; bit++, extno++) { if (xfs_isset(words, bit)) { set_rtbmap(extno, XR_E_FREE); sb_frextents++; if (prevbit == 0) { start_bmbno = bmbno; start_bit = bit; prevbit = 1; } } else if (prevbit == 1) { len = (bmbno - start_bmbno) * bitsperblock + (bit - start_bit); log = XFS_RTBLOCKLOG(len); offs = XFS_SUMOFFS(mp, log, start_bmbno); sumcompute[offs]++; prevbit = 0; } } libxfs_putbuf(bp); if (extno == mp->m_sb.sb_rextents) break; } if (prevbit == 1) { len = (bmbno - start_bmbno) * bitsperblock + (bit - start_bit); log = XFS_RTBLOCKLOG(len); offs = XFS_SUMOFFS(mp, log, start_bmbno); sumcompute[offs]++; } } /* * copy the real-time summary file data into memory */ void process_rtsummary(xfs_mount_t *mp, xfs_dinode_t *dino, blkmap_t *blkmap) { xfs_fsblock_t bno; xfs_buf_t *bp; char *bytes; int sumbno; for (sumbno = 0; sumbno < blkmap->count; sumbno++) { bno = blkmap_get(blkmap, sumbno); if (bno == NULLFSBLOCK) { do_warn(_("block %d for rtsummary inode is missing\n"), sumbno); error++; continue; } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), XFS_FSB_TO_BB(mp, 1), NULL); if (!bp) { do_warn(_("can't read block %d for rtsummary inode\n"), sumbno); error++; continue; } bytes = bp->b_un.b_addr; memmove((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes, mp->m_sb.sb_blocksize); libxfs_putbuf(bp); } } #endif xfsprogs-5.3.0/repair/rt.h0000644000175000017500000000072313435336037015335 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ struct blkmap; void rtinit(xfs_mount_t *mp); int generate_rtinfo(xfs_mount_t *mp, xfs_rtword_t *words, xfs_suminfo_t *sumcompute); #if 0 int check_summary(xfs_mount_t *mp); void process_rtbitmap(xfs_mount_t *mp, xfs_dinode_t *dino, struct blkmap *blkmap); void process_rtsummary(xfs_mount_t *mp, struct blkmap *blkmap); #endif xfsprogs-5.3.0/repair/sb.c0000644000175000017500000004777313570057155015330 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libfrog/util.h" #include "libxfs.h" #include "libxcmd.h" #include "libxlog.h" #include "agheader.h" #include "globals.h" #include "protos.h" #include "err_protos.h" #include "xfs_multidisk.h" #include "libfrog/topology.h" #define BSIZE (1024 * 1024) /* * copy the fields of a superblock that are present in primary and * secondaries -- preserve fields that are different in the primary. */ static void copy_sb(xfs_sb_t *source, xfs_sb_t *dest) { xfs_ino_t rootino; xfs_ino_t rbmino; xfs_ino_t rsumino; xfs_ino_t uquotino; xfs_ino_t gquotino; xfs_ino_t pquotino; uint16_t versionnum; rootino = dest->sb_rootino; rbmino = dest->sb_rbmino; rsumino = dest->sb_rsumino; uquotino = dest->sb_uquotino; gquotino = dest->sb_gquotino; pquotino = dest->sb_pquotino; versionnum = dest->sb_versionnum; *dest = *source; dest->sb_rootino = rootino; dest->sb_rbmino = rbmino; dest->sb_rsumino = rsumino; dest->sb_uquotino = uquotino; dest->sb_gquotino = gquotino; dest->sb_pquotino = pquotino; dest->sb_versionnum = versionnum; /* * copy over version bits that are stamped into all * secondaries and cannot be changed at run time in * the primary superblock */ if (xfs_sb_version_hasdalign(source)) dest->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT; dest->sb_versionnum |= XFS_SB_VERSION_EXTFLGBIT; /* * these are all supposed to be zero or will get reset anyway */ dest->sb_icount = 0; dest->sb_ifree = 0; dest->sb_fdblocks = 0; dest->sb_frextents = 0; memset(source->sb_fname, 0, 12); } static int verify_sb_blocksize(xfs_sb_t *sb) { /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */ if (sb->sb_blocksize == 0) return XR_BAD_BLOCKSIZE; if (sb->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || sb->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG) return XR_BAD_BLOCKLOG; if (sb->sb_blocksize != (1 << sb->sb_blocklog)) return XR_BAD_BLOCKLOG; return 0; } /* * find a secondary superblock, copy it into the sb buffer. * start is the point to begin reading BSIZE bytes. * skip contains a byte-count of how far to advance for next read. */ static int __find_secondary_sb( xfs_sb_t *rsb, uint64_t start, uint64_t skip) { xfs_off_t off; xfs_sb_t *sb; xfs_sb_t bufsb; char *c_bufsb; int done; int i; int dirty; int retval; int bsize; sb = (xfs_sb_t *)memalign(libxfs_device_alignment(), BSIZE); if (!sb) { do_error( _("error finding secondary superblock -- failed to memalign buffer\n")); exit(1); } memset(&bufsb, 0, sizeof(xfs_sb_t)); retval = 0; dirty = 0; bsize = 0; /* * skip first sector since we know that's bad */ for (done = 0, off = start; !done ; off += skip) { /* * read disk 1 MByte at a time. */ if (lseek(x.dfd, off, SEEK_SET) != off) { done = 1; } if (!done && (bsize = read(x.dfd, sb, BSIZE)) <= 0) { done = 1; } do_warn("."); /* * check the buffer 512 bytes at a time since * we don't know how big the sectors really are. */ for (i = 0; !done && i < bsize; i += BBSIZE) { c_bufsb = (char *)sb + i; libxfs_sb_from_disk(&bufsb, (xfs_dsb_t *)c_bufsb); if (verify_sb(c_bufsb, &bufsb, 0) != XR_OK) continue; do_warn(_("found candidate secondary superblock...\n")); /* * found one. now verify it by looking * for other secondaries. */ memmove(rsb, &bufsb, sizeof(xfs_sb_t)); rsb->sb_inprogress = 0; copied_sunit = 1; if (verify_set_primary_sb(rsb, 0, &dirty) == XR_OK) { do_warn( _("verified secondary superblock...\n")); done = 1; retval = 1; } else { do_warn( _("unable to verify superblock, continuing...\n")); } } } free(sb); return retval; } static int guess_default_geometry( uint64_t *agsize, uint64_t *agcount, libxfs_init_t *x) { struct fs_topology ft; int blocklog; uint64_t dblocks; int multidisk; memset(&ft, 0, sizeof(ft)); get_topology(x, &ft, 1); /* * get geometry from get_topology result. * Use default block size (2^12) */ blocklog = 12; multidisk = ft.dswidth | ft.dsunit; dblocks = x->dsize >> (blocklog - BBSHIFT); calc_default_ag_geometry(blocklog, dblocks, multidisk, agsize, agcount); return blocklog; } int find_secondary_sb(xfs_sb_t *rsb) { int retval = 0; uint64_t agcount; uint64_t agsize; uint64_t skip; int blocklog; /* * Attempt to find secondary sb with a coarse approach, * first trying agblocks and blocksize read from sb, providing * they're sane. */ do_warn(_("\nattempting to find secondary superblock...\n")); if (verify_sb_blocksize(rsb) == 0) { skip = (uint64_t)rsb->sb_agblocks * rsb->sb_blocksize; if (skip >= XFS_AG_MIN_BYTES && skip <= XFS_AG_MAX_BYTES) retval = __find_secondary_sb(rsb, skip, skip); } /* If that failed, retry coarse approach, using default geometry */ if (!retval) { blocklog = guess_default_geometry(&agsize, &agcount, &x); skip = agsize << blocklog; retval = __find_secondary_sb(rsb, skip, skip); } /* If that failed, fall back to the brute force method */ if (!retval) retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES, BSIZE); return retval; } /* * Calculate what the inode alignment field ought to be based on internal * superblock info and determine if it is valid. * * For standard v5 superblocks, the inode alignment must either match * XFS_INODE_BIG_CLUSTER_SIZE or a multiple based on the inode size. For v5 * superblocks with sparse inode chunks enabled, inode alignment must match the * inode chunk size. * * Return true if the alignment is valid, false otherwise. */ static bool sb_validate_ino_align(struct xfs_sb *sb) { xfs_extlen_t align; if (!xfs_sb_version_hasalign(sb)) return true; /* standard cluster size alignment is always valid */ align = XFS_INODE_BIG_CLUSTER_SIZE >> sb->sb_blocklog; if (align == sb->sb_inoalignmt) return true; /* alignment scaled by inode size is v5 only for now */ if (!xfs_sb_version_hascrc(sb)) return false; align = (XFS_INODE_BIG_CLUSTER_SIZE * sb->sb_inodesize / XFS_DINODE_MIN_SIZE) >> sb->sb_blocklog; if (align == sb->sb_inoalignmt) return true; /* * Sparse inodes requires inoalignmt to match full inode chunk size and * spino_align to match the scaled alignment (as calculated above). */ if (xfs_sb_version_hassparseinodes(sb)) { if (align != sb->sb_spino_align) return false; align = (sb->sb_inodesize * XFS_INODES_PER_CHUNK) >> sb->sb_blocklog; if (align == sb->sb_inoalignmt) return true; } return false; } /* * Validate the given log space. Derived from xfs_log_mount, though we * can't validate the minimum log size until later. We only do this * validation on V5 filesystems because the kernel doesn't reject malformed * log geometry on older revision filesystems. * * Returns false if the log is garbage. */ static bool verify_sb_loginfo( struct xfs_sb *sb) { if (xfs_sb_version_hascrc(sb) && (sb->sb_logblocks == 0 || sb->sb_logblocks > XFS_MAX_LOG_BLOCKS || ((unsigned long long)sb->sb_logblocks << sb->sb_blocklog) > XFS_MAX_LOG_BYTES)) return false; if (sb->sb_logsunit > 1 && sb->sb_logsunit % sb->sb_blocksize) return false; return true; } /* * verify a superblock -- does not verify root inode # * can only check that geometry info is internally * consistent. because of growfs, that's no guarantee * of correctness (e.g. geometry may have changed) * * fields verified or consistency checked: * * sb_magicnum * * sb_versionnum * * sb_inprogress * * sb_blocksize (as a group) * sb_blocklog * * geometry info - sb_dblocks (as a group) * sb_agcount * sb_agblocks * sb_agblklog * * inode info - sb_inodesize (x-checked with geo info) * sb_inopblock * * sector size info - * sb_sectsize * sb_sectlog * sb_logsectsize * sb_logsectlog * * not checked here - * sb_rootino * sb_fname * sb_fpack * sb_logstart * sb_uuid * * ALL real-time fields * final 4 summary counters */ int verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb) { uint32_t bsize; int i; int ret; /* check magic number and version number */ if (sb->sb_magicnum != XFS_SB_MAGIC) return(XR_BAD_MAGIC); if (!xfs_sb_good_version(sb)) return(XR_BAD_VERSION); /* does sb think mkfs really finished ? */ if (is_primary_sb && sb->sb_inprogress == 1) return(XR_BAD_INPROGRESS); /* * before going *any further*, validate the sector size and if the * version says we should have CRCs enabled, validate that. */ /* check to make sure sectorsize is legal 2^N, 9 <= N <= 15 */ if (sb->sb_sectsize == 0) return(XR_BAD_SECT_SIZE_DATA); bsize = 1; for (i = 0; bsize < sb->sb_sectsize && i < sizeof(sb->sb_sectsize) * NBBY; i++) { bsize <<= 1; } if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG) return(XR_BAD_SECT_SIZE_DATA); /* check sb sectorsize field against sb sectlog field */ if (i != sb->sb_sectlog) return(XR_BAD_SECT_SIZE_DATA); /* sector size in range - CRC check time */ if (xfs_sb_version_hascrc(sb) && !libxfs_verify_cksum(sb_buf, sb->sb_sectsize, XFS_SB_CRC_OFF)) return XR_BAD_CRC; /* check to ensure blocksize and blocklog are legal */ ret = verify_sb_blocksize(sb); if (ret != 0) return ret; /* sanity check ag count, size fields against data size field */ if (sb->sb_dblocks == 0 || sb->sb_dblocks > XFS_MAX_DBLOCKS(sb) || sb->sb_dblocks < XFS_MIN_DBLOCKS(sb)) return(XR_BAD_FS_SIZE_DATA); if (sb->sb_agblklog != (uint8_t)log2_roundup(sb->sb_agblocks)) return(XR_BAD_FS_SIZE_DATA); if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE || sb->sb_inodesize > XFS_DINODE_MAX_SIZE || sb->sb_inodelog < XFS_DINODE_MIN_LOG || sb->sb_inodelog > XFS_DINODE_MAX_LOG || sb->sb_inodesize != (1 << sb->sb_inodelog) || sb->sb_logsunit > XLOG_MAX_RECORD_BSIZE || sb->sb_inopblock != howmany(sb->sb_blocksize, sb->sb_inodesize) || (sb->sb_blocklog - sb->sb_inodelog != sb->sb_inopblog)) return XR_BAD_INO_SIZE_DATA; if (!verify_sb_loginfo(sb)) return XR_BAD_LOG_GEOMETRY; if (xfs_sb_version_hassector(sb)) { /* check to make sure log sector is legal 2^N, 9 <= N <= 15 */ if (sb->sb_logsectsize == 0) return(XR_BAD_SECT_SIZE_DATA); bsize = 1; for (i = 0; bsize < sb->sb_logsectsize && i < sizeof(sb->sb_logsectsize) * NBBY; i++) { bsize <<= 1; } if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG) return(XR_BAD_SECT_SIZE_DATA); /* check sb log sectorsize field against sb log sectlog field */ if (i != sb->sb_logsectlog) return(XR_BAD_SECT_SIZE_DATA); } /* * real-time extent size is always set */ if (sb->sb_rextsize * sb->sb_blocksize > XFS_MAX_RTEXTSIZE) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rextsize * sb->sb_blocksize < XFS_MIN_RTEXTSIZE) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rblocks == 0) { if (sb->sb_rextents != 0) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rbmblocks != 0) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rextslog != 0) return(XR_BAD_RT_GEO_DATA); if (sb->sb_frextents != 0) return(XR_BAD_RT_GEO_DATA); } else { /* * if we have a real-time partition, sanity-check geometry */ if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rextslog != libxfs_highbit32((unsigned int)sb->sb_rextents)) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents, NBBY * sb->sb_blocksize)) return(XR_BAD_RT_GEO_DATA); } /* * verify correctness of inode alignment if it's there */ if (!sb_validate_ino_align(sb)) return(XR_BAD_INO_ALIGN); /* * verify max. % of inodes (sb_imax_pct) */ if (sb->sb_imax_pct > 100) return(XR_BAD_INO_MAX_PCT); /* * verify stripe alignment fields if present */ if (xfs_sb_version_hasdalign(sb)) { if ((!sb->sb_unit && sb->sb_width) || (sb->sb_unit && sb->sb_agblocks % sb->sb_unit)) return(XR_BAD_SB_UNIT); if ((sb->sb_unit && !sb->sb_width) || (sb->sb_width && sb->sb_unit && sb->sb_width % sb->sb_unit)) return(XR_BAD_SB_WIDTH); } else if (sb->sb_unit || sb->sb_width) return XR_BAD_SB_WIDTH; /* Directory block log */ if (sb->sb_blocklog + sb->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG) return XR_BAD_DIR_SIZE_DATA; return(XR_OK); } void write_primary_sb(xfs_sb_t *sbp, int size) { xfs_dsb_t *buf; if (no_modify) return; buf = memalign(libxfs_device_alignment(), size); if (buf == NULL) { do_error(_("failed to memalign superblock buffer\n")); return; } memset(buf, 0, size); if (lseek(x.dfd, 0LL, SEEK_SET) != 0LL) { free(buf); do_error(_("couldn't seek to offset 0 in filesystem\n")); } libxfs_sb_to_disk(buf, sbp); if (xfs_sb_version_hascrc(sbp)) xfs_update_cksum((char *)buf, size, XFS_SB_CRC_OFF); if (write(x.dfd, buf, size) != size) { free(buf); do_error(_("primary superblock write failed!\n")); } free(buf); } /* * get a possible superblock -- checks for internal consistency */ int get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno) { int error, rval; xfs_dsb_t *buf; buf = memalign(libxfs_device_alignment(), size); if (buf == NULL) { do_error( _("error reading superblock %u -- failed to memalign buffer\n"), agno); exit(1); } memset(buf, 0, size); memset(sbp, 0, sizeof(*sbp)); /* try and read it first */ if (lseek(x.dfd, off, SEEK_SET) != off) { do_warn( _("error reading superblock %u -- seek to offset %" PRId64 " failed\n"), agno, off); free(buf); return(XR_EOF); } if ((rval = read(x.dfd, buf, size)) != size) { error = errno; do_warn( _("superblock read failed, offset %" PRId64 ", size %d, ag %u, rval %d\n"), off, size, agno, rval); do_error("%s\n", strerror(error)); } libxfs_sb_from_disk(sbp, buf); rval = verify_sb((char *)buf, sbp, agno == 0); free(buf); return rval; } /* returns element on list with highest reference count */ static fs_geo_list_t * get_best_geo(fs_geo_list_t *list) { int cnt = 0; fs_geo_list_t *current, *rval = NULL; current = list; while (current != NULL) { if (current->refs > cnt) { rval = current; cnt = current->refs; } current = current->next; } return(rval); } /* adds geometry info to linked list. returns (sometimes new) head of list */ static fs_geo_list_t * add_geo(fs_geo_list_t *list, fs_geometry_t *geo_p, int index) { fs_geo_list_t *current = list; while (current != NULL) { if (memcmp(geo_p, ¤t->geo, sizeof(fs_geometry_t)) == 0) { current->refs++; return(list); } current = current->next; } if ((current = malloc(sizeof(fs_geo_list_t))) == NULL) { do_error(_("couldn't malloc geometry structure\n")); exit(1); } current->geo = *geo_p; current->refs = 1; current->next = list; current->index = index; return(current); } static void free_geo(fs_geo_list_t *list) { fs_geo_list_t *next; fs_geo_list_t *current; for (current = list; current != NULL; current = next) { next = current->next; free(current); } } void get_sb_geometry(fs_geometry_t *geo, xfs_sb_t *sbp) { memset(geo, 0, sizeof(fs_geometry_t)); /* * blindly set fields that we know are always good */ geo->sb_blocksize = sbp->sb_blocksize; geo->sb_dblocks = sbp->sb_dblocks; geo->sb_rblocks = sbp->sb_rblocks; geo->sb_rextents = sbp->sb_rextents; geo->sb_logstart = sbp->sb_logstart; geo->sb_rextsize = sbp->sb_rextsize; geo->sb_agblocks = sbp->sb_agblocks; geo->sb_agcount = sbp->sb_agcount; geo->sb_rbmblocks = sbp->sb_rbmblocks; geo->sb_logblocks = sbp->sb_logblocks; geo->sb_sectsize = sbp->sb_sectsize; geo->sb_inodesize = sbp->sb_inodesize; if (xfs_sb_version_hasalign(sbp)) geo->sb_ialignbit = 1; if (xfs_sb_version_hasdalign(sbp)) geo->sb_salignbit = 1; geo->sb_extflgbit = 1; geo->sb_fully_zeroed = 1; } /* * the way to verify that a primary sb is consistent with the * filesystem is find the secondaries given the info in the * primary and compare the geometries in the secondaries against * the geometry indicated by the primary. * * returns 0 if ok, else error code (XR_EOF, XR_INSUFF_SEC_SB, etc). */ int verify_set_primary_sb(xfs_sb_t *rsb, int sb_index, int *sb_modified) { xfs_off_t off; fs_geometry_t geo; xfs_sb_t *sb; fs_geo_list_t *list; fs_geo_list_t *current; xfs_agnumber_t agno; int num_sbs; int size; int num_ok; int retval; /* * We haven't been able to validate the sector size yet properly * (e.g. in the case of repairing an image in a file), so we need to * take into account sector mismatches and so use the maximum possible * sector size rather than the sector size in @rsb. */ size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG)); list = NULL; num_ok = 0; *sb_modified = 0; num_sbs = rsb->sb_agcount; sb = (xfs_sb_t *) alloc_ag_buf(size); /* * put the primary sb geometry info onto the geometry list */ get_sb_geometry(&geo, rsb); list = add_geo(list, &geo, sb_index); /* * scan the secondaries and check them off as we get them so we only * process each one once */ for (agno = 1; agno < rsb->sb_agcount; agno++) { off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog; retval = get_sb(sb, off, size, agno); if (retval == XR_EOF) goto out_free_list; if (retval == XR_OK) { /* * save away geometry info. don't bother checking the * sb against the agi/agf as the odds of the sb being * corrupted in a way that it is internally consistent * but not consistent with the rest of the filesystem is * really really low. */ get_sb_geometry(&geo, sb); list = add_geo(list, &geo, agno); num_ok++; } } /* * see if we have enough superblocks to bother with */ retval = 0; if (num_ok < num_sbs / 2) { retval = XR_INSUFF_SEC_SB; goto out_free_list; } current = get_best_geo(list); /* * check that enough sbs agree that we're willing to * go with this geometry. if not, print out the * geometry and a message about the force option. */ switch (num_sbs) { case 2: /* * If we only have two allocation groups, and the superblock * in the second allocation group differs from the primary * superblock we can't verify the geometry information. * Warn the user about this situation and get out unless * explicitly overridden. */ if (current->refs != 2) { if (!force_geo) { do_warn( _("Only two AGs detected and they do not match - " "cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n")); exit(1); } } goto out_free_list; case 1: /* * If we only have a single allocation group there is no * secondary superblock that we can use to verify the geometry * information. Warn the user about this situation and get * out unless explicitly overridden. */ if (!force_geo) { do_warn( _("Only one AG detected - " "cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n")); exit(1); } goto out_free_list; default: /* * at least half of the probed superblocks have * to agree. if they don't, this fs is probably * too far gone anyway considering the fact that * XFS normally doesn't alter the secondary superblocks. */ if (current->refs < num_sbs / 2) { do_warn( _("Not enough matching superblocks - cannot proceed.\n")); exit(1); } } /* * set the geometry into primary superblock if necessary. */ if (current->index != sb_index) { *sb_modified = 1; off = (xfs_off_t)current->index * current->geo.sb_agblocks * current->geo.sb_blocksize; if (get_sb(sb, off, current->geo.sb_sectsize, current->index) != XR_OK) do_error(_("could not read superblock\n")); copy_sb(sb, rsb); /* * turn off inprogress bit since this is the primary. * also save away values that we need to ensure are * consistent in the other secondaries. */ rsb->sb_inprogress = 0; sb_inoalignmt = sb->sb_inoalignmt; sb_unit = sb->sb_unit; sb_width = sb->sb_width; } out_free_list: free_geo(list); free(sb); return retval; } xfsprogs-5.3.0/repair/scan.c0000644000175000017500000020113213570057155015625 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "avl.h" #include "globals.h" #include "agheader.h" #include "incore.h" #include "protos.h" #include "err_protos.h" #include "dinode.h" #include "scan.h" #include "versions.h" #include "bmap.h" #include "progress.h" #include "threads.h" #include "slab.h" #include "rmap.h" static xfs_mount_t *mp = NULL; /* * Variables to validate AG header values against the manual count * from the btree traversal. */ struct aghdr_cnts { xfs_agnumber_t agno; xfs_extlen_t agffreeblks; xfs_extlen_t agflongest; uint64_t agfbtreeblks; uint32_t agicount; uint32_t agifreecount; uint64_t fdblocks; uint64_t usedblocks; uint64_t ifreecount; uint32_t fibtfreecount; }; void set_mp(xfs_mount_t *mpp) { libxfs_bcache_purge(); mp = mpp; } static void scan_sbtree( xfs_agblock_t root, int nlevels, xfs_agnumber_t agno, int suspect, void (*func)(struct xfs_btree_block *block, int level, xfs_agblock_t bno, xfs_agnumber_t agno, int suspect, int isroot, uint32_t magic, void *priv, const struct xfs_buf_ops *ops), int isroot, uint32_t magic, void *priv, const struct xfs_buf_ops *ops) { xfs_buf_t *bp; bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, root), XFS_FSB_TO_BB(mp, 1), 0, ops); if (!bp) { do_error(_("can't read btree block %d/%d\n"), agno, root); return; } if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) { do_warn(_("btree block %d/%d is suspect, error %d\n"), agno, root, bp->b_error); suspect = 1; } (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, root, agno, suspect, isroot, magic, priv, ops); libxfs_putbuf(bp); } /* * returns 1 on bad news (inode needs to be cleared), 0 on good */ int scan_lbtree( xfs_fsblock_t root, int nlevels, int (*func)(struct xfs_btree_block *block, int level, int type, int whichfork, xfs_fsblock_t bno, xfs_ino_t ino, xfs_rfsblock_t *tot, uint64_t *nex, blkmap_t **blkmapp, bmap_cursor_t *bm_cursor, int isroot, int check_dups, int *dirty, uint64_t magic), int type, int whichfork, xfs_ino_t ino, xfs_rfsblock_t *tot, uint64_t *nex, blkmap_t **blkmapp, bmap_cursor_t *bm_cursor, int isroot, int check_dups, uint64_t magic, const struct xfs_buf_ops *ops) { xfs_buf_t *bp; int err; int dirty = 0; bool badcrc = false; bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, root), XFS_FSB_TO_BB(mp, 1), 0, ops); if (!bp) { do_error(_("can't read btree block %d/%d\n"), XFS_FSB_TO_AGNO(mp, root), XFS_FSB_TO_AGBNO(mp, root)); return(1); } /* * only check for bad CRC here - caller will determine if there * is a corruption or not and whether it got corrected and so needs * writing back. CRC errors always imply we need to write the block. */ if (bp->b_error == -EFSBADCRC) { do_warn(_("btree block %d/%d is suspect, error %d\n"), XFS_FSB_TO_AGNO(mp, root), XFS_FSB_TO_AGBNO(mp, root), bp->b_error); badcrc = true; } err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, type, whichfork, root, ino, tot, nex, blkmapp, bm_cursor, isroot, check_dups, &dirty, magic); ASSERT(dirty == 0 || (dirty && !no_modify)); if ((dirty || badcrc) && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); return(err); } int scan_bmapbt( struct xfs_btree_block *block, int level, int type, int whichfork, xfs_fsblock_t bno, xfs_ino_t ino, xfs_rfsblock_t *tot, uint64_t *nex, blkmap_t **blkmapp, bmap_cursor_t *bm_cursor, int isroot, int check_dups, int *dirty, uint64_t magic) { int i; int err; xfs_bmbt_ptr_t *pp; xfs_bmbt_key_t *pkey; xfs_bmbt_rec_t *rp; xfs_fileoff_t first_key; xfs_fileoff_t last_key; char *forkname = get_forkname(whichfork); int numrecs; xfs_agnumber_t agno; xfs_agblock_t agbno; int state; int error; /* * unlike the ag freeblock btrees, if anything looks wrong * in an inode bmap tree, just bail. it's possible that * we'll miss a case where the to-be-toasted inode and * another inode are claiming the same block but that's * highly unlikely. */ if (be32_to_cpu(block->bb_magic) != magic) { do_warn( _("bad magic # %#x in inode %" PRIu64 " (%s fork) bmbt block %" PRIu64 "\n"), be32_to_cpu(block->bb_magic), ino, forkname, bno); return(1); } if (be16_to_cpu(block->bb_level) != level) { do_warn( _("expected level %d got %d in inode %" PRIu64 ", (%s fork) bmbt block %" PRIu64 "\n"), level, be16_to_cpu(block->bb_level), ino, forkname, bno); return(1); } if (magic == XFS_BMAP_CRC_MAGIC) { /* verify owner */ if (be64_to_cpu(block->bb_u.l.bb_owner) != ino) { do_warn( _("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), ino, (unsigned long long)be64_to_cpu(block->bb_u.l.bb_owner), bno); return 1; } /* verify block number */ if (be64_to_cpu(block->bb_u.l.bb_blkno) != XFS_FSB_TO_DADDR(mp, bno)) { do_warn( _("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), XFS_FSB_TO_DADDR(mp, bno), (unsigned long long)be64_to_cpu(block->bb_u.l.bb_blkno), bno); return 1; } /* verify uuid */ if (platform_uuid_compare(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid) != 0) { do_warn( _("wrong FS UUID, bmbt block %" PRIu64 "\n"), bno); return 1; } } if (check_dups == 0) { /* * check sibling pointers. if bad we have a conflict * between the sibling pointers and the child pointers * in the parent block. blow out the inode if that happens */ if (bm_cursor->level[level].fsbno != NULLFSBLOCK) { /* * this is not the first block on this level * so the cursor for this level has recorded the * values for this's block left-sibling. */ if (bno != bm_cursor->level[level].right_fsbno) { do_warn( _("bad fwd (right) sibling pointer (saw %" PRIu64 " parent block says %" PRIu64 ")\n" "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"), bm_cursor->level[level].right_fsbno, bno, ino, forkname, bm_cursor->level[level].fsbno); return(1); } if (be64_to_cpu(block->bb_u.l.bb_leftsib) != bm_cursor->level[level].fsbno) { do_warn( _("bad back (left) sibling pointer (saw %llu parent block says %" PRIu64 ")\n" "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"), (unsigned long long) be64_to_cpu(block->bb_u.l.bb_leftsib), bm_cursor->level[level].fsbno, ino, forkname, bno); return(1); } } else { /* * This is the first or only block on this level. * Check that the left sibling pointer is NULL */ if (be64_to_cpu(block->bb_u.l.bb_leftsib) != NULLFSBLOCK) { do_warn( _("bad back (left) sibling pointer (saw %llu should be NULL (0))\n" "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"), (unsigned long long) be64_to_cpu(block->bb_u.l.bb_leftsib), ino, forkname, bno); return(1); } } /* * update cursor block pointers to reflect this block */ bm_cursor->level[level].fsbno = bno; bm_cursor->level[level].left_fsbno = be64_to_cpu(block->bb_u.l.bb_leftsib); bm_cursor->level[level].right_fsbno = be64_to_cpu(block->bb_u.l.bb_rightsib); agno = XFS_FSB_TO_AGNO(mp, bno); agbno = XFS_FSB_TO_AGBNO(mp, bno); pthread_mutex_lock(&ag_locks[agno].lock); state = get_bmap(agno, agbno); switch (state) { case XR_E_INUSE1: /* * block was claimed as in use data by the rmap * btree, but has not been found in the data extent * map for the inode. That means this bmbt block hasn't * yet been claimed as in use, which means -it's ours- */ case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: set_bmap(agno, agbno, XR_E_INUSE); break; case XR_E_FS_MAP: case XR_E_INUSE: /* * we'll try and continue searching here since * the block looks like it's been claimed by file * to store user data, a directory to store directory * data, or the space allocation btrees but since * we made it here, the block probably * contains btree data. */ set_bmap(agno, agbno, XR_E_MULT); do_warn( _("inode 0x%" PRIx64 "bmap block 0x%" PRIx64 " claimed, state is %d\n"), ino, bno, state); break; case XR_E_MULT: case XR_E_INUSE_FS: set_bmap(agno, agbno, XR_E_MULT); do_warn( _("inode 0x%" PRIx64 " bmap block 0x%" PRIx64 " claimed, state is %d\n"), ino, bno, state); /* * if we made it to here, this is probably a bmap block * that is being used by *another* file as a bmap block * so the block will be valid. Both files should be * trashed along with any other file that impinges on * any blocks referenced by either file. So we * continue searching down this btree to mark all * blocks duplicate */ break; case XR_E_BAD_STATE: default: do_warn( _("bad state %d, inode %" PRIu64 " bmap block 0x%" PRIx64 "\n"), state, ino, bno); break; } pthread_mutex_unlock(&ag_locks[agno].lock); } else { /* * attribute fork for realtime files is in the regular * filesystem */ if (type != XR_INO_RTDATA || whichfork != XFS_DATA_FORK) { if (search_dup_extent(XFS_FSB_TO_AGNO(mp, bno), XFS_FSB_TO_AGBNO(mp, bno), XFS_FSB_TO_AGBNO(mp, bno) + 1)) return(1); } else { if (search_rt_dup_extent(mp, bno)) return(1); } } (*tot)++; numrecs = be16_to_cpu(block->bb_numrecs); /* Record BMBT blocks in the reverse-mapping data. */ if (check_dups && collect_rmaps) { agno = XFS_FSB_TO_AGNO(mp, bno); pthread_mutex_lock(&ag_locks[agno].lock); error = rmap_add_bmbt_rec(mp, ino, whichfork, bno); pthread_mutex_unlock(&ag_locks[agno].lock); if (error) do_error( _("couldn't add inode %"PRIu64" bmbt block %"PRIu64" reverse-mapping data."), ino, bno); } if (level == 0) { if (numrecs > mp->m_bmap_dmxr[0] || (isroot == 0 && numrecs < mp->m_bmap_dmnr[0])) { do_warn( _("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"), ino, numrecs, mp->m_bmap_dmnr[0], mp->m_bmap_dmxr[0]); return(1); } rp = XFS_BMBT_REC_ADDR(mp, block, 1); *nex += numrecs; /* * XXX - if we were going to fix up the btree record, * we'd do it right here. For now, if there's a problem, * we'll bail out and presumably clear the inode. */ if (check_dups == 0) { err = process_bmbt_reclist(mp, rp, &numrecs, type, ino, tot, blkmapp, &first_key, &last_key, whichfork); if (err) return 1; /* * check that key ordering is monotonically increasing. * if the last_key value in the cursor is set to * NULLFILEOFF, then we know this is the first block * on the leaf level and we shouldn't check the * last_key value. */ if (first_key <= bm_cursor->level[level].last_key && bm_cursor->level[level].last_key != NULLFILEOFF) { do_warn( _("out-of-order bmap key (file offset) in inode %" PRIu64 ", %s fork, fsbno %" PRIu64 "\n"), ino, forkname, bno); return(1); } /* * update cursor keys to reflect this block. * don't have to check if last_key is > first_key * since that gets checked by process_bmbt_reclist. */ bm_cursor->level[level].first_key = first_key; bm_cursor->level[level].last_key = last_key; return 0; } else { return scan_bmbt_reclist(mp, rp, &numrecs, type, ino, tot, whichfork); } } if (numrecs > mp->m_bmap_dmxr[1] || (isroot == 0 && numrecs < mp->m_bmap_dmnr[1])) { do_warn( _("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"), ino, numrecs, mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1]); return(1); } pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); pkey = XFS_BMBT_KEY_ADDR(mp, block, 1); last_key = NULLFILEOFF; for (i = 0, err = 0; i < numrecs; i++) { /* * XXX - if we were going to fix up the interior btree nodes, * we'd do it right here. For now, if there's a problem, * we'll bail out and presumably clear the inode. */ if (!verify_dfsbno(mp, be64_to_cpu(pp[i]))) { do_warn( _("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"), (unsigned long long) be64_to_cpu(pp[i]), ino); return(1); } err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt, type, whichfork, ino, tot, nex, blkmapp, bm_cursor, 0, check_dups, magic, &xfs_bmbt_buf_ops); if (err) return(1); /* * fix key (offset) mismatches between the first key * in the child block (as recorded in the cursor) and the * key in the interior node referencing the child block. * * fixes cases where entries have been shifted between * child blocks but the parent hasn't been updated. We * don't have to worry about the key values in the cursor * not being set since we only look at the key values of * our child and those are guaranteed to be set by the * call to scan_lbtree() above. */ if (check_dups == 0 && be64_to_cpu(pkey[i].br_startoff) != bm_cursor->level[level-1].first_key) { if (!no_modify) { do_warn( _("correcting bt key (was %llu, now %" PRIu64 ") in inode %" PRIu64 "\n" "\t\t%s fork, btree block %" PRIu64 "\n"), (unsigned long long) be64_to_cpu(pkey[i].br_startoff), bm_cursor->level[level-1].first_key, ino, forkname, bno); *dirty = 1; pkey[i].br_startoff = cpu_to_be64( bm_cursor->level[level-1].first_key); } else { do_warn( _("bad btree key (is %llu, should be %" PRIu64 ") in inode %" PRIu64 "\n" "\t\t%s fork, btree block %" PRIu64 "\n"), (unsigned long long) be64_to_cpu(pkey[i].br_startoff), bm_cursor->level[level-1].first_key, ino, forkname, bno); } } } /* * If we're the last node at our level, check that the last child * block's forward sibling pointer is NULL. */ if (check_dups == 0 && bm_cursor->level[level].right_fsbno == NULLFSBLOCK && bm_cursor->level[level - 1].right_fsbno != NULLFSBLOCK) { do_warn( _("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLFSBLOCK)\n" "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"), bm_cursor->level[level - 1].right_fsbno, ino, forkname, bm_cursor->level[level - 1].fsbno); return(1); } /* * update cursor keys to reflect this block */ if (check_dups == 0) { bm_cursor->level[level].first_key = be64_to_cpu(pkey[0].br_startoff); bm_cursor->level[level].last_key = be64_to_cpu(pkey[numrecs - 1].br_startoff); } return(0); } static void scan_allocbt( struct xfs_btree_block *block, int level, xfs_agblock_t bno, xfs_agnumber_t agno, int suspect, int isroot, uint32_t magic, void *priv, const struct xfs_buf_ops *ops) { struct aghdr_cnts *agcnts = priv; const char *name; int i; xfs_alloc_ptr_t *pp; xfs_alloc_rec_t *rp; int hdr_errors = 0; int numrecs; int state; xfs_extlen_t lastcount = 0; xfs_agblock_t lastblock = 0; switch (magic) { case XFS_ABTB_CRC_MAGIC: case XFS_ABTB_MAGIC: name = "bno"; break; case XFS_ABTC_CRC_MAGIC: case XFS_ABTC_MAGIC: name = "cnt"; break; default: name = "(unknown)"; assert(0); break; } if (be32_to_cpu(block->bb_magic) != magic) { do_warn(_("bad magic # %#x in bt%s block %d/%d\n"), be32_to_cpu(block->bb_magic), name, agno, bno); hdr_errors++; if (suspect) return; } /* * All freespace btree blocks except the roots are freed for a * fully used filesystem, thus they are counted towards the * free data block counter. */ if (!isroot) { agcnts->agfbtreeblks++; agcnts->fdblocks++; } if (be16_to_cpu(block->bb_level) != level) { do_warn(_("expected level %d got %d in bt%s block %d/%d\n"), level, be16_to_cpu(block->bb_level), name, agno, bno); hdr_errors++; if (suspect) return; } /* * check for btree blocks multiply claimed */ state = get_bmap(agno, bno); if (state != XR_E_UNKNOWN) { set_bmap(agno, bno, XR_E_MULT); do_warn( _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), name, state, agno, bno, suspect); return; } set_bmap(agno, bno, XR_E_FS_MAP); numrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (numrecs > mp->m_alloc_mxr[0]) { numrecs = mp->m_alloc_mxr[0]; hdr_errors++; } if (isroot == 0 && numrecs < mp->m_alloc_mnr[0]) { numrecs = mp->m_alloc_mnr[0]; hdr_errors++; } if (hdr_errors) { do_warn( _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0], mp->m_alloc_mxr[0], name, agno, bno); suspect++; } rp = XFS_ALLOC_REC_ADDR(mp, block, 1); for (i = 0; i < numrecs; i++) { xfs_agblock_t b, end; xfs_extlen_t len, blen; b = be32_to_cpu(rp[i].ar_startblock); len = be32_to_cpu(rp[i].ar_blockcount); end = b + len; if (b == 0 || !verify_agbno(mp, agno, b)) { do_warn( _("invalid start block %u in record %u of %s btree block %u/%u\n"), b, i, name, agno, bno); continue; } if (len == 0 || !verify_agbno(mp, agno, end - 1)) { do_warn( _("invalid length %u in record %u of %s btree block %u/%u\n"), len, i, name, agno, bno); continue; } if (magic == XFS_ABTB_MAGIC || magic == XFS_ABTB_CRC_MAGIC) { if (b <= lastblock) { do_warn(_( "out-of-order bno btree record %d (%u %u) block %u/%u\n"), i, b, len, agno, bno); } else { lastblock = b; } } else { agcnts->fdblocks += len; agcnts->agffreeblks += len; if (len > agcnts->agflongest) agcnts->agflongest = len; if (len < lastcount) { do_warn(_( "out-of-order cnt btree record %d (%u %u) block %u/%u\n"), i, b, len, agno, bno); } else { lastcount = len; } } for ( ; b < end; b += blen) { state = get_bmap_ext(agno, b, end, &blen); switch (state) { case XR_E_UNKNOWN: set_bmap(agno, b, XR_E_FREE1); break; case XR_E_FREE1: /* * no warning messages -- we'll catch * FREE1 blocks later */ if (magic == XFS_ABTC_MAGIC || magic == XFS_ABTC_CRC_MAGIC) { set_bmap_ext(agno, b, blen, XR_E_FREE); break; } /* fall through */ default: do_warn( _("block (%d,%d-%d) multiply claimed by %s space tree, state - %d\n"), agno, b, b + blen - 1, name, state); break; } } } return; } /* * interior record */ pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); if (numrecs > mp->m_alloc_mxr[1]) { numrecs = mp->m_alloc_mxr[1]; hdr_errors++; } if (isroot == 0 && numrecs < mp->m_alloc_mnr[1]) { numrecs = mp->m_alloc_mnr[1]; hdr_errors++; } /* * don't pass bogus tree flag down further if this block * looked ok. bail out if two levels in a row look bad. */ if (hdr_errors) { do_warn( _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1], mp->m_alloc_mxr[1], name, agno, bno); if (suspect) return; suspect++; } else if (suspect) { suspect = 0; } for (i = 0; i < numrecs; i++) { xfs_agblock_t agbno = be32_to_cpu(pp[i]); /* * XXX - put sibling detection right here. * we know our sibling chain is good. So as we go, * we check the entry before and after each entry. * If either of the entries references a different block, * check the sibling pointer. If there's a sibling * pointer mismatch, try and extract as much data * as possible. */ if (agbno != 0 && verify_agbno(mp, agno, agbno)) { scan_sbtree(agbno, level, agno, suspect, scan_allocbt, 0, magic, priv, ops); } } } static bool ino_issparse( struct xfs_inobt_rec *rp, int offset) { if (!xfs_sb_version_hassparseinodes(&mp->m_sb)) return false; return xfs_inobt_is_sparse_disk(rp, offset); } /* See if the rmapbt owners agree with our observations. */ static void process_rmap_rec( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t b, xfs_agblock_t end, xfs_extlen_t blen, int64_t owner, int state, const char *name) { switch (state) { case XR_E_UNKNOWN: switch (owner) { case XFS_RMAP_OWN_FS: case XFS_RMAP_OWN_LOG: set_bmap_ext(agno, b, blen, XR_E_INUSE_FS1); break; case XFS_RMAP_OWN_AG: case XFS_RMAP_OWN_INOBT: set_bmap_ext(agno, b, blen, XR_E_FS_MAP1); break; case XFS_RMAP_OWN_INODES: set_bmap_ext(agno, b, blen, XR_E_INO1); break; case XFS_RMAP_OWN_REFC: set_bmap_ext(agno, b, blen, XR_E_REFC); break; case XFS_RMAP_OWN_COW: set_bmap_ext(agno, b, blen, XR_E_COW); break; case XFS_RMAP_OWN_NULL: /* still unknown */ break; default: /* file data */ set_bmap_ext(agno, b, blen, XR_E_INUSE1); break; } break; case XR_E_INUSE_FS: if (owner == XFS_RMAP_OWN_FS || owner == XFS_RMAP_OWN_LOG) break; do_warn( _("Static meta block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"), agno, b, b + blen - 1, name, state, owner); break; case XR_E_FS_MAP: if (owner == XFS_RMAP_OWN_AG || owner == XFS_RMAP_OWN_INOBT) break; do_warn( _("AG meta block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"), agno, b, b + blen - 1, name, state, owner); break; case XR_E_INO: if (owner == XFS_RMAP_OWN_INODES) break; do_warn( _("inode block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"), agno, b, b + blen - 1, name, state, owner); break; case XR_E_REFC: if (owner == XFS_RMAP_OWN_REFC) break; do_warn( _("AG refcount block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"), agno, b, b + blen - 1, name, state, owner); break; case XR_E_INUSE: if (owner >= 0 && owner < mp->m_sb.sb_dblocks) break; do_warn( _("in use block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"), agno, b, b + blen - 1, name, state, owner); break; case XR_E_FREE1: case XR_E_FREE: /* * May be on the AGFL. If not, they'll * be caught later. */ break; case XR_E_INUSE1: /* * multiple inode owners are ok with * reflink enabled */ if (xfs_sb_version_hasreflink(&mp->m_sb) && !XFS_RMAP_NON_INODE_OWNER(owner)) break; /* fall through */ default: do_warn( _("unknown block (%d,%d-%d) mismatch on %s tree, state - %d,%" PRIx64 "\n"), agno, b, b + blen - 1, name, state, owner); break; } } struct rmap_priv { struct aghdr_cnts *agcnts; struct xfs_rmap_irec high_key; struct xfs_rmap_irec last_rec; xfs_agblock_t nr_blocks; }; static bool rmap_in_order( xfs_agblock_t b, xfs_agblock_t lastblock, uint64_t owner, uint64_t lastowner, uint64_t offset, uint64_t lastoffset) { if (b > lastblock) return true; else if (b < lastblock) return false; if (owner > lastowner) return true; else if (owner < lastowner) return false; return offset > lastoffset; } static void scan_rmapbt( struct xfs_btree_block *block, int level, xfs_agblock_t bno, xfs_agnumber_t agno, int suspect, int isroot, uint32_t magic, void *priv, const struct xfs_buf_ops *ops) { const char *name = "rmap"; int i; xfs_rmap_ptr_t *pp; struct xfs_rmap_rec *rp; struct rmap_priv *rmap_priv = priv; int hdr_errors = 0; int numrecs; int state; xfs_agblock_t lastblock = 0; uint64_t lastowner = 0; uint64_t lastoffset = 0; struct xfs_rmap_key *kp; struct xfs_rmap_irec key = {0}; if (magic != XFS_RMAP_CRC_MAGIC) { name = "(unknown)"; hdr_errors++; suspect++; goto out; } if (be32_to_cpu(block->bb_magic) != magic) { do_warn(_("bad magic # %#x in bt%s block %d/%d\n"), be32_to_cpu(block->bb_magic), name, agno, bno); hdr_errors++; if (suspect) goto out; } /* * All RMAP btree blocks except the roots are freed for a * fully empty filesystem, thus they are counted towards the * free data block counter. */ if (!isroot) { rmap_priv->agcnts->agfbtreeblks++; rmap_priv->agcnts->fdblocks++; } rmap_priv->nr_blocks++; if (be16_to_cpu(block->bb_level) != level) { do_warn(_("expected level %d got %d in bt%s block %d/%d\n"), level, be16_to_cpu(block->bb_level), name, agno, bno); hdr_errors++; if (suspect) goto out; } /* check for btree blocks multiply claimed */ state = get_bmap(agno, bno); if (!(state == XR_E_UNKNOWN || state == XR_E_FS_MAP1)) { set_bmap(agno, bno, XR_E_MULT); do_warn( _("%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), name, state, agno, bno, suspect); goto out; } set_bmap(agno, bno, XR_E_FS_MAP); numrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (numrecs > mp->m_rmap_mxr[0]) { numrecs = mp->m_rmap_mxr[0]; hdr_errors++; } if (isroot == 0 && numrecs < mp->m_rmap_mnr[0]) { numrecs = mp->m_rmap_mnr[0]; hdr_errors++; } if (hdr_errors) { do_warn( _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[0], mp->m_rmap_mxr[0], name, agno, bno); suspect++; } rp = XFS_RMAP_REC_ADDR(block, 1); for (i = 0; i < numrecs; i++) { xfs_agblock_t b, end; xfs_extlen_t len, blen; int64_t owner, offset; b = be32_to_cpu(rp[i].rm_startblock); len = be32_to_cpu(rp[i].rm_blockcount); owner = be64_to_cpu(rp[i].rm_owner); offset = be64_to_cpu(rp[i].rm_offset); key.rm_flags = 0; key.rm_startblock = b; key.rm_blockcount = len; key.rm_owner = owner; if (libxfs_rmap_irec_offset_unpack(offset, &key)) { /* Look for impossible flags. */ do_warn( _("invalid flags in record %u of %s btree block %u/%u\n"), i, name, agno, bno); continue; } end = key.rm_startblock + key.rm_blockcount; /* Make sure agbno & len make sense. */ if (!verify_agbno(mp, agno, b)) { do_warn( _("invalid start block %u in record %u of %s btree block %u/%u\n"), b, i, name, agno, bno); continue; } if (len == 0 || !verify_agbno(mp, agno, end - 1)) { do_warn( _("invalid length %u in record %u of %s btree block %u/%u\n"), len, i, name, agno, bno); continue; } /* Look for impossible owners. */ if (!((owner > XFS_RMAP_OWN_MIN && owner <= XFS_RMAP_OWN_FS) || (XFS_INO_TO_AGNO(mp, owner) < mp->m_sb.sb_agcount && XFS_AGINO_TO_AGBNO(mp, XFS_INO_TO_AGINO(mp, owner)) < mp->m_sb.sb_agblocks))) do_warn( _("invalid owner in rmap btree record %d (%"PRId64" %u) block %u/%u\n"), i, owner, len, agno, bno); /* Look for impossible record field combinations. */ if (XFS_RMAP_NON_INODE_OWNER(key.rm_owner)) { if (key.rm_flags) do_warn( _("record %d of block (%u/%u) in %s btree cannot have non-inode owner with flags\n"), i, agno, bno, name); if (key.rm_offset) do_warn( _("record %d of block (%u/%u) in %s btree cannot have non-inode owner with offset\n"), i, agno, bno, name); } /* Check for out of order records. */ if (i == 0) { advance: lastblock = b; lastowner = owner; lastoffset = offset; } else { bool bad; if (xfs_sb_version_hasreflink(&mp->m_sb)) bad = !rmap_in_order(b, lastblock, owner, lastowner, offset, lastoffset); else bad = b <= lastblock; if (bad) do_warn( _("out-of-order rmap btree record %d (%u %"PRId64" %"PRIx64" %u) block %u/%u\n"), i, b, owner, offset, len, agno, bno); else goto advance; } /* Is this mergeable with the previous record? */ if (rmaps_are_mergeable(&rmap_priv->last_rec, &key)) { do_warn( _("record %d in block (%u/%u) of %s tree should be merged with previous record\n"), i, agno, bno, name); rmap_priv->last_rec.rm_blockcount += key.rm_blockcount; } else rmap_priv->last_rec = key; /* Check that we don't go past the high key. */ key.rm_startblock += key.rm_blockcount - 1; if (!XFS_RMAP_NON_INODE_OWNER(key.rm_owner) && !(key.rm_flags & XFS_RMAP_BMBT_BLOCK)) key.rm_offset += key.rm_blockcount - 1; key.rm_blockcount = 0; if (rmap_diffkeys(&key, &rmap_priv->high_key) > 0) { do_warn( _("record %d greater than high key of block (%u/%u) in %s tree\n"), i, agno, bno, name); } /* Check for block owner collisions. */ for ( ; b < end; b += blen) { state = get_bmap_ext(agno, b, end, &blen); process_rmap_rec(mp, agno, b, end, blen, owner, state, name); } } goto out; } /* * interior record */ pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]); if (numrecs > mp->m_rmap_mxr[1]) { numrecs = mp->m_rmap_mxr[1]; hdr_errors++; } if (isroot == 0 && numrecs < mp->m_rmap_mnr[1]) { numrecs = mp->m_rmap_mnr[1]; hdr_errors++; } /* * don't pass bogus tree flag down further if this block * looked ok. bail out if two levels in a row look bad. */ if (hdr_errors) { do_warn( _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1], mp->m_rmap_mxr[1], name, agno, bno); if (suspect) goto out; suspect++; } else if (suspect) { suspect = 0; } /* check the node's high keys */ for (i = 0; !isroot && i < numrecs; i++) { kp = XFS_RMAP_HIGH_KEY_ADDR(block, i + 1); key.rm_flags = 0; key.rm_startblock = be32_to_cpu(kp->rm_startblock); key.rm_owner = be64_to_cpu(kp->rm_owner); if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset), &key)) { /* Look for impossible flags. */ do_warn( _("invalid flags in key %u of %s btree block %u/%u\n"), i, name, agno, bno); continue; } if (rmap_diffkeys(&key, &rmap_priv->high_key) > 0) do_warn( _("key %d greater than high key of block (%u/%u) in %s tree\n"), i, agno, bno, name); } for (i = 0; i < numrecs; i++) { xfs_agblock_t agbno = be32_to_cpu(pp[i]); /* * XXX - put sibling detection right here. * we know our sibling chain is good. So as we go, * we check the entry before and after each entry. * If either of the entries references a different block, * check the sibling pointer. If there's a sibling * pointer mismatch, try and extract as much data * as possible. */ kp = XFS_RMAP_HIGH_KEY_ADDR(block, i + 1); rmap_priv->high_key.rm_flags = 0; rmap_priv->high_key.rm_startblock = be32_to_cpu(kp->rm_startblock); rmap_priv->high_key.rm_owner = be64_to_cpu(kp->rm_owner); if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset), &rmap_priv->high_key)) { /* Look for impossible flags. */ do_warn( _("invalid flags in high key %u of %s btree block %u/%u\n"), i, name, agno, agbno); continue; } if (agbno != 0 && verify_agbno(mp, agno, agbno)) { scan_sbtree(agbno, level, agno, suspect, scan_rmapbt, 0, magic, priv, ops); } } out: if (suspect) rmap_avoid_check(); } struct refc_priv { struct xfs_refcount_irec last_rec; xfs_agblock_t nr_blocks; }; static void scan_refcbt( struct xfs_btree_block *block, int level, xfs_agblock_t bno, xfs_agnumber_t agno, int suspect, int isroot, uint32_t magic, void *priv, const struct xfs_buf_ops *ops) { const char *name = "refcount"; int i; xfs_refcount_ptr_t *pp; struct xfs_refcount_rec *rp; int hdr_errors = 0; int numrecs; int state; xfs_agblock_t lastblock = 0; struct refc_priv *refc_priv = priv; if (magic != XFS_REFC_CRC_MAGIC) { name = "(unknown)"; hdr_errors++; suspect++; goto out; } if (be32_to_cpu(block->bb_magic) != magic) { do_warn(_("bad magic # %#x in %s btree block %d/%d\n"), be32_to_cpu(block->bb_magic), name, agno, bno); hdr_errors++; if (suspect) goto out; } if (be16_to_cpu(block->bb_level) != level) { do_warn(_("expected level %d got %d in %s btree block %d/%d\n"), level, be16_to_cpu(block->bb_level), name, agno, bno); hdr_errors++; if (suspect) goto out; } refc_priv->nr_blocks++; /* check for btree blocks multiply claimed */ state = get_bmap(agno, bno); if (!(state == XR_E_UNKNOWN || state == XR_E_REFC)) { set_bmap(agno, bno, XR_E_MULT); do_warn( _("%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), name, state, agno, bno, suspect); goto out; } set_bmap(agno, bno, XR_E_FS_MAP); numrecs = be16_to_cpu(block->bb_numrecs); if (level == 0) { if (numrecs > mp->m_refc_mxr[0]) { numrecs = mp->m_refc_mxr[0]; hdr_errors++; } if (isroot == 0 && numrecs < mp->m_refc_mnr[0]) { numrecs = mp->m_refc_mnr[0]; hdr_errors++; } if (hdr_errors) { do_warn( _("bad btree nrecs (%u, min=%u, max=%u) in %s btree block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[0], mp->m_refc_mxr[0], name, agno, bno); suspect++; } rp = XFS_REFCOUNT_REC_ADDR(block, 1); for (i = 0; i < numrecs; i++) { xfs_agblock_t b, agb, end; xfs_extlen_t len; xfs_nlink_t nr; b = agb = be32_to_cpu(rp[i].rc_startblock); len = be32_to_cpu(rp[i].rc_blockcount); nr = be32_to_cpu(rp[i].rc_refcount); if (b >= XFS_REFC_COW_START && nr != 1) do_warn( _("leftover CoW extent has incorrect refcount in record %u of %s btree block %u/%u\n"), i, name, agno, bno); if (nr == 1) { if (agb < XFS_REFC_COW_START) do_warn( _("leftover CoW extent has invalid startblock in record %u of %s btree block %u/%u\n"), i, name, agno, bno); agb -= XFS_REFC_COW_START; } end = agb + len; if (!verify_agbno(mp, agno, agb)) { do_warn( _("invalid start block %u in record %u of %s btree block %u/%u\n"), b, i, name, agno, bno); continue; } if (len == 0 || !verify_agbno(mp, agno, end - 1)) { do_warn( _("invalid length %u in record %u of %s btree block %u/%u\n"), len, i, name, agno, bno); continue; } if (nr == 1) { xfs_agblock_t c; xfs_extlen_t cnr; for (c = agb; c < end; c += cnr) { state = get_bmap_ext(agno, c, end, &cnr); switch (state) { case XR_E_UNKNOWN: case XR_E_COW: do_warn( _("leftover CoW extent (%u/%u) len %u\n"), agno, c, cnr); set_bmap_ext(agno, c, cnr, XR_E_FREE); break; default: do_warn( _("extent (%u/%u) len %u claimed, state is %d\n"), agno, c, cnr, state); break; } } } else if (nr < 2 || nr > MAXREFCOUNT) { do_warn( _("invalid reference count %u in record %u of %s btree block %u/%u\n"), nr, i, name, agno, bno); continue; } if (b && b <= lastblock) { do_warn(_( "out-of-order %s btree record %d (%u %u) block %u/%u\n"), name, i, b, len, agno, bno); } else { lastblock = b; } /* Is this record mergeable with the last one? */ if (refc_priv->last_rec.rc_startblock + refc_priv->last_rec.rc_blockcount == b && refc_priv->last_rec.rc_refcount == nr) { do_warn( _("record %d in block (%u/%u) of %s tree should be merged with previous record\n"), i, agno, bno, name); refc_priv->last_rec.rc_blockcount += len; } else { refc_priv->last_rec.rc_startblock = b; refc_priv->last_rec.rc_blockcount = len; refc_priv->last_rec.rc_refcount = nr; } /* XXX: probably want to mark the reflinked areas? */ } goto out; } /* * interior record */ pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]); if (numrecs > mp->m_refc_mxr[1]) { numrecs = mp->m_refc_mxr[1]; hdr_errors++; } if (isroot == 0 && numrecs < mp->m_refc_mnr[1]) { numrecs = mp->m_refc_mnr[1]; hdr_errors++; } /* * don't pass bogus tree flag down further if this block * looked ok. bail out if two levels in a row look bad. */ if (hdr_errors) { do_warn( _("bad btree nrecs (%u, min=%u, max=%u) in %s btree block %u/%u\n"), be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[1], mp->m_refc_mxr[1], name, agno, bno); if (suspect) goto out; suspect++; } else if (suspect) { suspect = 0; } for (i = 0; i < numrecs; i++) { xfs_agblock_t agbno = be32_to_cpu(pp[i]); if (agbno != 0 && verify_agbno(mp, agno, agbno)) { scan_sbtree(agbno, level, agno, suspect, scan_refcbt, 0, magic, priv, ops); } } out: if (suspect) refcount_avoid_check(); return; } /* * The following helpers are to help process and validate individual on-disk * inode btree records. We have two possible inode btrees with slightly * different semantics. Many of the validations and actions are equivalent, such * as record alignment constraints, etc. Other validations differ, such as the * fact that the inode chunk block allocation state is set by the content of the * core inobt and verified by the content of the finobt. * * The following structures are used to facilitate common validation routines * where the only difference between validation of the inobt or finobt might be * the error messages that results in the event of failure. */ enum inobt_type { INOBT, FINOBT }; static const char *inobt_names[] = { "inobt", "finobt" }; static int verify_single_ino_chunk_align( xfs_agnumber_t agno, enum inobt_type type, struct xfs_inobt_rec *rp, int suspect, bool *skip) { const char *inobt_name = inobt_names[type]; xfs_ino_t lino; xfs_agino_t ino; xfs_agblock_t agbno; int off; *skip = false; ino = be32_to_cpu(rp->ir_startino); off = XFS_AGINO_TO_OFFSET(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, ino); lino = XFS_AGINO_TO_INO(mp, agno, ino); /* * on multi-block block chunks, all chunks start at the beginning of the * block. with multi-chunk blocks, all chunks must start on 64-inode * boundaries since each block can hold N complete chunks. if fs has * aligned inodes, all chunks must start at a fs_ino_alignment*N'th * agbno. skip recs with badly aligned starting inodes. */ if (ino == 0 || (inodes_per_block <= XFS_INODES_PER_CHUNK && off != 0) || (inodes_per_block > XFS_INODES_PER_CHUNK && off % XFS_INODES_PER_CHUNK != 0) || (fs_aligned_inodes && fs_ino_alignment && agbno % fs_ino_alignment != 0)) { do_warn( _("badly aligned %s rec (starting inode = %" PRIu64 ")\n"), inobt_name, lino); suspect++; } /* * verify numeric validity of inode chunk first before inserting into a * tree. don't have to worry about the overflow case because the * starting ino number of a chunk can only get within 255 inodes of max * (NULLAGINO). if it gets closer, the agino number will be illegal as * the agbno will be too large. */ if (verify_aginum(mp, agno, ino)) { do_warn( _("bad starting inode # (%" PRIu64 " (0x%x 0x%x)) in %s rec, skipping rec\n"), lino, agno, ino, inobt_name); *skip = true; return ++suspect; } if (verify_aginum(mp, agno, ino + XFS_INODES_PER_CHUNK - 1)) { do_warn( _("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in %s rec, skipping rec\n"), lino + XFS_INODES_PER_CHUNK - 1, agno, ino + XFS_INODES_PER_CHUNK - 1, inobt_name); *skip = true; return ++suspect; } return suspect; } /* * Process the state of individual inodes in an on-disk inobt record and import * into the appropriate in-core tree based on whether the on-disk tree is * suspect. Return the total and free inode counts based on the record free and * hole masks. */ static int import_single_ino_chunk( xfs_agnumber_t agno, enum inobt_type type, struct xfs_inobt_rec *rp, int suspect, int *p_nfree, int *p_ninodes) { struct ino_tree_node *ino_rec = NULL; const char *inobt_name = inobt_names[type]; xfs_agino_t ino; int j; int nfree; int ninodes; ino = be32_to_cpu(rp->ir_startino); if (!suspect) { if (XFS_INOBT_IS_FREE_DISK(rp, 0)) ino_rec = set_inode_free_alloc(mp, agno, ino); else ino_rec = set_inode_used_alloc(mp, agno, ino); for (j = 1; j < XFS_INODES_PER_CHUNK; j++) { if (XFS_INOBT_IS_FREE_DISK(rp, j)) set_inode_free(ino_rec, j); else set_inode_used(ino_rec, j); } } else { for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { if (XFS_INOBT_IS_FREE_DISK(rp, j)) add_aginode_uncertain(mp, agno, ino + j, 1); else add_aginode_uncertain(mp, agno, ino + j, 0); } } /* * Mark sparse inodes as such in the in-core tree. Verify that sparse * inodes are free and that freecount is consistent with the free mask. */ nfree = ninodes = 0; for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { if (ino_issparse(rp, j)) { if (!suspect && !XFS_INOBT_IS_FREE_DISK(rp, j)) { do_warn( _("ir_holemask/ir_free mismatch, %s chunk %d/%u, holemask 0x%x free 0x%llx\n"), inobt_name, agno, ino, be16_to_cpu(rp->ir_u.sp.ir_holemask), (unsigned long long)be64_to_cpu(rp->ir_free)); suspect++; } if (!suspect && ino_rec) set_inode_sparse(ino_rec, j); } else { /* count fields track non-sparse inos */ if (XFS_INOBT_IS_FREE_DISK(rp, j)) nfree++; ninodes++; } } *p_nfree = nfree; *p_ninodes = ninodes; return suspect; } static int scan_single_ino_chunk( xfs_agnumber_t agno, xfs_inobt_rec_t *rp, int suspect) { xfs_ino_t lino; xfs_agino_t ino; xfs_agblock_t agbno; int j; int nfree; int ninodes; int off; int state; ino_tree_node_t *first_rec, *last_rec; int freecount; bool skip = false; ino = be32_to_cpu(rp->ir_startino); off = XFS_AGINO_TO_OFFSET(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, ino); lino = XFS_AGINO_TO_INO(mp, agno, ino); freecount = inorec_get_freecount(mp, rp); /* * Verify record alignment, start/end inode numbers, etc. */ suspect = verify_single_ino_chunk_align(agno, INOBT, rp, suspect, &skip); if (skip) return suspect; /* * set state of each block containing inodes */ if (off == 0 && !suspect) { for (j = 0; j < XFS_INODES_PER_CHUNK; j += mp->m_sb.sb_inopblock) { /* inodes in sparse chunks don't use blocks */ if (ino_issparse(rp, j)) continue; agbno = XFS_AGINO_TO_AGBNO(mp, ino + j); state = get_bmap(agno, agbno); switch (state) { case XR_E_INO: break; case XR_E_UNKNOWN: case XR_E_INO1: /* seen by rmap */ set_bmap(agno, agbno, XR_E_INO); break; case XR_E_INUSE_FS: case XR_E_INUSE_FS1: if (agno == 0 && ino + j >= first_prealloc_ino && ino + j < last_prealloc_ino) { set_bmap(agno, agbno, XR_E_INO); break; } /* fall through */ default: /* XXX - maybe should mark block a duplicate */ do_warn( _("inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n"), agno, agbno, mp->m_sb.sb_inopblock); return ++suspect; } } } /* * ensure only one avl entry per chunk */ find_inode_rec_range(mp, agno, ino, ino + XFS_INODES_PER_CHUNK, &first_rec, &last_rec); if (first_rec != NULL) { /* * this chunk overlaps with one (or more) * already in the tree */ do_warn( _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n"), lino, agno, ino, agno, first_rec->ino_startnum); suspect++; /* * if the 2 chunks start at the same place, * then we don't have to put this one * in the uncertain list. go to the next one. */ if (first_rec->ino_startnum == ino) return suspect; } /* * Import the state of individual inodes into the appropriate in-core * trees, mark them free or used, and get the resulting total and free * inode counts. */ nfree = ninodes = 0; suspect = import_single_ino_chunk(agno, INOBT, rp, suspect, &nfree, &ninodes); if (nfree != freecount) { do_warn( _("ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"), agno, ino, freecount, nfree); } /* verify sparse record formats have a valid inode count */ if (xfs_sb_version_hassparseinodes(&mp->m_sb) && ninodes != rp->ir_u.sp.ir_count) { do_warn( _("invalid inode count, inode chunk %d/%u, count %d ninodes %d\n"), agno, ino, rp->ir_u.sp.ir_count, ninodes); } return suspect; } static int scan_single_finobt_chunk( xfs_agnumber_t agno, xfs_inobt_rec_t *rp, int suspect) { xfs_ino_t lino; xfs_agino_t ino; xfs_agblock_t agbno; int j; int nfree; int ninodes; int off; int state; ino_tree_node_t *first_rec, *last_rec; int freecount; bool skip = false; ino = be32_to_cpu(rp->ir_startino); off = XFS_AGINO_TO_OFFSET(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, ino); lino = XFS_AGINO_TO_INO(mp, agno, ino); freecount = inorec_get_freecount(mp, rp); /* * Verify record alignment, start/end inode numbers, etc. */ suspect = verify_single_ino_chunk_align(agno, FINOBT, rp, suspect, &skip); if (skip) return suspect; /* * cross check state of each block containing inodes referenced by the * finobt against what we have already scanned from the alloc inobt. */ if (off == 0 && !suspect) { for (j = 0; j < XFS_INODES_PER_CHUNK; j += mp->m_sb.sb_inopblock) { agbno = XFS_AGINO_TO_AGBNO(mp, ino + j); state = get_bmap(agno, agbno); /* sparse inodes should not refer to inode blocks */ if (ino_issparse(rp, j)) { if (state == XR_E_INO) { do_warn( _("sparse inode chunk claims inode block, finobt block - agno %d, bno %d, inopb %d\n"), agno, agbno, mp->m_sb.sb_inopblock); suspect++; } continue; } switch (state) { case XR_E_INO: break; case XR_E_INO1: /* seen by rmap */ set_bmap(agno, agbno, XR_E_INO); break; case XR_E_UNKNOWN: do_warn( _("inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb %d\n"), agno, agbno, mp->m_sb.sb_inopblock); set_bmap(agno, agbno, XR_E_INO); suspect++; break; case XR_E_INUSE_FS: case XR_E_INUSE_FS1: if (agno == 0 && ino + j >= first_prealloc_ino && ino + j < last_prealloc_ino) { do_warn( _("inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb %d\n"), agno, agbno, mp->m_sb.sb_inopblock); set_bmap(agno, agbno, XR_E_INO); suspect++; break; } /* fall through */ default: do_warn( _("inode chunk claims used block, finobt block - agno %d, bno %d, inopb %d\n"), agno, agbno, mp->m_sb.sb_inopblock); return ++suspect; } } } /* * ensure we have an incore entry for each chunk */ find_inode_rec_range(mp, agno, ino, ino + XFS_INODES_PER_CHUNK, &first_rec, &last_rec); if (first_rec) { if (suspect) return suspect; /* * verify consistency between finobt record and incore state */ if (first_rec->ino_startnum != ino) { do_warn( _("finobt rec for ino %" PRIu64 " (%d/%u) does not match existing rec (%d/%d)\n"), lino, agno, ino, agno, first_rec->ino_startnum); return ++suspect; } nfree = ninodes = 0; for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { int isfree = XFS_INOBT_IS_FREE_DISK(rp, j); int issparse = ino_issparse(rp, j); if (!issparse) ninodes++; if (isfree && !issparse) nfree++; /* * inode allocation state should be consistent between * the inobt and finobt */ if (!suspect && isfree != is_inode_free(first_rec, j)) suspect++; if (!suspect && issparse != is_inode_sparse(first_rec, j)) suspect++; } goto check_freecount; } /* * The finobt contains a record that the previous inobt scan never * found. Warn about it and import the inodes into the appropriate * trees. * * Note that this should do the right thing if the previous inobt scan * had added these inodes to the uncertain tree. If the finobt is not * suspect, these inodes should supercede the uncertain ones. Otherwise, * the uncertain tree helpers handle the case where uncertain inodes * already exist. */ do_warn(_("undiscovered finobt record, ino %" PRIu64 " (%d/%u)\n"), lino, agno, ino); nfree = ninodes = 0; suspect = import_single_ino_chunk(agno, FINOBT, rp, suspect, &nfree, &ninodes); check_freecount: /* * Verify that the record freecount matches the actual number of free * inodes counted in the record. Don't increment 'suspect' here, since * we have already verified the allocation state of the individual * inodes against the in-core state. This will have already incremented * 'suspect' if something is wrong. If suspect hasn't been set at this * point, these warnings mean that we have a simple freecount * inconsistency or a stray finobt record (as opposed to a broader tree * corruption). Issue a warning and continue the scan. The final btree * reconstruction will correct this naturally. */ if (nfree != freecount) { do_warn( _("finobt ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"), agno, ino, freecount, nfree); } if (!nfree) { do_warn( _("finobt record with no free inodes, inode chunk %d/%u\n"), agno, ino); } /* verify sparse record formats have a valid inode count */ if (xfs_sb_version_hassparseinodes(&mp->m_sb) && ninodes != rp->ir_u.sp.ir_count) { do_warn( _("invalid inode count, inode chunk %d/%u, count %d ninodes %d\n"), agno, ino, rp->ir_u.sp.ir_count, ninodes); } return suspect; } /* * this one walks the inode btrees sucking the info there into * the incore avl tree. We try and rescue corrupted btree records * to minimize our chances of losing inodes. Inode info from potentially * corrupt sources could be bogus so rather than put the info straight * into the tree, instead we put it on a list and try and verify the * info in the next phase by examining what's on disk. At that point, * we'll be able to figure out what's what and stick the corrected info * into the tree. We do bail out at some point and give up on a subtree * so as to avoid walking randomly all over the ag. * * Note that it's also ok if the free/inuse info wrong, we can correct * that when we examine the on-disk inode. The important thing is to * get the start and alignment of the inode chunks right. Those chunks * that we aren't sure about go into the uncertain list. */ static void scan_inobt( struct xfs_btree_block *block, int level, xfs_agblock_t bno, xfs_agnumber_t agno, int suspect, int isroot, uint32_t magic, void *priv, const struct xfs_buf_ops *ops) { struct aghdr_cnts *agcnts = priv; int i; int numrecs; int state; xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; int hdr_errors; int freecount; struct xfs_ino_geometry *igeo = M_IGEO(mp); hdr_errors = 0; if (be32_to_cpu(block->bb_magic) != magic) { do_warn(_("bad magic # %#x in inobt block %d/%d\n"), be32_to_cpu(block->bb_magic), agno, bno); hdr_errors++; bad_ino_btree = 1; if (suspect) return; } if (be16_to_cpu(block->bb_level) != level) { do_warn(_("expected level %d got %d in inobt block %d/%d\n"), level, be16_to_cpu(block->bb_level), agno, bno); hdr_errors++; bad_ino_btree = 1; if (suspect) return; } /* * check for btree blocks multiply claimed, any unknown/free state * is ok in the bitmap block. */ state = get_bmap(agno, bno); switch (state) { case XR_E_FS_MAP1: /* already been seen by an rmap scan */ case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: set_bmap(agno, bno, XR_E_FS_MAP); break; default: set_bmap(agno, bno, XR_E_MULT); do_warn( _("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), state, agno, bno, suspect); } numrecs = be16_to_cpu(block->bb_numrecs); /* * leaf record in btree */ if (level == 0) { /* check for trashed btree block */ if (numrecs > igeo->inobt_mxr[0]) { numrecs = igeo->inobt_mxr[0]; hdr_errors++; } if (isroot == 0 && numrecs < igeo->inobt_mnr[0]) { numrecs = igeo->inobt_mnr[0]; hdr_errors++; } if (hdr_errors) { bad_ino_btree = 1; do_warn(_("dubious inode btree block header %d/%d\n"), agno, bno); suspect++; } rp = XFS_INOBT_REC_ADDR(mp, block, 1); /* * step through the records, each record points to * a chunk of inodes. The start of inode chunks should * be block-aligned. Each inode btree rec should point * to the start of a block of inodes or the start of a group * of INODES_PER_CHUNK (64) inodes. off is the offset into * the block. skip processing of bogus records. */ for (i = 0; i < numrecs; i++) { freecount = inorec_get_freecount(mp, &rp[i]); if (magic == XFS_IBT_MAGIC || magic == XFS_IBT_CRC_MAGIC) { int icount = XFS_INODES_PER_CHUNK; /* * ir_count holds the inode count for all * records on fs' with sparse inode support */ if (xfs_sb_version_hassparseinodes(&mp->m_sb)) icount = rp[i].ir_u.sp.ir_count; agcnts->agicount += icount; agcnts->agifreecount += freecount; agcnts->ifreecount += freecount; suspect = scan_single_ino_chunk(agno, &rp[i], suspect); } else { /* * the finobt tracks records with free inodes, * so only the free inode count is expected to be * consistent with the agi */ agcnts->fibtfreecount += freecount; suspect = scan_single_finobt_chunk(agno, &rp[i], suspect); } } if (suspect) bad_ino_btree = 1; return; } /* * interior record, continue on */ if (numrecs > igeo->inobt_mxr[1]) { numrecs = igeo->inobt_mxr[1]; hdr_errors++; } if (isroot == 0 && numrecs < igeo->inobt_mnr[1]) { numrecs = igeo->inobt_mnr[1]; hdr_errors++; } pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); /* * don't pass bogus tree flag down further if this block * looked ok. bail out if two levels in a row look bad. */ if (suspect && !hdr_errors) suspect = 0; if (hdr_errors) { bad_ino_btree = 1; if (suspect) return; else suspect++; } for (i = 0; i < numrecs; i++) { if (be32_to_cpu(pp[i]) != 0 && verify_agbno(mp, agno, be32_to_cpu(pp[i]))) scan_sbtree(be32_to_cpu(pp[i]), level, agno, suspect, scan_inobt, 0, magic, priv, ops); } } struct agfl_state { unsigned int count; xfs_agnumber_t agno; }; static int scan_agfl( struct xfs_mount *mp, xfs_agblock_t bno, void *priv) { struct agfl_state *as = priv; if (verify_agbno(mp, as->agno, bno)) set_bmap(as->agno, bno, XR_E_FREE); else do_warn(_("bad agbno %u in agfl, agno %d\n"), bno, as->agno); as->count++; return 0; } static void scan_freelist( xfs_agf_t *agf, struct aghdr_cnts *agcnts) { xfs_buf_t *agflbuf; xfs_agnumber_t agno; struct agfl_state state; agno = be32_to_cpu(agf->agf_seqno); if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp)) set_bmap(agno, XFS_AGFL_BLOCK(mp), XR_E_INUSE_FS); if (be32_to_cpu(agf->agf_flcount) == 0) return; agflbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &xfs_agfl_buf_ops); if (!agflbuf) { do_abort(_("can't read agfl block for ag %d\n"), agno); return; } if (agflbuf->b_error == -EFSBADCRC) do_warn(_("agfl has bad CRC for ag %d\n"), agno); if (no_modify) { /* agf values not fixed in verify_set_agf, so recheck */ if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) || be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) { do_warn(_("agf %d freelist blocks bad, skipping " "freelist scan\n"), agno); return; } } state.count = 0; state.agno = agno; libxfs_agfl_walk(mp, agf, agflbuf, scan_agfl, &state); if (state.count != be32_to_cpu(agf->agf_flcount)) { do_warn(_("freeblk count %d != flcount %d in ag %d\n"), state.count, be32_to_cpu(agf->agf_flcount), agno); } agcnts->fdblocks += state.count; libxfs_putbuf(agflbuf); } static void validate_agf( struct xfs_agf *agf, xfs_agnumber_t agno, struct aghdr_cnts *agcnts) { xfs_agblock_t bno; uint32_t magic; bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]); if (bno != 0 && verify_agbno(mp, agno, bno)) { magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC; scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]), agno, 0, scan_allocbt, 1, magic, agcnts, &xfs_bnobt_buf_ops); } else { do_warn(_("bad agbno %u for btbno root, agno %d\n"), bno, agno); } bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]); if (bno != 0 && verify_agbno(mp, agno, bno)) { magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTC_CRC_MAGIC : XFS_ABTC_MAGIC; scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]), agno, 0, scan_allocbt, 1, magic, agcnts, &xfs_cntbt_buf_ops); } else { do_warn(_("bad agbno %u for btbcnt root, agno %d\n"), bno, agno); } if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { struct rmap_priv priv; memset(&priv.high_key, 0xFF, sizeof(priv.high_key)); priv.high_key.rm_blockcount = 0; priv.agcnts = agcnts; priv.last_rec.rm_owner = XFS_RMAP_OWN_UNKNOWN; priv.nr_blocks = 0; bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]); if (bno != 0 && verify_agbno(mp, agno, bno)) { scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]), agno, 0, scan_rmapbt, 1, XFS_RMAP_CRC_MAGIC, &priv, &xfs_rmapbt_buf_ops); if (be32_to_cpu(agf->agf_rmap_blocks) != priv.nr_blocks) do_warn(_("bad rmapbt block count %u, saw %u\n"), priv.nr_blocks, be32_to_cpu(agf->agf_rmap_blocks)); } else { do_warn(_("bad agbno %u for rmapbt root, agno %d\n"), bno, agno); rmap_avoid_check(); } } if (xfs_sb_version_hasreflink(&mp->m_sb)) { bno = be32_to_cpu(agf->agf_refcount_root); if (bno != 0 && verify_agbno(mp, agno, bno)) { struct refc_priv priv; memset(&priv, 0, sizeof(priv)); scan_sbtree(bno, be32_to_cpu(agf->agf_refcount_level), agno, 0, scan_refcbt, 1, XFS_REFC_CRC_MAGIC, &priv, &xfs_refcountbt_buf_ops); if (be32_to_cpu(agf->agf_refcount_blocks) != priv.nr_blocks) do_warn(_("bad refcountbt block count %u, saw %u\n"), priv.nr_blocks, be32_to_cpu(agf->agf_refcount_blocks)); } else { do_warn(_("bad agbno %u for refcntbt root, agno %d\n"), bno, agno); refcount_avoid_check(); } } if (be32_to_cpu(agf->agf_freeblks) != agcnts->agffreeblks) { do_warn(_("agf_freeblks %u, counted %u in ag %u\n"), be32_to_cpu(agf->agf_freeblks), agcnts->agffreeblks, agno); } if (be32_to_cpu(agf->agf_longest) != agcnts->agflongest) { do_warn(_("agf_longest %u, counted %u in ag %u\n"), be32_to_cpu(agf->agf_longest), agcnts->agflongest, agno); } if (xfs_sb_version_haslazysbcount(&mp->m_sb) && be32_to_cpu(agf->agf_btreeblks) != agcnts->agfbtreeblks) { do_warn(_("agf_btreeblks %u, counted %" PRIu64 " in ag %u\n"), be32_to_cpu(agf->agf_btreeblks), agcnts->agfbtreeblks, agno); } } static void validate_agi( struct xfs_agi *agi, xfs_agnumber_t agno, struct aghdr_cnts *agcnts) { xfs_agblock_t bno; int i; uint32_t magic; bno = be32_to_cpu(agi->agi_root); if (bno != 0 && verify_agbno(mp, agno, bno)) { magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC : XFS_IBT_MAGIC; scan_sbtree(bno, be32_to_cpu(agi->agi_level), agno, 0, scan_inobt, 1, magic, agcnts, &xfs_inobt_buf_ops); } else { do_warn(_("bad agbno %u for inobt root, agno %d\n"), be32_to_cpu(agi->agi_root), agno); } if (xfs_sb_version_hasfinobt(&mp->m_sb)) { bno = be32_to_cpu(agi->agi_free_root); if (bno != 0 && verify_agbno(mp, agno, bno)) { magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC; scan_sbtree(bno, be32_to_cpu(agi->agi_free_level), agno, 0, scan_inobt, 1, magic, agcnts, &xfs_finobt_buf_ops); } else { do_warn(_("bad agbno %u for finobt root, agno %d\n"), be32_to_cpu(agi->agi_free_root), agno); } } if (be32_to_cpu(agi->agi_count) != agcnts->agicount) { do_warn(_("agi_count %u, counted %u in ag %u\n"), be32_to_cpu(agi->agi_count), agcnts->agicount, agno); } if (be32_to_cpu(agi->agi_freecount) != agcnts->agifreecount) { do_warn(_("agi_freecount %u, counted %u in ag %u\n"), be32_to_cpu(agi->agi_freecount), agcnts->agifreecount, agno); } if (xfs_sb_version_hasfinobt(&mp->m_sb) && be32_to_cpu(agi->agi_freecount) != agcnts->fibtfreecount) { do_warn(_("agi_freecount %u, counted %u in ag %u finobt\n"), be32_to_cpu(agi->agi_freecount), agcnts->fibtfreecount, agno); } for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { xfs_agino_t agino = be32_to_cpu(agi->agi_unlinked[i]); if (agino != NULLAGINO) { do_warn( _("agi unlinked bucket %d is %u in ag %u (inode=%" PRIu64 ")\n"), i, agino, agno, XFS_AGINO_TO_INO(mp, agno, agino)); } } } /* * Scan an AG for obvious corruption. */ static void scan_ag( struct workqueue*wq, xfs_agnumber_t agno, void *arg) { struct aghdr_cnts *agcnts = arg; struct xfs_agf *agf; struct xfs_buf *agfbuf = NULL; int agf_dirty = 0; struct xfs_agi *agi; struct xfs_buf *agibuf = NULL; int agi_dirty = 0; struct xfs_sb *sb = NULL; struct xfs_buf *sbbuf = NULL; int sb_dirty = 0; int status; char *objname = NULL; sb = (struct xfs_sb *)calloc(BBTOB(XFS_FSS_TO_BB(mp, 1)), 1); if (!sb) { do_error(_("can't allocate memory for superblock\n")); return; } sbbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_FSS_TO_BB(mp, 1), 0, &xfs_sb_buf_ops); if (!sbbuf) { objname = _("root superblock"); goto out_free_sb; } libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbbuf)); agfbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &xfs_agf_buf_ops); if (!agfbuf) { objname = _("agf block"); goto out_free_sbbuf; } agf = XFS_BUF_TO_AGF(agfbuf); agibuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &xfs_agi_buf_ops); if (!agibuf) { objname = _("agi block"); goto out_free_agfbuf; } agi = XFS_BUF_TO_AGI(agibuf); /* fix up bad ag headers */ status = verify_set_agheader(mp, sbbuf, sb, agf, agi, agno); if (status & XR_AG_SB_SEC) { if (!no_modify) sb_dirty = 1; /* * clear bad sector bit because we don't want * to skip further processing. we just want to * ensure that we write out the modified sb buffer. */ status &= ~XR_AG_SB_SEC; } if (status & XR_AG_SB) { if (!no_modify) { do_warn(_("reset bad sb for ag %d\n"), agno); sb_dirty = 1; } else { do_warn(_("would reset bad sb for ag %d\n"), agno); } } if (status & XR_AG_AGF) { if (!no_modify) { do_warn(_("reset bad agf for ag %d\n"), agno); agf_dirty = 1; } else { do_warn(_("would reset bad agf for ag %d\n"), agno); } } if (status & XR_AG_AGI) { if (!no_modify) { do_warn(_("reset bad agi for ag %d\n"), agno); agi_dirty = 1; } else { do_warn(_("would reset bad agi for ag %d\n"), agno); } } if (status && no_modify) { do_warn(_("bad uncorrected agheader %d, skipping ag...\n"), agno); goto out_free_agibuf; } scan_freelist(agf, agcnts); validate_agf(agf, agno, agcnts); validate_agi(agi, agno, agcnts); ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify)); ASSERT(agf_dirty == 0 || (agf_dirty && !no_modify)); ASSERT(sb_dirty == 0 || (sb_dirty && !no_modify)); /* * Only pay attention to CRC/verifier errors if we can correct them. * Note that we can get uncorrected EFSCORRUPTED errors here because * the verifier will flag on out of range values that we can't correct * until phase 5 when we have all the information necessary to rebuild * the freespace/inode btrees. We can correct bad CRC errors * immediately, though. */ if (!no_modify) { agi_dirty += (agibuf->b_error == -EFSBADCRC); agf_dirty += (agfbuf->b_error == -EFSBADCRC); sb_dirty += (sbbuf->b_error == -EFSBADCRC); } if (agi_dirty && !no_modify) libxfs_writebuf(agibuf, 0); else libxfs_putbuf(agibuf); if (agf_dirty && !no_modify) libxfs_writebuf(agfbuf, 0); else libxfs_putbuf(agfbuf); if (sb_dirty && !no_modify) { if (agno == 0) memcpy(&mp->m_sb, sb, sizeof(xfs_sb_t)); libxfs_sb_to_disk(XFS_BUF_TO_SBP(sbbuf), sb); libxfs_writebuf(sbbuf, 0); } else libxfs_putbuf(sbbuf); free(sb); PROG_RPT_INC(prog_rpt_done[agno], 1); #ifdef XR_INODE_TRACE print_inode_list(i); #endif return; out_free_agibuf: libxfs_putbuf(agibuf); out_free_agfbuf: libxfs_putbuf(agfbuf); out_free_sbbuf: libxfs_putbuf(sbbuf); out_free_sb: free(sb); if (objname) do_error(_("can't get %s for ag %d\n"), objname, agno); } void scan_ags( struct xfs_mount *mp, int scan_threads) { struct aghdr_cnts *agcnts; uint64_t fdblocks = 0; uint64_t icount = 0; uint64_t ifreecount = 0; uint64_t usedblocks = 0; xfs_agnumber_t i; struct workqueue wq; agcnts = malloc(mp->m_sb.sb_agcount * sizeof(*agcnts)); if (!agcnts) { do_abort(_("no memory for ag header counts\n")); return; } memset(agcnts, 0, mp->m_sb.sb_agcount * sizeof(*agcnts)); create_work_queue(&wq, mp, scan_threads); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&wq, scan_ag, i, &agcnts[i]); destroy_work_queue(&wq); /* tally up the counts */ for (i = 0; i < mp->m_sb.sb_agcount; i++) { fdblocks += agcnts[i].fdblocks; icount += agcnts[i].agicount; ifreecount += agcnts[i].ifreecount; usedblocks += agcnts[i].usedblocks; } free(agcnts); /* * Validate that our manual counts match the superblock. */ if (mp->m_sb.sb_icount != icount) { do_warn(_("sb_icount %" PRIu64 ", counted %" PRIu64 "\n"), mp->m_sb.sb_icount, icount); } if (mp->m_sb.sb_ifree != ifreecount) { do_warn(_("sb_ifree %" PRIu64 ", counted %" PRIu64 "\n"), mp->m_sb.sb_ifree, ifreecount); } if (mp->m_sb.sb_fdblocks != fdblocks) { do_warn(_("sb_fdblocks %" PRIu64 ", counted %" PRIu64 "\n"), mp->m_sb.sb_fdblocks, fdblocks); } if (usedblocks && usedblocks != mp->m_sb.sb_dblocks - fdblocks) { do_warn(_("used blocks %" PRIu64 ", counted %" PRIu64 "\n"), mp->m_sb.sb_dblocks - fdblocks, usedblocks); } } xfsprogs-5.3.0/repair/scan.h0000644000175000017500000000225013435336037015631 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XR_SCAN_H #define _XR_SCAN_H struct blkmap; void set_mp(xfs_mount_t *mpp); int scan_lbtree( xfs_fsblock_t root, int nlevels, int (*func)(struct xfs_btree_block *block, int level, int type, int whichfork, xfs_fsblock_t bno, xfs_ino_t ino, xfs_rfsblock_t *tot, uint64_t *nex, struct blkmap **blkmapp, bmap_cursor_t *bm_cursor, int isroot, int check_dups, int *dirty, uint64_t magic), int type, int whichfork, xfs_ino_t ino, xfs_rfsblock_t *tot, uint64_t *nex, struct blkmap **blkmapp, bmap_cursor_t *bm_cursor, int isroot, int check_dups, uint64_t magic, const struct xfs_buf_ops *ops); int scan_bmapbt( struct xfs_btree_block *block, int level, int type, int whichfork, xfs_fsblock_t bno, xfs_ino_t ino, xfs_rfsblock_t *tot, uint64_t *nex, struct blkmap **blkmapp, bmap_cursor_t *bm_cursor, int isroot, int check_dups, int *dirty, uint64_t magic); void scan_ags( struct xfs_mount *mp, int scan_threads); #endif /* _XR_SCAN_H */ xfsprogs-5.3.0/repair/slab.c0000644000175000017500000002321513570057155015626 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include #include "slab.h" #undef SLAB_DEBUG #ifdef SLAB_DEBUG # define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) #else # define dbg_printf(f, a...) #endif /* * Slab Arrays and Bags * * The slab array is a dynamically growable linear array. Internally it * maintains a list of slabs of increasing size; when a slab fills up, another * is allocated. Each slab is sorted individually, which means that one must * use an iterator to walk the entire logical array, sorted order or otherwise. * Array items can neither be removed nor accessed randomly, since (at the * moment) the only user of them (storing reverse mappings) doesn't need either * piece. Pointers are not stable across sort operations. * * A bag is a collection of pointers. The bag can be added to or removed from * arbitrarily, and the bag items can be iterated. Bags are used to process * rmaps into refcount btree entries. */ /* * Slabs -- each slab_hdr holds an array of items; when a slab_hdr fills up, we * allocate a new one and add to that one. The slab object coordinates the * slab_hdrs. */ /* Each slab holds at least 4096 items */ #define MIN_SLAB_NR 4096 /* and cannot be larger than 128M */ #define MAX_SLAB_SIZE (128 * 1048576) struct xfs_slab_hdr { size_t sh_nr; size_t sh_inuse; /* items in use */ struct xfs_slab_hdr *sh_next; /* next slab hdr */ /* objects follow */ }; struct xfs_slab { size_t s_item_sz; /* item size */ size_t s_nr_slabs; /* # of slabs */ size_t s_nr_items; /* # of items */ struct xfs_slab_hdr *s_first; /* first slab header */ struct xfs_slab_hdr *s_last; /* last sh_next pointer */ }; /* * Slab cursors -- each slab_hdr_cursor tracks a slab_hdr; the slab_cursor * tracks the slab_hdr_cursors. If a compare_fn is specified, the cursor * returns objects in increasing order (if you've previously sorted the * slabs with qsort_slab()). If compare_fn == NULL, it returns slab items * in order. */ struct xfs_slab_hdr_cursor { struct xfs_slab_hdr *hdr; /* a slab header */ size_t loc; /* where we are in the slab */ }; typedef int (*xfs_slab_compare_fn)(const void *, const void *); struct xfs_slab_cursor { size_t nr; /* # of per-slab cursors */ struct xfs_slab *slab; /* pointer to the slab */ struct xfs_slab_hdr_cursor *last_hcur; /* last header we took from */ xfs_slab_compare_fn compare_fn; /* compare items */ struct xfs_slab_hdr_cursor hcur[0]; /* per-slab cursors */ }; /* * Bags -- each bag is an array of pointers items; when a bag fills up, we * resize it. */ #define MIN_BAG_SIZE 4096 struct xfs_bag { size_t bg_nr; /* number of pointers */ size_t bg_inuse; /* number of slots in use */ void **bg_ptrs; /* pointers */ }; #define BAG_END(bag) (&(bag)->bg_ptrs[(bag)->bg_nr]) /* * Create a slab to hold some objects of a particular size. */ int init_slab( struct xfs_slab **slab, size_t item_size) { struct xfs_slab *ptr; ptr = calloc(1, sizeof(struct xfs_slab)); if (!ptr) return -ENOMEM; ptr->s_item_sz = item_size; ptr->s_last = NULL; *slab = ptr; return 0; } /* * Frees a slab. */ void free_slab( struct xfs_slab **slab) { struct xfs_slab *ptr; struct xfs_slab_hdr *hdr; struct xfs_slab_hdr *nhdr; ptr = *slab; if (!ptr) return; hdr = ptr->s_first; while (hdr) { nhdr = hdr->sh_next; free(hdr); hdr = nhdr; } free(ptr); *slab = NULL; } static void * slab_ptr( struct xfs_slab *slab, struct xfs_slab_hdr *hdr, size_t idx) { char *p; ASSERT(idx < hdr->sh_inuse); p = (char *)(hdr + 1); p += slab->s_item_sz * idx; return p; } /* * Add an item to the slab. */ int slab_add( struct xfs_slab *slab, void *item) { struct xfs_slab_hdr *hdr; void *p; hdr = slab->s_last; if (!hdr || hdr->sh_inuse == hdr->sh_nr) { size_t n; n = (hdr ? hdr->sh_nr * 2 : MIN_SLAB_NR); if (n * slab->s_item_sz > MAX_SLAB_SIZE) n = MAX_SLAB_SIZE / slab->s_item_sz; hdr = malloc(sizeof(struct xfs_slab_hdr) + (n * slab->s_item_sz)); if (!hdr) return -ENOMEM; hdr->sh_nr = n; hdr->sh_inuse = 0; hdr->sh_next = NULL; if (slab->s_last) slab->s_last->sh_next = hdr; if (!slab->s_first) slab->s_first = hdr; slab->s_last = hdr; slab->s_nr_slabs++; } hdr->sh_inuse++; p = slab_ptr(slab, hdr, hdr->sh_inuse - 1); memcpy(p, item, slab->s_item_sz); slab->s_nr_items++; return 0; } #include "threads.h" struct qsort_slab { struct xfs_slab *slab; struct xfs_slab_hdr *hdr; int (*compare_fn)(const void *, const void *); }; static void qsort_slab_helper( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct qsort_slab *qs = arg; qsort(slab_ptr(qs->slab, qs->hdr, 0), qs->hdr->sh_inuse, qs->slab->s_item_sz, qs->compare_fn); free(qs); } /* * Sort the items in the slab. Do not run this method if there are any * cursors holding on to the slab. */ void qsort_slab( struct xfs_slab *slab, int (*compare_fn)(const void *, const void *)) { struct workqueue wq; struct xfs_slab_hdr *hdr; struct qsort_slab *qs; /* * If we don't have that many slabs, we're probably better * off skipping all the thread overhead. */ if (slab->s_nr_slabs <= 4) { hdr = slab->s_first; while (hdr) { qsort(slab_ptr(slab, hdr, 0), hdr->sh_inuse, slab->s_item_sz, compare_fn); hdr = hdr->sh_next; } return; } create_work_queue(&wq, NULL, platform_nproc()); hdr = slab->s_first; while (hdr) { qs = malloc(sizeof(struct qsort_slab)); qs->slab = slab; qs->hdr = hdr; qs->compare_fn = compare_fn; queue_work(&wq, qsort_slab_helper, 0, qs); hdr = hdr->sh_next; } destroy_work_queue(&wq); } /* * init_slab_cursor() -- Create a slab cursor to iterate the slab items. * * @slab: The slab. * @compare_fn: If specified, use this function to return items in ascending order. * @cur: The new cursor. */ int init_slab_cursor( struct xfs_slab *slab, int (*compare_fn)(const void *, const void *), struct xfs_slab_cursor **cur) { struct xfs_slab_cursor *c; struct xfs_slab_hdr_cursor *hcur; struct xfs_slab_hdr *hdr; c = malloc(sizeof(struct xfs_slab_cursor) + (sizeof(struct xfs_slab_hdr_cursor) * slab->s_nr_slabs)); if (!c) return -ENOMEM; c->nr = slab->s_nr_slabs; c->slab = slab; c->compare_fn = compare_fn; c->last_hcur = NULL; hcur = (struct xfs_slab_hdr_cursor *)(c + 1); hdr = slab->s_first; while (hdr) { hcur->hdr = hdr; hcur->loc = 0; hcur++; hdr = hdr->sh_next; } *cur = c; return 0; } /* * Free the slab cursor. */ void free_slab_cursor( struct xfs_slab_cursor **cur) { if (!*cur) return; free(*cur); *cur = NULL; } /* * Return the smallest item in the slab, without advancing the iterator. * The slabs must be sorted prior to the creation of the cursor. */ void * peek_slab_cursor( struct xfs_slab_cursor *cur) { struct xfs_slab_hdr_cursor *hcur; void *p = NULL; void *q; size_t i; cur->last_hcur = NULL; /* no compare function; inorder traversal */ if (!cur->compare_fn) { if (!cur->last_hcur) cur->last_hcur = &cur->hcur[0]; hcur = cur->last_hcur; while (hcur < &cur->hcur[cur->nr] && hcur->loc >= hcur->hdr->sh_inuse) hcur++; if (hcur == &cur->hcur[cur->nr]) return NULL; p = slab_ptr(cur->slab, hcur->hdr, hcur->loc); cur->last_hcur = hcur; return p; } /* otherwise return things in increasing order */ for (i = 0, hcur = &cur->hcur[i]; i < cur->nr; i++, hcur++) { if (hcur->loc >= hcur->hdr->sh_inuse) continue; q = slab_ptr(cur->slab, hcur->hdr, hcur->loc); if (!p || cur->compare_fn(p, q) > 0) { p = q; cur->last_hcur = hcur; } } return p; } /* * After a peek operation, advance the cursor. */ void advance_slab_cursor( struct xfs_slab_cursor *cur) { ASSERT(cur->last_hcur); cur->last_hcur->loc++; } /* * Retrieve the next item in the slab and advance the cursor. */ void * pop_slab_cursor( struct xfs_slab_cursor *cur) { void *p; p = peek_slab_cursor(cur); if (p) advance_slab_cursor(cur); return p; } /* * Return the number of items in the slab. */ size_t slab_count( struct xfs_slab *slab) { return slab->s_nr_items; } /* * Create a bag to point to some objects. */ int init_bag( struct xfs_bag **bag) { struct xfs_bag *ptr; ptr = calloc(1, sizeof(struct xfs_bag)); if (!ptr) return -ENOMEM; ptr->bg_ptrs = calloc(MIN_BAG_SIZE, sizeof(void *)); if (!ptr->bg_ptrs) { free(ptr); return -ENOMEM; } ptr->bg_nr = MIN_BAG_SIZE; *bag = ptr; return 0; } /* * Free a bag of pointers. */ void free_bag( struct xfs_bag **bag) { struct xfs_bag *ptr; ptr = *bag; if (!ptr) return; free(ptr->bg_ptrs); free(ptr); *bag = NULL; } /* * Add an object to the pointer bag. */ int bag_add( struct xfs_bag *bag, void *ptr) { void **p, **x; p = &bag->bg_ptrs[bag->bg_inuse]; if (p == BAG_END(bag)) { /* No free space, alloc more pointers */ size_t nr; nr = bag->bg_nr * 2; x = realloc(bag->bg_ptrs, nr * sizeof(void *)); if (!x) return -ENOMEM; bag->bg_ptrs = x; memset(BAG_END(bag), 0, bag->bg_nr * sizeof(void *)); bag->bg_nr = nr; } bag->bg_ptrs[bag->bg_inuse] = ptr; bag->bg_inuse++; return 0; } /* * Remove a pointer from a bag. */ int bag_remove( struct xfs_bag *bag, size_t nr) { ASSERT(nr < bag->bg_inuse); memmove(&bag->bg_ptrs[nr], &bag->bg_ptrs[nr + 1], (bag->bg_inuse - nr - 1) * sizeof(void *)); bag->bg_inuse--; return 0; } /* * Return the number of items in a bag. */ size_t bag_count( struct xfs_bag *bag) { return bag->bg_inuse; } /* * Return the nth item in a bag. */ void * bag_item( struct xfs_bag *bag, size_t nr) { if (nr >= bag->bg_inuse) return NULL; return bag->bg_ptrs[nr]; } xfsprogs-5.3.0/repair/slab.h0000644000175000017500000000273713435336037015640 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef SLAB_H_ #define SLAB_H_ struct xfs_slab; struct xfs_slab_cursor; extern int init_slab(struct xfs_slab **, size_t); extern void free_slab(struct xfs_slab **); extern int slab_add(struct xfs_slab *, void *); extern void qsort_slab(struct xfs_slab *, int (*)(const void *, const void *)); extern size_t slab_count(struct xfs_slab *); extern int init_slab_cursor(struct xfs_slab *, int (*)(const void *, const void *), struct xfs_slab_cursor **); extern void free_slab_cursor(struct xfs_slab_cursor **); extern void *peek_slab_cursor(struct xfs_slab_cursor *); extern void advance_slab_cursor(struct xfs_slab_cursor *); extern void *pop_slab_cursor(struct xfs_slab_cursor *); struct xfs_bag; extern int init_bag(struct xfs_bag **); extern void free_bag(struct xfs_bag **); extern int bag_add(struct xfs_bag *, void *); extern int bag_remove(struct xfs_bag *, size_t); extern size_t bag_count(struct xfs_bag *); extern void *bag_item(struct xfs_bag *, size_t); #define foreach_bag_ptr(bag, idx, ptr) \ for ((idx) = 0, (ptr) = bag_item((bag), (idx)); \ (idx) < bag_count(bag); \ (idx)++, (ptr) = bag_item((bag), (idx))) #define foreach_bag_ptr_reverse(bag, idx, ptr) \ for ((idx) = bag_count(bag) - 1, (ptr) = bag_item((bag), (idx)); \ (ptr) != NULL; \ (idx)--, (ptr) = bag_item((bag), (idx))) #endif /* SLAB_H_ */ xfsprogs-5.3.0/repair/threads.c0000644000175000017500000000223613570057155016337 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #include "libxfs.h" #include #include #include "threads.h" #include "err_protos.h" #include "protos.h" #include "globals.h" void thread_init(void) { sigset_t blocked; /* * block delivery of progress report signal to all threads */ sigemptyset(&blocked); sigaddset(&blocked, SIGHUP); sigaddset(&blocked, SIGALRM); pthread_sigmask(SIG_BLOCK, &blocked, NULL); } void create_work_queue( struct workqueue *wq, struct xfs_mount *mp, unsigned int nworkers) { int err; err = -workqueue_create(wq, mp, nworkers); if (err) do_error(_("cannot create worker threads, error = [%d] %s\n"), err, strerror(err)); } void queue_work( struct workqueue *wq, workqueue_func_t func, xfs_agnumber_t agno, void *arg) { int err; err = -workqueue_add(wq, func, agno, arg); if (err) do_error(_("cannot allocate worker item, error = [%d] %s\n"), err, strerror(err)); } void destroy_work_queue( struct workqueue *wq) { int err; err = -workqueue_terminate(wq); if (err) do_error(_("cannot terminate worker item, error = [%d] %s\n"), err, strerror(err)); workqueue_destroy(wq); } xfsprogs-5.3.0/repair/threads.h0000644000175000017500000000067413570057155016350 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 #ifndef _XFS_REPAIR_THREADS_H_ #define _XFS_REPAIR_THREADS_H_ #include "libfrog/workqueue.h" void thread_init(void); void create_work_queue( struct workqueue *wq, struct xfs_mount *mp, unsigned int nworkers); void queue_work( struct workqueue *wq, workqueue_func_t func, xfs_agnumber_t agno, void *arg); void destroy_work_queue( struct workqueue *wq); #endif /* _XFS_REPAIR_THREADS_H_ */ xfsprogs-5.3.0/repair/versions.c0000644000175000017500000001107413435336037016554 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "err_protos.h" #include "globals.h" #include "versions.h" /* * filesystem feature global vars, set to 1 if the feature * is on, 0 otherwise */ int fs_attributes; int fs_attributes2; int fs_inode_nlink; int fs_quotas; int fs_aligned_inodes; int fs_sb_feature_bits; int fs_has_extflgbit; /* * inode chunk alignment, fsblocks */ xfs_extlen_t fs_ino_alignment; void update_sb_version(xfs_mount_t *mp) { xfs_sb_t *sb; sb = &mp->m_sb; if (fs_attributes && !xfs_sb_version_hasattr(sb)) xfs_sb_version_addattr(sb); if (fs_attributes2 && !xfs_sb_version_hasattr2(sb)) xfs_sb_version_addattr2(sb); /* V2 inode conversion is now always going to happen */ if (!(sb->sb_versionnum & XFS_SB_VERSION_NLINKBIT)) sb->sb_versionnum |= XFS_SB_VERSION_NLINKBIT; /* * fix up the superblock version number and feature bits, * turn off quota bits and flags if the filesystem doesn't * have quotas. */ if (fs_quotas) { if (!xfs_sb_version_hasquota(sb)) xfs_sb_version_addquota(sb); /* * protect against stray bits in the quota flag field */ if (sb->sb_qflags & ~XFS_MOUNT_QUOTA_ALL) { /* * update the incore superblock, if we're in * no_modify mode, it'll never get flushed out * so this is ok. */ do_warn(_("bogus quota flags 0x%x set in superblock"), sb->sb_qflags & ~XFS_MOUNT_QUOTA_ALL); sb->sb_qflags &= XFS_MOUNT_QUOTA_ALL; if (!no_modify) do_warn(_(", bogus flags will be cleared\n")); else do_warn(_(", bogus flags would be cleared\n")); } } else { sb->sb_qflags = 0; if (xfs_sb_version_hasquota(sb)) { lost_quotas = 1; sb->sb_versionnum &= ~XFS_SB_VERSION_QUOTABIT; } } if (!fs_aligned_inodes && xfs_sb_version_hasalign(sb)) sb->sb_versionnum &= ~XFS_SB_VERSION_ALIGNBIT; } /* * returns 0 if things are fine, 1 if we don't understand * this superblock version. Sets superblock geometry-dependent * global variables. */ int parse_sb_version(xfs_sb_t *sb) { fs_attributes = 0; fs_attributes2 = 0; fs_inode_nlink = 1; fs_quotas = 0; fs_aligned_inodes = 0; fs_sb_feature_bits = 0; fs_ino_alignment = 0; fs_has_extflgbit = 1; have_uquotino = 0; have_gquotino = 0; have_pquotino = 0; if (sb->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) { do_warn(_("Shared Version bit set. Not supported. Ever.\n")); return 1; } /* * ok, check to make sure that the sb isn't newer * than we are */ if (!xfs_sb_good_version(sb)) { do_warn(_("WARNING: unknown superblock version %d\n"), XFS_SB_VERSION_NUM(sb)); do_warn( _("This filesystem contains features not understood by this program.\n")); return(1); } if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_4) fs_sb_feature_bits = 1; /* Look for V5 feature flags we don't know about */ if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && (xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN) || xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN))) { do_warn( _("Superblock has unknown compat/rocompat/incompat features (0x%x/0x%x/0x%x).\n" "Using a more recent xfs_repair is recommended.\n"), sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN, sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN, sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN); return 1; } if (xfs_sb_version_hasattr(sb)) fs_attributes = 1; if (xfs_sb_version_hasattr2(sb)) fs_attributes2 = 1; if (!(sb->sb_versionnum & XFS_SB_VERSION_NLINKBIT)) { if (!no_modify) { do_warn( _("WARNING: you have a V1 inode filesystem. It will be converted to a\n" "\tversion 2 inode filesystem. If you do not want this, run an older\n" "\tversion of xfs_repair.\n")); } else { do_warn( _("WARNING: you have a V1 inode filesystem. It would be converted to a\n" "\tversion 2 inode filesystem. If you do not want this, run an older\n" "\tversion of xfs_repair.\n")); } } if (xfs_sb_version_hasquota(sb)) { fs_quotas = 1; if (sb->sb_uquotino != 0 && sb->sb_uquotino != NULLFSINO) have_uquotino = 1; if (sb->sb_gquotino != 0 && sb->sb_gquotino != NULLFSINO) have_gquotino = 1; if (sb->sb_pquotino != 0 && sb->sb_pquotino != NULLFSINO) have_pquotino = 1; } if (xfs_sb_version_hasalign(sb)) { fs_aligned_inodes = 1; fs_ino_alignment = sb->sb_inoalignmt; } /* * calculate maximum file offset for this geometry */ fs_max_file_offset = 0x7fffffffffffffffLL >> sb->sb_blocklog; return(0); } xfsprogs-5.3.0/repair/versions.h0000644000175000017500000000152313435336037016557 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #ifndef _XR_VERSIONS_H #define _XR_VERSIONS_H #ifndef EXTERN #define EXTERN extern #endif /* EXTERN */ /* * filesystem feature global vars, set to 1 if the feature * is on, 0 otherwise */ extern int fs_attributes; extern int fs_attributes2; extern int fs_inode_nlink; extern int fs_quotas; extern int fs_aligned_inodes; extern int fs_sb_feature_bits; extern int fs_has_extflgbit; /* * inode chunk alignment, fsblocks */ extern xfs_extlen_t fs_ino_alignment; /* * modify superblock to reflect current state of global fs * feature vars above */ void update_sb_version(xfs_mount_t *mp); /* * parse current sb to set above feature vars */ int parse_sb_version(xfs_sb_t *sb); #endif /* _XR_VERSIONS_H */ xfsprogs-5.3.0/repair/xfs_repair.c0000644000175000017500000006740413570057155017057 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libxlog.h" #include #include "xfs_multidisk.h" #include "avl.h" #include "libfrog/avl64.h" #include "globals.h" #include "versions.h" #include "agheader.h" #include "protos.h" #include "incore.h" #include "err_protos.h" #include "prefetch.h" #include "threads.h" #include "progress.h" #include "dinode.h" #include "slab.h" #include "rmap.h" #include "libfrog/fsgeom.h" #include "libfrog/platform.h" /* * option tables for getsubopt calls */ /* * -o: user-supplied override options */ enum o_opt_nums { ASSUME_XFS = 0, IHASH_SIZE, BHASH_SIZE, AG_STRIDE, FORCE_GEO, PHASE2_THREADS, O_MAX_OPTS, }; static char *o_opts[] = { [ASSUME_XFS] = "assume_xfs", [IHASH_SIZE] = "ihash", [BHASH_SIZE] = "bhash", [AG_STRIDE] = "ag_stride", [FORCE_GEO] = "force_geometry", [PHASE2_THREADS] = "phase2_threads", [O_MAX_OPTS] = NULL, }; /* * -c: conversion options */ enum c_opt_nums { CONVERT_LAZY_COUNT = 0, C_MAX_OPTS, }; static char *c_opts[] = { [CONVERT_LAZY_COUNT] = "lazycount", [C_MAX_OPTS] = NULL, }; static int bhash_option_used; static long max_mem_specified; /* in megabytes */ static int phase2_threads = 32; static bool report_corrected; static void usage(void) { do_warn(_( "Usage: %s [options] device\n" "\n" "Options:\n" " -f The device is a file\n" " -L Force log zeroing. Do this as a last resort.\n" " -l logdev Specifies the device where the external log resides.\n" " -m maxmem Maximum amount of memory to be used in megabytes.\n" " -n No modify mode, just checks the filesystem for damage.\n" " (Cannot be used together with -e.)\n" " -P Disables prefetching.\n" " -r rtdev Specifies the device where the realtime section resides.\n" " -v Verbose output.\n" " -c subopts Change filesystem parameters - use xfs_admin.\n" " -o subopts Override default behaviour, refer to man page.\n" " -t interval Reporting interval in seconds.\n" " -d Repair dangerously.\n" " -e Exit with a non-zero code if any errors were repaired.\n" " (Cannot be used together with -n.)\n" " -V Reports version and exits.\n"), progname); exit(1); } char * err_string(int err_code) { static char *err_message[XR_BAD_ERR_CODE]; static int done; if (!done) { err_message[XR_OK] = _("no error"); err_message[XR_BAD_MAGIC] = _("bad magic number"); err_message[XR_BAD_BLOCKSIZE] = _("bad blocksize field"); err_message[XR_BAD_BLOCKLOG] = _("bad blocksize log field"); err_message[XR_BAD_VERSION] = _("bad or unsupported version"); err_message[XR_BAD_INPROGRESS] = _("filesystem mkfs-in-progress bit set"); err_message[XR_BAD_FS_SIZE_DATA] = _("inconsistent filesystem geometry information"); err_message[XR_BAD_INO_SIZE_DATA] = _("bad inode size or inconsistent with number of inodes/block"), err_message[XR_BAD_SECT_SIZE_DATA] = _("bad sector size"); err_message[XR_AGF_GEO_MISMATCH] = _("AGF geometry info conflicts with filesystem geometry"); err_message[XR_AGI_GEO_MISMATCH] = _("AGI geometry info conflicts with filesystem geometry"); err_message[XR_SB_GEO_MISMATCH] = _("AG superblock geometry info conflicts with filesystem geometry"); err_message[XR_EOF] = _("attempted to perform I/O beyond EOF"); err_message[XR_BAD_RT_GEO_DATA] = _("inconsistent filesystem geometry in realtime filesystem component"); err_message[XR_BAD_INO_MAX_PCT] = _("maximum indicated percentage of inodes > 100%"); err_message[XR_BAD_INO_ALIGN] = _("inconsistent inode alignment value"); err_message[XR_INSUFF_SEC_SB] = _("not enough secondary superblocks with matching geometry"); err_message[XR_BAD_SB_UNIT] = _("bad stripe unit in superblock"); err_message[XR_BAD_SB_WIDTH] = _("bad stripe width in superblock"); err_message[XR_BAD_SVN] = _("bad shared version number in superblock"); err_message[XR_BAD_CRC] = _("bad CRC in superblock"); err_message[XR_BAD_DIR_SIZE_DATA] = _("inconsistent directory geometry information"); err_message[XR_BAD_LOG_GEOMETRY] = _("inconsistent log geometry information"); done = 1; } if (err_code < XR_OK || err_code >= XR_BAD_ERR_CODE) do_abort(_("bad error code - %d\n"), err_code); return(err_message[err_code]); } static void noval(char opt, char *tbl[], int idx) { do_warn(_("-%c %s option cannot have a value\n"), opt, tbl[idx]); usage(); } static void respec(char opt, char *tbl[], int idx) { do_warn("-%c ", opt); if (tbl) do_warn("%s ", tbl[idx]); do_warn(_("option respecified\n")); usage(); } static void unknown(char opt, char *s) { do_warn(_("unknown option -%c %s\n"), opt, s); usage(); } /* * sets only the global argument flags and variables */ static void process_args(int argc, char **argv) { char *p; int c; log_spec = 0; fs_is_dirty = 0; verbose = 0; no_modify = 0; dangerously = 0; isa_file = 0; zap_log = 0; dumpcore = 0; full_ino_ex_data = 0; force_geo = 0; assume_xfs = 0; copied_sunit = 0; sb_inoalignmt = 0; sb_unit = 0; sb_width = 0; ag_stride = 0; thread_count = 1; report_interval = PROG_RPT_DEFAULT; report_corrected = false; /* * XXX have to add suboption processing here * attributes, quotas, nlinks, aligned_inos, sb_fbits */ while ((c = getopt(argc, argv, "c:o:fl:m:r:LnDvVdPet:")) != EOF) { switch (c) { case 'D': dumpcore = 1; break; case 'o': p = optarg; while (*p != '\0') { char *val; switch (getsubopt(&p, o_opts, &val)) { case ASSUME_XFS: if (val) noval('o', o_opts, ASSUME_XFS); if (assume_xfs) respec('o', o_opts, ASSUME_XFS); assume_xfs = 1; break; case IHASH_SIZE: do_warn( _("-o ihash option has been removed and will be ignored\n")); break; case BHASH_SIZE: if (max_mem_specified) do_abort( _("-o bhash option cannot be used with -m option\n")); if (!val) do_abort( _("-o bhash requires a parameter\n")); libxfs_bhash_size = (int)strtol(val, NULL, 0); bhash_option_used = 1; break; case AG_STRIDE: if (!val) do_abort( _("-o ag_stride requires a parameter\n")); ag_stride = (int)strtol(val, NULL, 0); break; case FORCE_GEO: if (val) noval('o', o_opts, FORCE_GEO); if (force_geo) respec('o', o_opts, FORCE_GEO); force_geo = 1; break; case PHASE2_THREADS: if (!val) do_abort( _("-o phase2_threads requires a parameter\n")); phase2_threads = (int)strtol(val, NULL, 0); break; default: unknown('o', val); break; } } break; case 'c': p = optarg; while (*p) { char *val; switch (getsubopt(&p, c_opts, &val)) { case CONVERT_LAZY_COUNT: if (!val) do_abort( _("-c lazycount requires a parameter\n")); lazy_count = (int)strtol(val, NULL, 0); convert_lazy_count = 1; break; default: unknown('c', val); break; } } break; case 'l': log_name = optarg; log_spec = 1; break; case 'r': rt_name = optarg; rt_spec = 1; break; case 'f': isa_file = 1; break; case 'm': if (bhash_option_used) do_abort(_("-m option cannot be used with " "-o bhash option\n")); max_mem_specified = strtol(optarg, NULL, 0); break; case 'L': zap_log = 1; break; case 'n': no_modify = 1; break; case 'd': dangerously = 1; break; case 'v': verbose++; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); case 'P': do_prefetch = 0; break; case 't': report_interval = (int)strtol(optarg, NULL, 0); break; case 'e': report_corrected = true; break; case '?': usage(); } } if (argc - optind != 1) usage(); if ((fs_name = argv[optind]) == NULL) usage(); if (report_corrected && no_modify) usage(); } void __attribute__((noreturn)) do_error(char const *msg, ...) { va_list args; fprintf(stderr, _("\nfatal error -- ")); va_start(args, msg); vfprintf(stderr, msg, args); if (dumpcore) abort(); exit(1); } /* * like do_error, only the error is internal, no system * error so no oserror processing */ void __attribute__((noreturn)) do_abort(char const *msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr, msg, args); if (dumpcore) abort(); exit(1); } void do_warn(char const *msg, ...) { va_list args; fs_is_dirty = 1; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); } /* no formatting */ void do_log(char const *msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); } static void calc_mkfs(xfs_mount_t *mp) { xfs_agblock_t fino_bno; int do_inoalign; do_inoalign = M_IGEO(mp)->ialloc_align; /* * Pre-calculate the geometry of ag 0. We know what it looks like * because we know what mkfs does: 2 allocation btree roots (by block * and by size), the inode allocation btree root, the free inode * allocation btree root (if enabled) and some number of blocks to * prefill the agfl. * * Because the current shape of the btrees may differ from the current * shape, we open code the mkfs freelist block count here. mkfs creates * single level trees, so the calculation is pertty straight forward for * the trees that use the AGFL. */ bnobt_root = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize); bcntbt_root = bnobt_root + 1; inobt_root = bnobt_root + 2; fino_bno = inobt_root + (2 * min(2, mp->m_ag_maxlevels)) + 1; if (xfs_sb_version_hasfinobt(&mp->m_sb)) fino_bno++; if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { fino_bno += min(2, mp->m_rmap_maxlevels); /* agfl blocks */ fino_bno++; } if (xfs_sb_version_hasreflink(&mp->m_sb)) fino_bno++; /* * If the log is allocated in the first allocation group we need to * add the number of blocks used by the log to the above calculation. * * This can happens with filesystems that only have a single * allocation group, or very odd geometries created by old mkfs * versions on very small filesystems. */ if (mp->m_sb.sb_logstart && XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == 0) { /* * XXX(hch): verify that sb_logstart makes sense? */ fino_bno += mp->m_sb.sb_logblocks; } /* * ditto the location of the first inode chunks in the fs ('/') */ if (xfs_sb_version_hasdalign(&mp->m_sb) && do_inoalign) { first_prealloc_ino = XFS_AGB_TO_AGINO(mp, roundup(fino_bno, mp->m_sb.sb_unit)); } else if (xfs_sb_version_hasalign(&mp->m_sb) && mp->m_sb.sb_inoalignmt > 1) { first_prealloc_ino = XFS_AGB_TO_AGINO(mp, roundup(fino_bno, mp->m_sb.sb_inoalignmt)); } else { first_prealloc_ino = XFS_AGB_TO_AGINO(mp, fino_bno); } ASSERT(M_IGEO(mp)->ialloc_blks > 0); if (M_IGEO(mp)->ialloc_blks > 1) last_prealloc_ino = first_prealloc_ino + XFS_INODES_PER_CHUNK; else last_prealloc_ino = XFS_AGB_TO_AGINO(mp, fino_bno + 1); /* * now the first 3 inodes in the system */ if (mp->m_sb.sb_rootino != first_prealloc_ino) { do_warn( _("sb root inode value %" PRIu64 " %sinconsistent with calculated value %u\n"), mp->m_sb.sb_rootino, (mp->m_sb.sb_rootino == NULLFSINO ? "(NULLFSINO) ":""), first_prealloc_ino); if (!no_modify) do_warn( _("resetting superblock root inode pointer to %u\n"), first_prealloc_ino); else do_warn( _("would reset superblock root inode pointer to %u\n"), first_prealloc_ino); /* * just set the value -- safe since the superblock * doesn't get flushed out if no_modify is set */ mp->m_sb.sb_rootino = first_prealloc_ino; } if (mp->m_sb.sb_rbmino != first_prealloc_ino + 1) { do_warn( _("sb realtime bitmap inode %" PRIu64 " %sinconsistent with calculated value %u\n"), mp->m_sb.sb_rbmino, (mp->m_sb.sb_rbmino == NULLFSINO ? "(NULLFSINO) ":""), first_prealloc_ino + 1); if (!no_modify) do_warn( _("resetting superblock realtime bitmap ino pointer to %u\n"), first_prealloc_ino + 1); else do_warn( _("would reset superblock realtime bitmap ino pointer to %u\n"), first_prealloc_ino + 1); /* * just set the value -- safe since the superblock * doesn't get flushed out if no_modify is set */ mp->m_sb.sb_rbmino = first_prealloc_ino + 1; } if (mp->m_sb.sb_rsumino != first_prealloc_ino + 2) { do_warn( _("sb realtime summary inode %" PRIu64 " %sinconsistent with calculated value %u\n"), mp->m_sb.sb_rsumino, (mp->m_sb.sb_rsumino == NULLFSINO ? "(NULLFSINO) ":""), first_prealloc_ino + 2); if (!no_modify) do_warn( _("resetting superblock realtime summary ino pointer to %u\n"), first_prealloc_ino + 2); else do_warn( _("would reset superblock realtime summary ino pointer to %u\n"), first_prealloc_ino + 2); /* * just set the value -- safe since the superblock * doesn't get flushed out if no_modify is set */ mp->m_sb.sb_rsumino = first_prealloc_ino + 2; } } /* * v5 superblock metadata track the LSN of last modification and thus require * that the current LSN is always moving forward. The current LSN is reset if * the log has been cleared, which puts the log behind parts of the filesystem * on-disk and can disrupt log recovery. * * We have tracked the maximum LSN of every piece of metadata that has been read * in via the read verifiers. Compare the max LSN with the log and if the log is * behind, bump the cycle number and reformat the log. */ static void format_log_max_lsn( struct xfs_mount *mp) { struct xlog *log = mp->m_log; int max_cycle; int max_block; int new_cycle; xfs_daddr_t logstart; xfs_daddr_t logblocks; int logversion; if (!xfs_sb_version_hascrc(&mp->m_sb)) return; /* * If the log is ahead of the highest metadata LSN we've seen, we're * safe and there's nothing to do. */ max_cycle = CYCLE_LSN(libxfs_max_lsn); max_block = BLOCK_LSN(libxfs_max_lsn); if (max_cycle < log->l_curr_cycle || (max_cycle == log->l_curr_cycle && max_block < log->l_curr_block)) return; /* * Going to the next cycle should be sufficient but we bump by a few * counts to help cover any metadata LSNs we could have missed. */ new_cycle = max_cycle + 3; logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); logblocks = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); logversion = xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1; do_warn(_("Maximum metadata LSN (%d:%d) is ahead of log (%d:%d).\n"), max_cycle, max_block, log->l_curr_cycle, log->l_curr_block); if (no_modify) { do_warn(_("Would format log to cycle %d.\n"), new_cycle); return; } do_warn(_("Format log to cycle %d.\n"), new_cycle); libxfs_log_clear(log->l_dev, NULL, logstart, logblocks, &mp->m_sb.sb_uuid, logversion, mp->m_sb.sb_logsunit, XLOG_FMT, new_cycle, true); } /* * mkfs increases the AG count for "multidisk" configurations, we want * to target these for an increase in thread count. Hence check the superlock * geometry information to determine if mkfs considered this a multidisk * configuration. */ static bool is_multidisk_filesystem( struct xfs_mount *mp) { struct xfs_sb *sbp = &mp->m_sb; /* High agcount filesystems are always considered "multidisk" */ if (sbp->sb_agcount >= XFS_MULTIDISK_AGCOUNT) return true; /* * If it doesn't have a sunit/swidth, mkfs didn't consider it a * multi-disk array, so we don't either. */ if (!sbp->sb_unit) return false; ASSERT(sbp->sb_width); return true; } /* * if the sector size of the filesystem we are trying to repair is * smaller than that of the underlying filesystem (i.e. we are repairing * an image), the we have to turn off direct IO because we cannot do IO * smaller than the host filesystem's sector size. */ static void check_fs_vs_host_sectsize( struct xfs_sb *sb) { int fd, ret; long old_flags; struct xfs_fsop_geom geom = { 0 }; fd = libxfs_device_to_fd(x.ddev); ret = -xfrog_geometry(fd, &geom); if (ret) { do_log(_("Cannot get host filesystem geometry.\n" "Repair may fail if there is a sector size mismatch between\n" "the image and the host filesystem.\n")); geom.sectsize = BBSIZE; } if (sb->sb_sectsize < geom.sectsize) { old_flags = fcntl(fd, F_GETFL, 0); if (fcntl(fd, F_SETFL, old_flags & ~O_DIRECT) < 0) { do_warn(_( "Sector size on host filesystem larger than image sector size.\n" "Cannot turn off direct IO, so exiting.\n")); exit(1); } } } int main(int argc, char **argv) { xfs_mount_t *temp_mp; xfs_mount_t *mp; xfs_dsb_t *dsb; xfs_buf_t *sbp; xfs_mount_t xfs_m; struct xlog log = {0}; char *msgbuf; struct xfs_sb psb; int rval; struct xfs_ino_geometry *igeo; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); dinode_bmbt_translation_init(); temp_mp = &xfs_m; setbuf(stdout, NULL); process_args(argc, argv); xfs_init(&x); msgbuf = malloc(DURATION_BUF_SIZE); timestamp(PHASE_START, 0, NULL); timestamp(PHASE_END, 0, NULL); /* -f forces this, but let's be nice and autodetect it, as well. */ if (!isa_file) { int fd = libxfs_device_to_fd(x.ddev); struct stat statbuf; if (fstat(fd, &statbuf) < 0) do_warn(_("%s: couldn't stat \"%s\"\n"), progname, fs_name); else if (S_ISREG(statbuf.st_mode)) isa_file = 1; } if (isa_file) { /* Best effort attempt to validate fs vs host sector size */ rval = get_sb(&psb, 0, XFS_MAX_SECTORSIZE, 0); if (rval == XR_OK) check_fs_vs_host_sectsize(&psb); } /* do phase1 to make sure we have a superblock */ phase1(temp_mp); timestamp(PHASE_END, 1, NULL); if (no_modify && primary_sb_modified) { do_warn(_("Primary superblock would have been modified.\n" "Cannot proceed further in no_modify mode.\n" "Exiting now.\n")); exit(1); } rval = get_sb(&psb, 0, XFS_MAX_SECTORSIZE, 0); if (rval != XR_OK) { do_warn(_("Primary superblock bad after phase 1!\n" "Exiting now.\n")); exit(1); } /* * Now that we have completely validated the superblock, geometry may * have changed; re-check geometry vs the host filesystem geometry */ if (isa_file) check_fs_vs_host_sectsize(&psb); /* * Prepare the mount structure. Point the log reference to our local * copy so it's available to the various phases. The log bits are * initialized in phase 2. */ memset(&xfs_m, 0, sizeof(xfs_mount_t)); mp = libxfs_mount(&xfs_m, &psb, x.ddev, x.logdev, x.rtdev, 0); if (!mp) { fprintf(stderr, _("%s: cannot repair this filesystem. Sorry.\n"), progname); exit(1); } mp->m_log = &log; igeo = M_IGEO(mp); /* Spit out function & line on these corruption macros */ if (verbose > 2) mp->m_flags |= LIBXFS_MOUNT_WANT_CORRUPTED; /* * set XFS-independent status vars from the mount/sb structure */ glob_agcount = mp->m_sb.sb_agcount; chunks_pblock = mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK; max_symlink_blocks = libxfs_symlink_blocks(mp, XFS_SYMLINK_MAXLEN); /* * Automatic striding for high agcount filesystems. * * More AGs indicates that the filesystem is either large or can handle * more IO parallelism. Either way, we should try to process multiple * AGs at a time in such a configuration to try to saturate the * underlying storage and speed the repair process. Only do this if * prefetching is enabled. * * Given mkfs defaults for 16AGs for "multidisk" configurations, we want * to target these for an increase in thread count. Hence a stride value * of 15 is chosen to ensure we get at least 2 AGs being scanned at once * on such filesystems. * * Limit the maximum thread count based on the available CPU power that * is available. If we use too many threads, we might run out of memory * and CPU power before we run out of IO concurrency. We limit to 8 * threads/CPU as this is enough threads to saturate a CPU on fast * devices, yet few enough that it will saturate but won't overload slow * devices. * * Multidisk filesystems can handle more IO parallelism so we should try * to process multiple AGs at a time in such a configuration to try to * saturate the underlying storage and speed the repair process. Only do * this if prefetching is enabled. */ if (!ag_stride && do_prefetch && is_multidisk_filesystem(mp)) { /* * For small agcount multidisk systems, just double the * parallelism. For larger AG count filesystems (32 and above) * use more parallelism, and linearly increase the parallelism * with the number of AGs. */ ag_stride = min(glob_agcount, XFS_MULTIDISK_AGCOUNT / 2) - 1; } if (ag_stride) { int max_threads = platform_nproc() * 8; thread_count = (glob_agcount + ag_stride - 1) / ag_stride; while (thread_count > max_threads) { ag_stride *= 2; thread_count = (glob_agcount + ag_stride - 1) / ag_stride; } if (thread_count > 0) thread_init(); else { thread_count = 1; ag_stride = 0; } } if (ag_stride && report_interval) { init_progress_rpt(); if (msgbuf) { do_log(_(" - reporting progress in intervals of %s\n"), duration(report_interval, msgbuf)); } } /* * Adjust libxfs cache sizes based on system memory, * filesystem size and inode count. * * We'll set the cache size based on 3/4s the memory minus * space used by the inode AVL tree and block usage map. * * Inode AVL tree space is approximately 4 bytes per inode, * block usage map is currently 1 byte for 2 blocks. * * We assume most blocks will be inode clusters. * * Calculations are done in kilobyte units. */ if (!bhash_option_used || max_mem_specified) { unsigned long mem_used; unsigned long max_mem; struct rlimit rlim; libxfs_bcache_purge(); cache_destroy(libxfs_bcache); mem_used = (mp->m_sb.sb_icount >> (10 - 2)) + (mp->m_sb.sb_dblocks >> (10 + 1)) + 50000; /* rough estimate of 50MB overhead */ max_mem = max_mem_specified ? max_mem_specified * 1024 : platform_physmem() * 3 / 4; if (getrlimit(RLIMIT_AS, &rlim) != -1 && rlim.rlim_cur != RLIM_INFINITY) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_AS, &rlim); /* use approximately 80% of rlimit to avoid overrun */ max_mem = min(max_mem, rlim.rlim_cur / 1280); } else max_mem = min(max_mem, (LONG_MAX >> 10) + 1); if (verbose > 1) do_log( _(" - max_mem = %lu, icount = %" PRIu64 ", imem = %" PRIu64 ", dblock = %" PRIu64 ", dmem = %" PRIu64 "\n"), max_mem, mp->m_sb.sb_icount, mp->m_sb.sb_icount >> (10 - 2), mp->m_sb.sb_dblocks, mp->m_sb.sb_dblocks >> (10 + 1)); if (max_mem <= mem_used) { if (max_mem_specified) { do_abort( _("Required memory for repair is greater that the maximum specified\n" "with the -m option. Please increase it to at least %lu.\n"), mem_used / 1024); } do_log( _("Memory available for repair (%luMB) may not be sufficient.\n" "At least %luMB is needed to repair this filesystem efficiently\n" "If repair fails due to lack of memory, please\n"), max_mem / 1024, mem_used / 1024); if (do_prefetch) do_log( _("turn prefetching off (-P) to reduce the memory footprint.\n")); else do_log( _("increase system RAM and/or swap space to at least %luMB.\n"), mem_used * 2 / 1024); max_mem = mem_used; } max_mem -= mem_used; if (max_mem >= (1 << 30)) max_mem = 1 << 30; libxfs_bhash_size = max_mem / (HASH_CACHE_RATIO * (igeo->inode_cluster_size >> 10)); if (libxfs_bhash_size < 512) libxfs_bhash_size = 512; if (verbose) do_log(_(" - block cache size set to %d entries\n"), libxfs_bhash_size * HASH_CACHE_RATIO); libxfs_bcache = cache_init(0, libxfs_bhash_size, &libxfs_bcache_operations); } /* * calculate what mkfs would do to this filesystem */ calc_mkfs(mp); /* * initialize block alloc map */ init_bmaps(mp); incore_ino_init(mp); incore_ext_init(mp); rmaps_init(mp); /* initialize random globals now that we know the fs geometry */ inodes_per_block = mp->m_sb.sb_inopblock; if (parse_sb_version(&mp->m_sb)) { do_warn( _("Found unsupported filesystem features. Exiting now.\n")); return(1); } /* make sure the per-ag freespace maps are ok so we can mount the fs */ phase2(mp, phase2_threads); timestamp(PHASE_END, 2, NULL); if (do_prefetch) init_prefetch(mp); phase3(mp, phase2_threads); timestamp(PHASE_END, 3, NULL); phase4(mp); timestamp(PHASE_END, 4, NULL); if (no_modify) printf(_("No modify flag set, skipping phase 5\n")); else { phase5(mp); } timestamp(PHASE_END, 5, NULL); /* * Done with the block usage maps, toss them... */ rmaps_free(mp); free_bmaps(mp); if (!bad_ino_btree) { phase6(mp); timestamp(PHASE_END, 6, NULL); phase7(mp, phase2_threads); timestamp(PHASE_END, 7, NULL); } else { do_warn( _("Inode allocation btrees are too corrupted, skipping phases 6 and 7\n")); } if (lost_quotas && !have_uquotino && !have_gquotino && !have_pquotino) { if (!no_modify) { do_warn( _("Warning: no quota inodes were found. Quotas disabled.\n")); } else { do_warn( _("Warning: no quota inodes were found. Quotas would be disabled.\n")); } } else if (lost_quotas) { if (!no_modify) { do_warn( _("Warning: quota inodes were cleared. Quotas disabled.\n")); } else { do_warn( _("Warning: quota inodes would be cleared. Quotas would be disabled.\n")); } } else { if (lost_uquotino) { if (!no_modify) { do_warn( _("Warning: user quota information was cleared.\n" "User quotas can not be enforced until limit information is recreated.\n")); } else { do_warn( _("Warning: user quota information would be cleared.\n" "User quotas could not be enforced until limit information was recreated.\n")); } } if (lost_gquotino) { if (!no_modify) { do_warn( _("Warning: group quota information was cleared.\n" "Group quotas can not be enforced until limit information is recreated.\n")); } else { do_warn( _("Warning: group quota information would be cleared.\n" "Group quotas could not be enforced until limit information was recreated.\n")); } } if (lost_pquotino) { if (!no_modify) { do_warn( _("Warning: project quota information was cleared.\n" "Project quotas can not be enforced until limit information is recreated.\n")); } else { do_warn( _("Warning: project quota information would be cleared.\n" "Project quotas could not be enforced until limit information was recreated.\n")); } } } if (ag_stride && report_interval) stop_progress_rpt(); if (no_modify) { /* * Warn if the current LSN is problematic and the log requires a * reformat. */ format_log_max_lsn(mp); do_log( _("No modify flag set, skipping filesystem flush and exiting.\n")); if (verbose) summary_report(); if (fs_is_dirty) return(1); return(0); } /* * Clear the quota flags if they're on. */ sbp = libxfs_getsb(mp); if (!sbp) do_error(_("couldn't get superblock\n")); dsb = XFS_BUF_TO_SBP(sbp); if (be16_to_cpu(dsb->sb_qflags) & XFS_ALL_QUOTA_CHKD) { do_warn(_("Note - quota info will be regenerated on next " "quota mount.\n")); dsb->sb_qflags &= cpu_to_be16(~XFS_ALL_QUOTA_CHKD); } if (copied_sunit) { do_warn( _("Note - stripe unit (%d) and width (%d) were copied from a backup superblock.\n" "Please reset with mount -o sunit=,swidth= if necessary\n"), be32_to_cpu(dsb->sb_unit), be32_to_cpu(dsb->sb_width)); } libxfs_writebuf(sbp, 0); /* * Done. Flush all cached buffers and inodes first to ensure all * verifiers are run (where we discover the max metadata LSN), reformat * the log if necessary and unmount. */ libxfs_bcache_flush(); format_log_max_lsn(mp); libxfs_umount(mp); if (x.rtdev) libxfs_device_close(x.rtdev); if (x.logdev && x.logdev != x.ddev) libxfs_device_close(x.logdev); libxfs_device_close(x.ddev); libxfs_destroy(); if (verbose) summary_report(); do_log(_("done\n")); if (dangerously && !no_modify) do_warn( _("Repair of readonly mount complete. Immediate reboot encouraged.\n")); pftrace_done(); free(msgbuf); if (fs_is_dirty && report_corrected) return (4); return (0); } xfsprogs-5.3.0/rtcp/Makefile0000644000175000017500000000070713570057155015670 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_rtcp CFILES = xfs_rtcp.c LLDFLAGS = -static LLDLIBS = $(LIBFROG) LTDEPENDENCIES = $(LIBFROG) default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/rtcp/xfs_rtcp.c0000644000175000017500000001751213570057155016226 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libfrog/fsgeom.h" int rtcp(char *, char *, int); int xfsrtextsize(char *path); static int pflag; char *progname; static void usage(void) { fprintf(stderr, _("%s [-e extsize] [-p] [-V] source target\n"), progname); exit(2); } int main(int argc, char **argv) { int c, i, r, errflg = 0; struct stat s2; int extsize = - 1; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); while ((c = getopt(argc, argv, "pe:V")) != EOF) { switch (c) { case 'e': extsize = atoi(optarg); break; case 'p': pflag = 1; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); default: errflg++; } } /* * Check for sufficient arguments or a usage error. */ argc -= optind; argv = &argv[optind]; if (argc < 2) { fprintf(stderr, _("%s: must specify files to copy\n"), progname); errflg++; } if (errflg) usage(); /* * If there is more than a source and target, * the last argument (the target) must be a directory * which really exists. */ if (argc > 2) { if (stat(argv[argc-1], &s2) < 0) { fprintf(stderr, _("%s: stat of %s failed\n"), progname, argv[argc-1]); exit(2); } if (!S_ISDIR(s2.st_mode)) { fprintf(stderr, _("%s: final argument is not directory\n"), progname); usage(); } } /* * Perform a multiple argument rtcp by * multiple invocations of rtcp(). */ r = 0; for (i = 0; i < argc-1; i++) r += rtcp(argv[i], argv[argc-1], extsize); /* * Show errors by nonzero exit code. */ exit(r?2:0); } int rtcp( char *source, char *target, int fextsize) { int fromfd, tofd, readct, writect, iosz, reopen; int remove = 0, rtextsize; char *sp, *fbuf, *ptr; char tbuf[ PATH_MAX ]; struct stat s1, s2; struct fsxattr fsxattr; struct dioattr dioattr; /* * While source or target have trailing /, remove them * unless only "/". */ sp = source + strlen(source); if (sp) { while (*--sp == '/' && sp > source) *sp = '\0'; } sp = target + strlen(target); if (sp) { while (*--sp == '/' && sp > target) *sp = '\0'; } if ( stat(source, &s1) ) { fprintf(stderr, _("%s: failed stat on %s: %s\n"), progname, source, strerror(errno)); return( -1); } /* * check for a realtime partition */ snprintf(tbuf, sizeof(tbuf), "%s", target); if ( stat(target, &s2) ) { if (!S_ISDIR(s2.st_mode)) { /* take out target file name */ if ((ptr = strrchr(tbuf, '/')) != NULL) *ptr = '\0'; else snprintf(tbuf, sizeof(tbuf), "."); } } if ( (rtextsize = xfsrtextsize( tbuf )) <= 0 ) { fprintf(stderr, _("%s: %s filesystem has no realtime partition\n"), progname, tbuf); return( -1 ); } /* * check if target is a directory */ snprintf(tbuf, sizeof(tbuf), "%s", target); if ( !stat(target, &s2) ) { if (S_ISDIR(s2.st_mode)) { snprintf(tbuf, sizeof(tbuf), "%s/%s", target, basename(source)); } } if ( stat(tbuf, &s2) ) { /* * create the file if it does not exist */ if ( (tofd = open(tbuf, O_RDWR|O_CREAT|O_DIRECT, 0666)) < 0 ) { fprintf(stderr, _("%s: open of %s failed: %s\n"), progname, tbuf, strerror(errno)); return( -1 ); } remove = 1; /* * mark the file as a realtime file */ fsxattr.fsx_xflags = FS_XFLAG_REALTIME; if (fextsize != -1 ) fsxattr.fsx_extsize = fextsize; else fsxattr.fsx_extsize = 0; if ( xfsctl(tbuf, tofd, FS_IOC_FSSETXATTR, &fsxattr) ) { fprintf(stderr, _("%s: set attributes on %s failed: %s\n"), progname, tbuf, strerror(errno)); close( tofd ); unlink( tbuf ); return( -1 ); } } else { /* * open existing file */ if ( (tofd = open(tbuf, O_RDWR|O_DIRECT)) < 0 ) { fprintf(stderr, _("%s: open of %s failed: %s\n"), progname, tbuf, strerror(errno)); return( -1 ); } if ( xfsctl(tbuf, tofd, FS_IOC_FSGETXATTR, &fsxattr) ) { fprintf(stderr, _("%s: get attributes of %s failed: %s\n"), progname, tbuf, strerror(errno)); close( tofd ); return( -1 ); } /* * check if the existing file is already a realtime file */ if ( !(fsxattr.fsx_xflags & FS_XFLAG_REALTIME) ) { fprintf(stderr, _("%s: %s is not a realtime file.\n"), progname, tbuf); close( tofd ); return( -1 ); } /* * check for matching extent size */ if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) { fprintf(stderr, _("%s: %s file extent size is %d, " "instead of %d.\n"), progname, tbuf, fsxattr.fsx_extsize, fextsize); close( tofd ); return( -1 ); } } /* * open the source file */ reopen = 0; if ( (fromfd = open(source, O_RDONLY|O_DIRECT)) < 0 ) { fprintf(stderr, _("%s: open of %s source failed: %s\n"), progname, source, strerror(errno)); close( tofd ); if (remove) unlink( tbuf ); return( -1 ); } fsxattr.fsx_xflags = 0; fsxattr.fsx_extsize = 0; if ( xfsctl(source, fromfd, FS_IOC_FSGETXATTR, &fsxattr) ) { reopen = 1; } else { if (! (fsxattr.fsx_xflags & FS_XFLAG_REALTIME) ){ fprintf(stderr, _("%s: %s is not a realtime file.\n"), progname, source); reopen = 1; } } if (reopen) { close( fromfd ); if ( (fromfd = open(source, O_RDONLY )) < 0 ) { fprintf(stderr, _("%s: open of %s source failed: %s\n"), progname, source, strerror(errno)); close( tofd ); if (remove) unlink( tbuf ); return( -1 ); } } /* * get direct I/O parameters */ if ( xfsctl(tbuf, tofd, XFS_IOC_DIOINFO, &dioattr) ) { fprintf(stderr, _("%s: couldn't get direct I/O information: %s\n"), progname, strerror(errno)); close( fromfd ); close( tofd ); if ( remove ) unlink( tbuf ); return( -1 ); } if ( rtextsize % dioattr.d_miniosz ) { fprintf(stderr, _("%s: extent size %d not a multiple of %d.\n"), progname, rtextsize, dioattr.d_miniosz); close( fromfd ); close( tofd ); if ( remove ) unlink( tbuf ); return( -1 ); } /* * Check that the source file size is a multiple of the * file system block size. */ if ( s1.st_size % dioattr.d_miniosz ) { printf(_("The size of %s is not a multiple of %d.\n"), source, dioattr.d_miniosz); if ( pflag ) { printf(_("%s will be padded to %lld bytes.\n"), tbuf, (long long) (((s1.st_size / dioattr.d_miniosz) + 1) * dioattr.d_miniosz) ); } else { printf(_("Use the -p option to pad %s to a " "size which is a multiple of %d bytes.\n"), tbuf, dioattr.d_miniosz); close( fromfd ); close( tofd ); if ( remove ) unlink( tbuf ); return( -1 ); } } iosz = dioattr.d_miniosz; fbuf = memalign( dioattr.d_mem, iosz); memset(fbuf, 0, iosz); /* * read the entire source file */ while ( ( readct = read( fromfd, fbuf, iosz) ) != 0 ) { /* * if there is a read error - break */ if (readct < 0 ) { break; } /* * if there is a short read, pad to a block boundary */ if ( readct != iosz ) { if ( (readct % dioattr.d_miniosz) != 0 ) { readct = ( (readct/dioattr.d_miniosz) + 1 ) * dioattr.d_miniosz; } } /* * write to target file */ writect = write( tofd, fbuf, readct); if ( writect != readct ) { fprintf(stderr, _("%s: write error: %s\n"), progname, strerror(errno)); close(fromfd); close(tofd); free( fbuf ); return( -1 ); } memset( fbuf, 0, iosz); } close(fromfd); close(tofd); free( fbuf ); return( 0 ); } /* * Determine the realtime extent size of the XFS file system */ int xfsrtextsize( char *path) { struct xfs_fsop_geom geo; int fd, rval, rtextsize; fd = open( path, O_RDONLY ); if ( fd < 0 ) { fprintf(stderr, _("%s: could not open %s: %s\n"), progname, path, strerror(errno)); return -1; } rval = -xfrog_geometry(fd, &geo); close(fd); if (rval) return -1; rtextsize = geo.rtextsize * geo.blocksize; return rtextsize; } xfsprogs-5.3.0/scrub/Makefile0000644000175000017500000000644713570057155016045 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2018 Oracle. All Rights Reserved. # TOPDIR = .. builddefs=$(TOPDIR)/include/builddefs include $(builddefs) # On linux we get fsmap from the system or define it ourselves # so include this based on platform type. If this reverts to only # the autoconf check w/o local definition, change to testing HAVE_GETFSMAP SCRUB_PREREQS=$(HAVE_OPENAT)$(HAVE_FSTATAT) ifeq ($(SCRUB_PREREQS),yesyes) LTCOMMAND = xfs_scrub INSTALL_SCRUB = install-scrub XFS_SCRUB_ALL_PROG = xfs_scrub_all XFS_SCRUB_ARGS = -b -n ifeq ($(HAVE_SYSTEMD),yes) INSTALL_SCRUB += install-systemd SYSTEMD_SERVICES = xfs_scrub@.service xfs_scrub_all.service xfs_scrub_all.timer xfs_scrub_fail@.service OPTIONAL_TARGETS += $(SYSTEMD_SERVICES) endif ifeq ($(HAVE_CROND),yes) INSTALL_SCRUB += install-crond CRONTABS = xfs_scrub_all.cron OPTIONAL_TARGETS += $(CRONTABS) # Don't enable the crontab by default for now CROND_DIR = $(PKG_LIB_DIR)/$(PKG_NAME) endif endif # scrub_prereqs HFILES = \ common.h \ counter.h \ descr.h \ disk.h \ filemap.h \ fscounters.h \ inodes.h \ progress.h \ read_verify.h \ repair.h \ scrub.h \ spacemap.h \ unicrash.h \ vfs.h \ xfs_scrub.h CFILES = \ common.c \ counter.c \ descr.c \ disk.c \ filemap.c \ fscounters.c \ inodes.c \ phase1.c \ phase2.c \ phase3.c \ phase4.c \ phase5.c \ phase6.c \ phase7.c \ progress.c \ read_verify.c \ repair.c \ scrub.c \ spacemap.c \ vfs.c \ xfs_scrub.c LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBICU_LIBS) $(LIBRT) LTDEPENDENCIES += $(LIBHANDLE) $(LIBFROG) LLDFLAGS = -static ifeq ($(HAVE_MALLINFO),yes) LCFLAGS += -DHAVE_MALLINFO endif ifeq ($(HAVE_SYNCFS),yes) LCFLAGS += -DHAVE_SYNCFS endif ifeq ($(HAVE_LIBATTR),yes) LCFLAGS += -DHAVE_LIBATTR endif ifeq ($(HAVE_LIBICU),yes) CFILES += unicrash.c LCFLAGS += -DHAVE_LIBICU $(LIBICU_CFLAGS) endif ifeq ($(HAVE_SG_IO),yes) LCFLAGS += -DHAVE_SG_IO endif ifeq ($(HAVE_HDIO_GETGEO),yes) LCFLAGS += -DHAVE_HDIO_GETGEO endif LDIRT = $(XFS_SCRUB_ALL_PROG) *.service *.cron default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(OPTIONAL_TARGETS) xfs_scrub_all: xfs_scrub_all.in $(builddefs) @echo " [SED] $@" $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ -e "s|@pkg_version@|$(PKG_VERSION)|g" \ -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" < $< > $@ $(Q)chmod a+x $@ phase5.o unicrash.o xfs.o: $(builddefs) include $(BUILDRULES) install: $(INSTALL_SCRUB) %.service: %.service.in $(builddefs) @echo " [SED] $@" $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" \ -e "s|@pkg_lib_dir@|$(PKG_LIB_DIR)|g" \ -e "s|@pkg_name@|$(PKG_NAME)|g" < $< > $@ %.cron: %.cron.in $(builddefs) @echo " [SED] $@" $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" < $< > $@ install-systemd: default $(SYSTEMD_SERVICES) $(INSTALL) -m 755 -d $(SYSTEMD_SYSTEM_UNIT_DIR) $(INSTALL) -m 644 $(SYSTEMD_SERVICES) $(SYSTEMD_SYSTEM_UNIT_DIR) $(INSTALL) -m 755 -d $(PKG_LIB_DIR)/$(PKG_NAME) $(INSTALL) -m 755 xfs_scrub_fail $(PKG_LIB_DIR)/$(PKG_NAME) install-crond: default $(CRONTABS) $(INSTALL) -m 755 -d $(CROND_DIR) $(INSTALL) -m 644 $(CRONTABS) $(CROND_DIR) install-scrub: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) $(INSTALL) -m 755 $(XFS_SCRUB_ALL_PROG) $(PKG_SBIN_DIR) install-dev: -include .dep xfsprogs-5.3.0/scrub/common.c0000644000175000017500000002210313570057155016024 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "platform_defs.h" #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "progress.h" extern char *progname; /* * Reporting Status to the Console * * We aim for a roughly standard reporting format -- the severity of the * status being reported, a textual description of the object being * reported, and whatever the status happens to be. * * Errors are the most severe and reflect filesystem corruption. * Warnings indicate that something is amiss and needs the attention of * the administrator, but does not constitute a corruption. Information * is merely advisory. */ /* Too many errors? Bail out. */ bool xfs_scrub_excessive_errors( struct scrub_ctx *ctx) { unsigned long long errors_seen; /* * We only set max_errors at the start of the program, so it's safe to * access it locklessly. */ if (ctx->max_errors == 0) return false; pthread_mutex_lock(&ctx->lock); errors_seen = ctx->corruptions_found + ctx->unfixable_errors; pthread_mutex_unlock(&ctx->lock); return errors_seen >= ctx->max_errors; } static struct { const char *string; int loglevel; } err_levels[] = { [S_ERROR] = { .string = "Error", .loglevel = LOG_ERR, }, [S_CORRUPT] = { .string = "Corruption", .loglevel = LOG_ERR, }, [S_UNFIXABLE] = { .string = "Unfixable Error", .loglevel = LOG_ERR, }, [S_WARN] = { .string = "Warning", .loglevel = LOG_WARNING, }, [S_INFO] = { .string = "Info", .loglevel = LOG_INFO, }, [S_REPAIR] = { .string = "Repaired", .loglevel = LOG_INFO, }, [S_PREEN] = { .string = "Optimized", .loglevel = LOG_INFO, }, }; /* If stream is a tty, clear to end of line to clean up progress bar. */ static inline const char *stream_start(FILE *stream) { if (stream == stderr) return stderr_isatty ? CLEAR_EOL : ""; return stdout_isatty ? CLEAR_EOL : ""; } /* Print a warning string and some warning text. */ void __str_out( struct scrub_ctx *ctx, const char *descr, enum error_level level, int error, const char *file, int line, const char *format, ...) { FILE *stream = stderr; va_list args; char buf[DESCR_BUFSZ]; /* print strerror or format of choice but not both */ assert(!(error && format)); if (level >= S_INFO) stream = stdout; pthread_mutex_lock(&ctx->lock); /* We only want to hear about optimizing when in debug/verbose mode. */ if (level == S_PREEN && !debug && !verbose) goto out_record; fprintf(stream, "%s%s: %s: ", stream_start(stream), _(err_levels[level].string), descr); if (error) { fprintf(stream, _("%s."), strerror_r(error, buf, DESCR_BUFSZ)); } else { va_start(args, format); vfprintf(stream, format, args); va_end(args); } if (debug) fprintf(stream, _(" (%s line %d)"), file, line); fprintf(stream, "\n"); if (stream == stdout) fflush(stream); out_record: if (error || level == S_ERROR) /* A syscall failed */ ctx->runtime_errors++; else if (level == S_CORRUPT) ctx->corruptions_found++; else if (level == S_UNFIXABLE) ctx->unfixable_errors++; else if (level == S_WARN) ctx->warnings_found++; else if (level == S_REPAIR) ctx->repairs++; else if (level == S_PREEN) ctx->preens++; pthread_mutex_unlock(&ctx->lock); } /* Log a message to syslog. */ #define LOG_BUFSZ 4096 #define LOGNAME_BUFSZ 256 void __str_log( struct scrub_ctx *ctx, enum error_level level, const char *format, ...) { va_list args; char logname[LOGNAME_BUFSZ]; char buf[LOG_BUFSZ]; int sz; /* We only want to hear about optimizing when in debug/verbose mode. */ if (level == S_PREEN && !debug && !verbose) return; /* * Skip logging if we're being run as a service (presumably the * service will log stdout/stderr); if we're being run in a non * interactive manner (assume we're a service); or if we're in * debug mode. */ if (is_service || !isatty(fileno(stdin)) || debug) return; snprintf(logname, LOGNAME_BUFSZ, "%s@%s", progname, ctx->mntpoint); openlog(logname, LOG_PID, LOG_DAEMON); sz = snprintf(buf, LOG_BUFSZ, "%s: ", _(err_levels[level].string)); va_start(args, format); vsnprintf(buf + sz, LOG_BUFSZ - sz, format, args); va_end(args); syslog(err_levels[level].loglevel, "%s", buf); closelog(); } double timeval_subtract( struct timeval *tv1, struct timeval *tv2) { return ((tv1->tv_sec - tv2->tv_sec) + ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); } /* Produce human readable disk space output. */ double auto_space_units( unsigned long long bytes, char **units) { if (debug > 1) goto no_prefix; if (bytes > (1ULL << 40)) { *units = "TiB"; return (double)bytes / (1ULL << 40); } else if (bytes > (1ULL << 30)) { *units = "GiB"; return (double)bytes / (1ULL << 30); } else if (bytes > (1ULL << 20)) { *units = "MiB"; return (double)bytes / (1ULL << 20); } else if (bytes > (1ULL << 10)) { *units = "KiB"; return (double)bytes / (1ULL << 10); } no_prefix: *units = "B"; return bytes; } /* Produce human readable discrete number output. */ double auto_units( unsigned long long number, char **units, int *precision) { if (debug > 1) goto no_prefix; *precision = 1; if (number > 1000000000000ULL) { *units = "T"; return number / 1000000000000.0; } else if (number > 1000000000ULL) { *units = "G"; return number / 1000000000.0; } else if (number > 1000000ULL) { *units = "M"; return number / 1000000.0; } else if (number > 1000ULL) { *units = "K"; return number / 1000.0; } no_prefix: *units = ""; *precision = 0; return number; } /* How many threads to kick off? */ unsigned int scrub_nproc( struct scrub_ctx *ctx) { if (force_nr_threads) return force_nr_threads; return ctx->nr_io_threads; } /* * How many threads to kick off for a workqueue? If we only want one * thread, save ourselves the overhead and just run it in the main thread. */ unsigned int scrub_nproc_workqueue( struct scrub_ctx *ctx) { unsigned int x; x = scrub_nproc(ctx); if (x == 1) x = 0; return x; } /* * Sleep for 100us * however many -b we got past the initial one. * This is an (albeit clumsy) way to throttle scrub activity. */ #define NSEC_PER_SEC 1000000000ULL #define NSEC_PER_USEC 1000ULL void background_sleep(void) { unsigned long long time_ns; struct timespec tv; if (bg_mode < 2) return; time_ns = 100 * NSEC_PER_USEC * (bg_mode - 1); tv.tv_sec = time_ns / NSEC_PER_SEC; tv.tv_nsec = time_ns % NSEC_PER_SEC; nanosleep(&tv, NULL); } /* * Return the input string with non-printing bytes escaped. * Caller must free the buffer. */ char * string_escape( const char *in) { char *str; const char *p; char *q; int x; str = malloc(strlen(in) * 4); if (!str) return NULL; for (p = in, q = str; *p != '\0'; p++) { if (isprint(*p)) { *q = *p; q++; } else { x = sprintf(q, "\\x%02x", *p); q += x; } } *q = '\0'; return str; } /* * Record another naming warning, and decide if it's worth * complaining about. */ bool should_warn_about_name( struct scrub_ctx *ctx) { bool whine; bool res; pthread_mutex_lock(&ctx->lock); ctx->naming_warnings++; whine = ctx->naming_warnings == TOO_MANY_NAME_WARNINGS; res = ctx->naming_warnings < TOO_MANY_NAME_WARNINGS; pthread_mutex_unlock(&ctx->lock); if (whine && !(debug || verbose)) str_info(ctx, ctx->mntpoint, _("More than %u naming warnings, shutting up."), TOO_MANY_NAME_WARNINGS); return debug || verbose || res; } /* Decide if a value is within +/- (n/d) of a desired value. */ bool within_range( struct scrub_ctx *ctx, unsigned long long value, unsigned long long desired, unsigned long long abs_threshold, unsigned int n, unsigned int d, const char *descr) { assert(n < d); /* Don't complain if difference does not exceed an absolute value. */ if (value < desired && desired - value < abs_threshold) return true; if (value > desired && value - desired < abs_threshold) return true; /* Complain if the difference exceeds a certain percentage. */ if (value < desired * (d - n) / d) return false; if (value > desired * (d + n) / d) return false; return true; } /* * Render an inode number into a buffer in a format suitable for use in * log messages. The buffer will be filled with: * "inode (/)" * If the @format argument is non-NULL, it will be rendered into the buffer * after the inode representation and a single space. */ int scrub_render_ino_descr( const struct scrub_ctx *ctx, char *buf, size_t buflen, uint64_t ino, uint32_t gen, const char *format, ...) { va_list args; uint32_t agno; uint32_t agino; int ret; agno = cvt_ino_to_agno(&ctx->mnt, ino); agino = cvt_ino_to_agino(&ctx->mnt, ino); ret = snprintf(buf, buflen, _("inode %"PRIu64" (%"PRIu32"/%"PRIu32")%s"), ino, agno, agino, format ? " " : ""); if (ret < 0 || ret >= buflen || format == NULL) return ret; va_start(args, format); ret += vsnprintf(buf + ret, buflen - ret, format, args); va_end(args); return ret; } xfsprogs-5.3.0/scrub/common.h0000644000175000017500000000576513570057155016050 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_COMMON_H_ #define XFS_SCRUB_COMMON_H_ /* * When reporting a defective metadata object to the console, this * is the size of the buffer to use to store the description of that * item. */ #define DESCR_BUFSZ 256 bool xfs_scrub_excessive_errors(struct scrub_ctx *ctx); enum error_level { S_ERROR = 0, S_CORRUPT, S_UNFIXABLE, S_WARN, S_INFO, S_REPAIR, S_PREEN, }; void __str_out(struct scrub_ctx *ctx, const char *descr, enum error_level level, int error, const char *file, int line, const char *format, ...); #define str_errno(ctx, str) \ __str_out(ctx, str, S_ERROR, errno, __FILE__, __LINE__, NULL) #define str_liberror(ctx, error, str) \ __str_out(ctx, str, S_ERROR, error, __FILE__, __LINE__, NULL) #define str_corrupt(ctx, str, ...) \ __str_out(ctx, str, S_CORRUPT, 0, __FILE__, __LINE__, __VA_ARGS__) #define str_error(ctx, str, ...) \ __str_out(ctx, str, S_ERROR, 0, __FILE__, __LINE__, __VA_ARGS__) #define str_warn(ctx, str, ...) \ __str_out(ctx, str, S_WARN, 0, __FILE__, __LINE__, __VA_ARGS__) #define str_info(ctx, str, ...) \ __str_out(ctx, str, S_INFO, 0, __FILE__, __LINE__, __VA_ARGS__) #define record_repair(ctx, str, ...) \ __str_out(ctx, str, S_REPAIR, 0, __FILE__, __LINE__, __VA_ARGS__) #define record_preen(ctx, str, ...) \ __str_out(ctx, str, S_PREEN, 0, __FILE__, __LINE__, __VA_ARGS__) #define str_unfixable_error(ctx, str, ...) \ __str_out(ctx, str, S_UNFIXABLE, 0, __FILE__, __LINE__, __VA_ARGS__) #define dbg_printf(fmt, ...) \ do {if (debug > 1) {printf(fmt, __VA_ARGS__);}} while (0) void __str_log(struct scrub_ctx *ctx, enum error_level level, const char *format, ...); #define log_info(ctx, ...) \ __str_log(ctx, S_INFO, __VA_ARGS__) #define log_warn(ctx, ...) \ __str_log(ctx, S_WARN, __VA_ARGS__) #define log_err(ctx, ...) \ __str_log(ctx, S_ERROR, __VA_ARGS__) /* Is this debug tweak enabled? */ static inline bool debug_tweak_on( const char *name) { return debug && getenv(name) != NULL; } double timeval_subtract(struct timeval *tv1, struct timeval *tv2); double auto_space_units(unsigned long long kilobytes, char **units); double auto_units(unsigned long long number, char **units, int *precision); unsigned int scrub_nproc(struct scrub_ctx *ctx); unsigned int scrub_nproc_workqueue(struct scrub_ctx *ctx); #ifndef HAVE_SYNCFS static inline int syncfs(int fd) { sync(); return 0; } #endif void background_sleep(void); char *string_escape(const char *in); #define TOO_MANY_NAME_WARNINGS 10000 bool should_warn_about_name(struct scrub_ctx *ctx); bool within_range(struct scrub_ctx *ctx, unsigned long long value, unsigned long long desired, unsigned long long abs_threshold, unsigned int n, unsigned int d, const char *descr); int scrub_render_ino_descr(const struct scrub_ctx *ctx, char *buf, size_t buflen, uint64_t ino, uint32_t gen, const char *format, ...); #endif /* XFS_SCRUB_COMMON_H_ */ xfsprogs-5.3.0/scrub/counter.c0000644000175000017500000000334613570057155016223 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include "libfrog/ptvar.h" #include "counter.h" /* * Per-Thread Counters * * This is a global counter object that uses per-thread counters to * count things without having to content for a single shared lock. * Provided we know the number of threads that will be accessing the * counter, each thread gets its own thread-specific counter variable. * Changing the value is fast, though retrieving the value is expensive * and approximate. */ struct ptcounter { struct ptvar *var; }; /* Allocate per-thread counter. */ int ptcounter_alloc( size_t nr, struct ptcounter **pp) { struct ptcounter *p; int ret; p = malloc(sizeof(struct ptcounter)); if (!p) return errno; ret = -ptvar_alloc(nr, sizeof(uint64_t), &p->var); if (ret) { free(p); return ret; } *pp = p; return 0; } /* Free per-thread counter. */ void ptcounter_free( struct ptcounter *ptc) { ptvar_free(ptc->var); free(ptc); } /* Add a quantity to the counter. */ int ptcounter_add( struct ptcounter *ptc, int64_t nr) { uint64_t *p; int ret; p = ptvar_get(ptc->var, &ret); if (ret) return -ret; *p += nr; return 0; } static int ptcounter_val_helper( struct ptvar *ptv, void *data, void *foreach_arg) { uint64_t *sum = foreach_arg; uint64_t *count = data; *sum += *count; return 0; } /* Return the approximate value of this counter. */ int ptcounter_value( struct ptcounter *ptc, uint64_t *sum) { *sum = 0; return -ptvar_foreach(ptc->var, ptcounter_val_helper, sum); } xfsprogs-5.3.0/scrub/counter.h0000644000175000017500000000073113570057155016223 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_COUNTER_H_ #define XFS_SCRUB_COUNTER_H_ struct ptcounter; int ptcounter_alloc(size_t nr, struct ptcounter **pp); void ptcounter_free(struct ptcounter *ptc); int ptcounter_add(struct ptcounter *ptc, int64_t nr); int ptcounter_value(struct ptcounter *ptc, uint64_t *sum); #endif /* XFS_SCRUB_COUNTER_H_ */ xfsprogs-5.3.0/scrub/descr.c0000644000175000017500000000531213570057155015637 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include "platform_defs.h" #include "input.h" #include "libfrog/paths.h" #include "libfrog/ptvar.h" #include "xfs_scrub.h" #include "common.h" #include "descr.h" /* * Deferred String Description Renderer * ==================================== * There are many places in xfs_scrub where some event occurred and we'd like * to be able to print some sort of message describing what happened, and * where. However, we don't know whether we're going to need the description * of where ahead of time and there's little point in spending any time looking * up gettext strings and formatting buffers until we actually need to. * * This code provides enough of a function closure that we are able to record * some information about the program status but defer rendering the textual * description until we know that we need it. Once we've rendered the string * we can skip it for subsequent calls. We use per-thread storage for the * message buffer to amortize the memory allocation across calls. * * On a clean filesystem this can reduce the xfs_scrub runtime by 7-10% by * avoiding unnecessary work. */ static struct ptvar *descr_ptvar; /* Global buffer for when we aren't running in threaded mode. */ static char global_dsc_buf[DESCR_BUFSZ]; /* * Render a textual description string using the function and location stored * in the description context. */ const char * __descr_render( struct descr *dsc, const char *file, int line) { char *dsc_buf; int ret; if (descr_ptvar) { dsc_buf = ptvar_get(descr_ptvar, &ret); if (ret) return _("error finding description buffer"); } else dsc_buf = global_dsc_buf; ret = dsc->fn(dsc->ctx, dsc_buf, DESCR_BUFSZ, dsc->where); if (ret < 0) { snprintf(dsc_buf, DESCR_BUFSZ, _("error %d while rendering description at %s line %d\n"), ret, file, line); } return dsc_buf; } /* * Set a new location context for this deferred-rendering string. * The caller is responsible for freeing the old context, if any. */ void descr_set( struct descr *dsc, void *where) { dsc->where = where; } /* Allocate all the description string buffers. */ int descr_init_phase( struct scrub_ctx *ctx, unsigned int nr_threads) { int ret; assert(descr_ptvar == NULL); ret = -ptvar_alloc(nr_threads, DESCR_BUFSZ, &descr_ptvar); if (ret) str_liberror(ctx, ret, _("creating description buffer")); return ret; } /* Free all the description string buffers. */ void descr_end_phase(void) { if (descr_ptvar) ptvar_free(descr_ptvar); descr_ptvar = NULL; } xfsprogs-5.3.0/scrub/descr.h0000644000175000017500000000143613570057155015647 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_DESCR_H_ #define XFS_SCRUB_DESCR_H_ typedef int (*descr_fn)(struct scrub_ctx *ctx, char *buf, size_t buflen, void *data); struct descr { struct scrub_ctx *ctx; descr_fn fn; void *where; }; #define DEFINE_DESCR(_name, _ctx, _fn) \ struct descr _name = { .ctx = (_ctx), .fn = (_fn) } const char *__descr_render(struct descr *dsc, const char *file, int line); #define descr_render(dsc) __descr_render((dsc), __FILE__, __LINE__) void descr_set(struct descr *dsc, void *where); int descr_init_phase(struct scrub_ctx *ctx, unsigned int nr_threads); void descr_end_phase(void); #endif /* XFS_SCRUB_DESCR_H_ */ xfsprogs-5.3.0/scrub/disk.c0000644000175000017500000002115513570057155015474 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include #ifdef HAVE_SG_IO # include #endif #ifdef HAVE_HDIO_GETGEO # include #endif #include "platform_defs.h" #include "libfrog/util.h" #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "disk.h" #include "platform_defs.h" #ifndef BLKROTATIONAL # define BLKROTATIONAL _IO(0x12, 126) #endif /* * Disk Abstraction * * These routines help us to discover the geometry of a block device, * estimate the amount of concurrent IOs that we can send to it, and * abstract the process of performing read verification of disk blocks. */ /* Figure out how many disk heads are available. */ static unsigned int __disk_heads( struct disk *disk) { int iomin; int ioopt; int nproc = platform_nproc(); unsigned short rot; int error; /* If it's not a block device, throw all the CPUs at it. */ if (!S_ISBLK(disk->d_sb.st_mode)) return nproc; /* Non-rotational device? Throw all the CPUs at the problem. */ rot = 1; error = ioctl(disk->d_fd, BLKROTATIONAL, &rot); if (error == 0 && rot == 0) return nproc; /* * Sometimes we can infer the number of devices from the * min/optimal IO sizes. */ iomin = ioopt = 0; if (ioctl(disk->d_fd, BLKIOMIN, &iomin) == 0 && ioctl(disk->d_fd, BLKIOOPT, &ioopt) == 0 && iomin > 0 && ioopt > 0) { return min(nproc, max(1, ioopt / iomin)); } /* Rotating device? I guess? */ return 2; } /* Figure out how many disk heads are available. */ unsigned int disk_heads( struct disk *disk) { if (force_nr_threads) return force_nr_threads; return __disk_heads(disk); } /* * Execute a SCSI VERIFY(16) to verify disk contents. * For devices that support this command, this can sharply reduce the * runtime of the data block verification phase if the storage device's * internal bandwidth exceeds its link bandwidth. However, it only * works if we're talking to a raw SCSI device, and only if we trust the * firmware. */ #ifdef HAVE_SG_IO # define SENSE_BUF_LEN 64 # define VERIFY16_CMDLEN 16 # define VERIFY16_CMD 0x8F # ifndef SG_FLAG_Q_AT_TAIL # define SG_FLAG_Q_AT_TAIL 0x10 # endif static int disk_scsi_verify( struct disk *disk, uint64_t startblock, /* lba */ uint64_t blockcount) /* lba */ { struct sg_io_hdr iohdr; unsigned char cdb[VERIFY16_CMDLEN]; unsigned char sense[SENSE_BUF_LEN]; uint64_t llba; uint64_t veri_len = blockcount; int error; assert(!debug_tweak_on("XFS_SCRUB_NO_SCSI_VERIFY")); llba = startblock + (disk->d_start >> BBSHIFT); /* Borrowed from sg_verify */ cdb[0] = VERIFY16_CMD; cdb[1] = 0; /* skip PI, DPO, and byte check. */ cdb[2] = (llba >> 56) & 0xff; cdb[3] = (llba >> 48) & 0xff; cdb[4] = (llba >> 40) & 0xff; cdb[5] = (llba >> 32) & 0xff; cdb[6] = (llba >> 24) & 0xff; cdb[7] = (llba >> 16) & 0xff; cdb[8] = (llba >> 8) & 0xff; cdb[9] = llba & 0xff; cdb[10] = (veri_len >> 24) & 0xff; cdb[11] = (veri_len >> 16) & 0xff; cdb[12] = (veri_len >> 8) & 0xff; cdb[13] = veri_len & 0xff; cdb[14] = 0; cdb[15] = 0; memset(sense, 0, SENSE_BUF_LEN); /* v3 SG_IO */ memset(&iohdr, 0, sizeof(iohdr)); iohdr.interface_id = 'S'; iohdr.dxfer_direction = SG_DXFER_NONE; iohdr.cmdp = cdb; iohdr.cmd_len = VERIFY16_CMDLEN; iohdr.sbp = sense; iohdr.mx_sb_len = SENSE_BUF_LEN; iohdr.flags |= SG_FLAG_Q_AT_TAIL; iohdr.timeout = 30000; /* 30s */ error = ioctl(disk->d_fd, SG_IO, &iohdr); if (error < 0) return error; dbg_printf("VERIFY(16) fd %d lba %"PRIu64" len %"PRIu64" info %x " "status %d masked %d msg %d host %d driver %d " "duration %d resid %d\n", disk->d_fd, startblock, blockcount, iohdr.info, iohdr.status, iohdr.masked_status, iohdr.msg_status, iohdr.host_status, iohdr.driver_status, iohdr.duration, iohdr.resid); if (iohdr.info & SG_INFO_CHECK) { dbg_printf("status: msg %x host %x driver %x\n", iohdr.msg_status, iohdr.host_status, iohdr.driver_status); errno = EIO; return -1; } return blockcount << BBSHIFT; } #else # define disk_scsi_verify(...) (ENOTTY) #endif /* HAVE_SG_IO */ /* Test the availability of the kernel scrub ioctl. */ static bool disk_can_scsi_verify( struct disk *disk) { int error; if (debug_tweak_on("XFS_SCRUB_NO_SCSI_VERIFY")) return false; error = disk_scsi_verify(disk, 0, 1); return error == 0; } /* Open a disk device and discover its geometry. */ struct disk * disk_open( const char *pathname) { #ifdef HAVE_HDIO_GETGEO struct hd_geometry bdgeo; #endif struct disk *disk; bool suspicious_disk = false; int error; disk = calloc(1, sizeof(struct disk)); if (!disk) return NULL; disk->d_fd = open(pathname, O_RDONLY | O_DIRECT | O_NOATIME); if (disk->d_fd < 0) goto out_free; /* Try to get LBA size. */ error = ioctl(disk->d_fd, BLKSSZGET, &disk->d_lbasize); if (error) disk->d_lbasize = 512; disk->d_lbalog = log2_roundup(disk->d_lbasize); /* Obtain disk's stat info. */ error = fstat(disk->d_fd, &disk->d_sb); if (error) goto out_close; /* Determine bdev size, block size, and offset. */ if (S_ISBLK(disk->d_sb.st_mode)) { error = ioctl(disk->d_fd, BLKGETSIZE64, &disk->d_size); if (error) disk->d_size = 0; error = ioctl(disk->d_fd, BLKBSZGET, &disk->d_blksize); if (error) disk->d_blksize = 0; #ifdef HAVE_HDIO_GETGEO error = ioctl(disk->d_fd, HDIO_GETGEO, &bdgeo); if (!error) { /* * dm devices will pass through ioctls, which means * we can't use SCSI VERIFY unless the start is 0. * Most dm devices don't set geometry (unlike scsi * and nvme) so use a zeroed out CHS to screen them * out. */ if (bdgeo.start != 0 && (unsigned long long)bdgeo.heads * bdgeo.sectors * bdgeo.sectors == 0) suspicious_disk = true; disk->d_start = bdgeo.start << BBSHIFT; } else #endif disk->d_start = 0; } else { disk->d_size = disk->d_sb.st_size; disk->d_blksize = disk->d_sb.st_blksize; disk->d_start = 0; } /* Can we issue SCSI VERIFY? */ if (!suspicious_disk && disk_can_scsi_verify(disk)) disk->d_flags |= DISK_FLAG_SCSI_VERIFY; return disk; out_close: close(disk->d_fd); out_free: free(disk); return NULL; } /* Close a disk device. */ int disk_close( struct disk *disk) { int error = 0; if (disk->d_fd >= 0) error = close(disk->d_fd); disk->d_fd = -1; free(disk); return error; } #define BTOLBAT(d, bytes) ((uint64_t)(bytes) >> (d)->d_lbalog) #define LBASIZE(d) (1ULL << (d)->d_lbalog) #define BTOLBA(d, bytes) (((uint64_t)(bytes) + LBASIZE(d) - 1) >> (d)->d_lbalog) /* Simulate disk errors. */ static int disk_simulate_read_error( struct disk *disk, uint64_t start, uint64_t *length) { static int64_t interval; uint64_t start_interval; /* Simulated disk errors are disabled. */ if (interval < 0) return 0; /* Figure out the disk read error interval. */ if (interval == 0) { char *p; /* Pretend there's bad media every so often, in bytes. */ p = getenv("XFS_SCRUB_DISK_ERROR_INTERVAL"); if (p == NULL) { interval = -1; return 0; } interval = strtoull(p, NULL, 10); interval &= ~((1U << disk->d_lbalog) - 1); } if (interval <= 0) { interval = -1; return 0; } /* * We simulate disk errors by pretending that there are media errors at * predetermined intervals across the disk. If a read verify request * crosses one of those intervals we shorten it so that the next read * will start on an interval threshold. If the read verify request * starts on an interval threshold, we send back EIO as if it had * failed. */ if ((start % interval) == 0) { dbg_printf("fd %d: simulating disk error at %"PRIu64".\n", disk->d_fd, start); return EIO; } start_interval = start / interval; if (start_interval != (start + *length) / interval) { *length = ((start_interval + 1) * interval) - start; dbg_printf( "fd %d: simulating short read at %"PRIu64" to length %"PRIu64".\n", disk->d_fd, start, *length); } return 0; } /* Read-verify an extent of a disk device. */ ssize_t disk_read_verify( struct disk *disk, void *buf, uint64_t start, uint64_t length) { if (debug) { int ret; ret = disk_simulate_read_error(disk, start, &length); if (ret) { errno = ret; return -1; } /* Don't actually issue the IO */ if (getenv("XFS_SCRUB_DISK_VERIFY_SKIP")) return length; } /* Convert to logical block size. */ if (disk->d_flags & DISK_FLAG_SCSI_VERIFY) return disk_scsi_verify(disk, BTOLBAT(disk, start), BTOLBA(disk, length)); return pread(disk->d_fd, buf, length, start); } xfsprogs-5.3.0/scrub/disk.h0000644000175000017500000000132513570057155015476 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_DISK_H_ #define XFS_SCRUB_DISK_H_ #define DISK_FLAG_SCSI_VERIFY 0x1 struct disk { struct stat d_sb; int d_fd; unsigned int d_lbalog; unsigned int d_lbasize; /* bytes */ unsigned int d_flags; unsigned int d_blksize; /* bytes */ uint64_t d_size; /* bytes */ uint64_t d_start; /* bytes */ }; unsigned int disk_heads(struct disk *disk); struct disk *disk_open(const char *pathname); int disk_close(struct disk *disk); ssize_t disk_read_verify(struct disk *disk, void *buf, uint64_t startblock, uint64_t blockcount); #endif /* XFS_SCRUB_DISK_H_ */ xfsprogs-5.3.0/scrub/filemap.c0000644000175000017500000000530413570057155016155 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "filemap.h" /* * These routines provide a simple interface to query the block * mappings of the fork of a given inode via GETBMAPX and call a * function to iterate each mapping result. */ #define BMAP_NR 2048 /* * Iterate all the extent block mappings between the key and fork end. * Returns 0 or a positive error number. */ int scrub_iterate_filemaps( struct scrub_ctx *ctx, int fd, int whichfork, struct file_bmap *key, scrub_bmap_iter_fn fn, void *arg) { struct fsxattr fsx; struct getbmapx *map; struct getbmapx *p; struct file_bmap bmap; xfs_off_t new_off; int getxattr_type; int i; int ret; map = calloc(BMAP_NR, sizeof(struct getbmapx)); if (!map) return errno; map->bmv_offset = BTOBB(key->bm_offset); map->bmv_block = BTOBB(key->bm_physical); if (key->bm_length == 0) map->bmv_length = ULLONG_MAX; else map->bmv_length = BTOBB(key->bm_length); map->bmv_iflags = BMV_IF_NO_DMAPI_READ | BMV_IF_PREALLOC | BMV_IF_NO_HOLES; switch (whichfork) { case XFS_ATTR_FORK: getxattr_type = XFS_IOC_FSGETXATTRA; map->bmv_iflags |= BMV_IF_ATTRFORK; break; case XFS_COW_FORK: map->bmv_iflags |= BMV_IF_COWFORK; getxattr_type = FS_IOC_FSGETXATTR; break; case XFS_DATA_FORK: getxattr_type = FS_IOC_FSGETXATTR; break; default: abort(); } ret = ioctl(fd, getxattr_type, &fsx); if (ret < 0) { ret = errno; goto out; } if (fsx.fsx_nextents == 0) goto out; map->bmv_count = min(fsx.fsx_nextents + 1, BMAP_NR); while ((ret = ioctl(fd, XFS_IOC_GETBMAPX, map)) == 0) { for (i = 0, p = &map[i + 1]; i < map->bmv_entries; i++, p++) { bmap.bm_offset = BBTOB(p->bmv_offset); bmap.bm_physical = BBTOB(p->bmv_block); bmap.bm_length = BBTOB(p->bmv_length); bmap.bm_flags = p->bmv_oflags; ret = fn(ctx, fd, whichfork, &fsx, &bmap, arg); if (ret) goto out; if (xfs_scrub_excessive_errors(ctx)) goto out; } if (map->bmv_entries == 0) break; p = map + map->bmv_entries; if (p->bmv_oflags & BMV_OF_LAST) break; new_off = p->bmv_offset + p->bmv_length; map->bmv_length -= new_off - map->bmv_offset; map->bmv_offset = new_off; } if (ret < 0) ret = errno; /* * Pre-reflink filesystems don't know about CoW forks, so don't * be too surprised if it fails. */ if (whichfork == XFS_COW_FORK && ret == EINVAL) ret = 0; out: free(map); return ret; } xfsprogs-5.3.0/scrub/filemap.h0000644000175000017500000000162613570057155016165 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_FILEMAP_H_ #define XFS_SCRUB_FILEMAP_H_ /* inode fork block mapping */ struct file_bmap { uint64_t bm_offset; /* file offset of segment in bytes */ uint64_t bm_physical; /* physical starting byte */ uint64_t bm_length; /* length of segment, bytes */ uint32_t bm_flags; /* output flags */ }; /* * Visit each inode fork mapping. Return 0 to continue iteration or a positive * error code to stop iterating and return to the caller. */ typedef int (*scrub_bmap_iter_fn)(struct scrub_ctx *ctx, int fd, int whichfork, struct fsxattr *fsx, struct file_bmap *bmap, void *arg); int scrub_iterate_filemaps(struct scrub_ctx *ctx, int fd, int whichfork, struct file_bmap *key, scrub_bmap_iter_fn fn, void *arg); #endif /* XFS_SCRUB_FILEMAP_H_ */ xfsprogs-5.3.0/scrub/fscounters.c0000644000175000017500000000716513570057155016742 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "platform_defs.h" #include "xfs_arch.h" #include "xfs_format.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "fscounters.h" #include "libfrog/bulkstat.h" /* * Filesystem counter collection routines. We can count the number of * inodes in the filesystem, and we can estimate the block counters. */ /* Count the number of inodes in the filesystem. */ /* INUMBERS wrapper routines. */ struct count_inodes { int error; uint64_t counters[0]; }; /* * Count the number of inodes. Use INUMBERS to figure out how many inodes * exist in the filesystem, assuming we've already scrubbed that. */ static void count_ag_inodes( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct count_inodes *ci = arg; struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; struct xfs_inumbers_req *ireq; uint64_t nr = 0; unsigned int i; int error; error = -xfrog_inumbers_alloc_req(64, 0, &ireq); if (error) { ci->error = error; return; } xfrog_inumbers_set_ag(ireq, agno); while (!ci->error && (error = -xfrog_inumbers(&ctx->mnt, ireq)) == 0) { if (ireq->hdr.ocount == 0) break; for (i = 0; i < ireq->hdr.ocount; i++) nr += ireq->inumbers[i].xi_alloccount; } if (error) ci->error = error; free(ireq); ci->counters[agno] = nr; } /* * Count all the inodes in a filesystem. Returns 0 or a positive error number. */ int scrub_count_all_inodes( struct scrub_ctx *ctx, uint64_t *count) { struct count_inodes *ci; xfs_agnumber_t agno; struct workqueue wq; int ret, ret2; ci = calloc(1, sizeof(struct count_inodes) + (ctx->mnt.fsgeom.agcount * sizeof(uint64_t))); if (!ci) return errno; ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, scrub_nproc_workqueue(ctx)); if (ret) goto out_free; for (agno = 0; agno < ctx->mnt.fsgeom.agcount && !ci->error; agno++) { ret = -workqueue_add(&wq, count_ag_inodes, agno, ci); if (ret) break; } ret2 = -workqueue_terminate(&wq); if (!ret && ret2) ret = ret2; workqueue_destroy(&wq); if (ci->error) { ret = ci->error; goto out_free; } for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) *count += ci->counters[agno]; out_free: free(ci); return ret; } /* * Estimate the number of blocks and inodes in the filesystem. Returns 0 * or a positive error number. */ int scrub_scan_estimate_blocks( struct scrub_ctx *ctx, unsigned long long *d_blocks, unsigned long long *d_bfree, unsigned long long *r_blocks, unsigned long long *r_bfree, unsigned long long *f_files, unsigned long long *f_free) { struct xfs_fsop_counts fc; struct xfs_fsop_resblks rb; struct statvfs sfs; int error; /* Grab the fstatvfs counters, since it has to report accurately. */ error = fstatvfs(ctx->mnt.fd, &sfs); if (error) return errno; /* Fetch the filesystem counters. */ error = ioctl(ctx->mnt.fd, XFS_IOC_FSCOUNTS, &fc); if (error) return errno; /* * XFS reserves some blocks to prevent hard ENOSPC, so add those * blocks back to the free data counts. */ error = ioctl(ctx->mnt.fd, XFS_IOC_GET_RESBLKS, &rb); if (error) return errno; sfs.f_bfree += rb.resblks_avail; *d_blocks = sfs.f_blocks; if (ctx->mnt.fsgeom.logstart > 0) *d_blocks += ctx->mnt.fsgeom.logblocks; *d_bfree = sfs.f_bfree; *r_blocks = ctx->mnt.fsgeom.rtblocks; *r_bfree = fc.freertx; *f_files = sfs.f_files; *f_free = sfs.f_ffree; return 0; } xfsprogs-5.3.0/scrub/fscounters.h0000644000175000017500000000105413570057155016736 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_FSCOUNTERS_H_ #define XFS_SCRUB_FSCOUNTERS_H_ int scrub_scan_estimate_blocks(struct scrub_ctx *ctx, unsigned long long *d_blocks, unsigned long long *d_bfree, unsigned long long *r_blocks, unsigned long long *r_bfree, unsigned long long *f_files, unsigned long long *f_free); int scrub_count_all_inodes(struct scrub_ctx *ctx, uint64_t *count); #endif /* XFS_SCRUB_FSCOUNTERS_H_ */ xfsprogs-5.3.0/scrub/inodes.c0000644000175000017500000001536013570057155016024 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "platform_defs.h" #include "xfs_arch.h" #include "xfs_format.h" #include "handle.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "inodes.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" /* * Iterate a range of inodes. * * This is a little more involved than repeatedly asking BULKSTAT for a * buffer's worth of stat data for some number of inodes. We want to scan as * many of the inodes that the inobt thinks there are, including the ones that * are broken, but if we ask for n inodes starting at x, it'll skip the bad * ones and fill from beyond the range (x + n). * * Therefore, we ask INUMBERS to return one inobt chunk's worth of inode * bitmap information. Then we try to BULKSTAT only the inodes that were * present in that chunk, and compare what we got against what INUMBERS said * was there. If there's a mismatch, we know that we have an inode that fails * the verifiers but we can inject the bulkstat information to force the scrub * code to deal with the broken inodes. * * If the iteration function returns ESTALE, that means that the inode has * been deleted and possibly recreated since the BULKSTAT call. We wil * refresh the stat information and try again up to 30 times before reporting * the staleness as an error. */ /* * Run bulkstat on an entire inode allocation group, then check that we got * exactly the inodes we expected. If not, load them one at a time (or fake * it) into the bulkstat data. */ static void bulkstat_for_inumbers( struct scrub_ctx *ctx, const char *descr, const struct xfs_inumbers *inumbers, struct xfs_bulkstat_req *breq) { struct xfs_bulkstat *bstat = breq->bulkstat; struct xfs_bulkstat *bs; int i; int error; /* First we try regular bulkstat, for speed. */ breq->hdr.ino = inumbers->xi_startino; breq->hdr.icount = inumbers->xi_alloccount; error = -xfrog_bulkstat(&ctx->mnt, breq); if (error) { char errbuf[DESCR_BUFSZ]; str_info(ctx, descr, "%s", strerror_r(error, errbuf, DESCR_BUFSZ)); } /* * Check each of the stats we got back to make sure we got the inodes * we asked for. */ for (i = 0, bs = bstat; i < XFS_INODES_PER_CHUNK; i++) { if (!(inumbers->xi_allocmask & (1ULL << i))) continue; if (bs->bs_ino == inumbers->xi_startino + i) { bs++; continue; } /* Load the one inode. */ error = -xfrog_bulkstat_single(&ctx->mnt, inumbers->xi_startino + i, 0, bs); if (error || bs->bs_ino != inumbers->xi_startino + i) { memset(bs, 0, sizeof(struct xfs_bulkstat)); bs->bs_ino = inumbers->xi_startino + i; bs->bs_blksize = ctx->mnt_sv.f_frsize; } bs++; } } /* BULKSTAT wrapper routines. */ struct scan_inodes { scrub_inode_iter_fn fn; void *arg; bool aborted; }; /* * Call into the filesystem for inode/bulkstat information and call our * iterator function. We'll try to fill the bulkstat information in batches, * but we also can detect iget failures. */ static void scan_ag_inodes( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct xfs_handle handle; char descr[DESCR_BUFSZ]; struct xfs_inumbers_req *ireq; struct xfs_bulkstat_req *breq; struct scan_inodes *si = arg; struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; struct xfs_bulkstat *bs; struct xfs_inumbers *inumbers; int i; int error; int stale_count = 0; snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"), major(ctx->fsinfo.fs_datadev), minor(ctx->fsinfo.fs_datadev), agno); memcpy(&handle.ha_fsid, ctx->fshandle, sizeof(handle.ha_fsid)); handle.ha_fid.fid_len = sizeof(xfs_fid_t) - sizeof(handle.ha_fid.fid_len); handle.ha_fid.fid_pad = 0; error = -xfrog_bulkstat_alloc_req(XFS_INODES_PER_CHUNK, 0, &breq); if (error) { str_liberror(ctx, error, descr); si->aborted = true; return; } error = -xfrog_inumbers_alloc_req(1, 0, &ireq); if (error) { str_liberror(ctx, error, descr); free(breq); si->aborted = true; return; } inumbers = &ireq->inumbers[0]; xfrog_inumbers_set_ag(ireq, agno); /* Find the inode chunk & alloc mask */ error = -xfrog_inumbers(&ctx->mnt, ireq); while (!error && !si->aborted && ireq->hdr.ocount > 0) { /* * We can have totally empty inode chunks on filesystems where * there are more than 64 inodes per block. Skip these. */ if (inumbers->xi_alloccount == 0) goto igrp_retry; bulkstat_for_inumbers(ctx, descr, inumbers, breq); /* Iterate all the inodes. */ for (i = 0, bs = breq->bulkstat; !si->aborted && i < inumbers->xi_alloccount; i++, bs++) { handle.ha_fid.fid_ino = bs->bs_ino; handle.ha_fid.fid_gen = bs->bs_gen; error = si->fn(ctx, &handle, bs, si->arg); switch (error) { case 0: break; case ESTALE: { char idescr[DESCR_BUFSZ]; stale_count++; if (stale_count < 30) { ireq->hdr.ino = inumbers->xi_startino; goto igrp_retry; } scrub_render_ino_descr(ctx, idescr, DESCR_BUFSZ, bs->bs_ino, bs->bs_gen, NULL); str_info(ctx, idescr, _("Changed too many times during scan; giving up.")); break; } case ECANCELED: error = 0; /* fall thru */ default: goto err; } if (xfs_scrub_excessive_errors(ctx)) { si->aborted = true; goto out; } } stale_count = 0; igrp_retry: error = -xfrog_inumbers(&ctx->mnt, ireq); } err: if (error) { str_liberror(ctx, error, descr); si->aborted = true; } out: free(ireq); free(breq); } /* * Scan all the inodes in a filesystem. On error, this function will log * an error message and return -1. */ int scrub_scan_all_inodes( struct scrub_ctx *ctx, scrub_inode_iter_fn fn, void *arg) { struct scan_inodes si = { .fn = fn, .arg = arg, }; xfs_agnumber_t agno; struct workqueue wq; int ret; ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, scrub_nproc_workqueue(ctx)); if (ret) { str_liberror(ctx, ret, _("creating bulkstat workqueue")); return -1; } for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) { ret = -workqueue_add(&wq, scan_ag_inodes, agno, &si); if (ret) { si.aborted = true; str_liberror(ctx, ret, _("queueing bulkstat work")); break; } } ret = -workqueue_terminate(&wq); if (ret) { si.aborted = true; str_liberror(ctx, ret, _("finishing bulkstat work")); } workqueue_destroy(&wq); return si.aborted ? -1 : 0; } /* Open a file by handle, returning either the fd or -1 on error. */ int scrub_open_handle( struct xfs_handle *handle) { return open_by_fshandle(handle, sizeof(*handle), O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); } xfsprogs-5.3.0/scrub/inodes.h0000644000175000017500000000166413570057155016033 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_INODES_H_ #define XFS_SCRUB_INODES_H_ /* * Visit each space mapping of an inode fork. Return 0 to continue iteration * or a positive error code to interrupt iteraton. If ESTALE is returned, * iteration will be restarted from the beginning of the inode allocation * group. Any other non zero value will stop iteration. The special return * value ECANCELED can be used to stop iteration, because the inode iteration * function never generates that error code on its own. */ typedef int (*scrub_inode_iter_fn)(struct scrub_ctx *ctx, struct xfs_handle *handle, struct xfs_bulkstat *bs, void *arg); int scrub_scan_all_inodes(struct scrub_ctx *ctx, scrub_inode_iter_fn fn, void *arg); int scrub_open_handle(struct xfs_handle *handle); #endif /* XFS_SCRUB_INODES_H_ */ xfsprogs-5.3.0/scrub/phase1.c0000644000175000017500000001210013570057155015711 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include #include #include #include #include "libfrog/util.h" #include "libfrog/workqueue.h" #include "input.h" #include "libfrog/paths.h" #include "handle.h" #include "bitops.h" #include "libfrog/avl64.h" #include "list.h" #include "xfs_scrub.h" #include "common.h" #include "disk.h" #include "scrub.h" #include "repair.h" #include "libfrog/fsgeom.h" /* Phase 1: Find filesystem geometry (and clean up after) */ /* Shut down the filesystem. */ void xfs_shutdown_fs( struct scrub_ctx *ctx) { int flag; flag = XFS_FSOP_GOING_FLAGS_LOGFLUSH; str_info(ctx, ctx->mntpoint, _("Shutting down filesystem!")); if (ioctl(ctx->mnt.fd, XFS_IOC_GOINGDOWN, &flag)) str_errno(ctx, ctx->mntpoint); } /* Clean up the XFS-specific state data. */ int scrub_cleanup( struct scrub_ctx *ctx) { int error; action_lists_free(&ctx->action_lists); if (ctx->fshandle) free_handle(ctx->fshandle, ctx->fshandle_len); if (ctx->rtdev) disk_close(ctx->rtdev); if (ctx->logdev) disk_close(ctx->logdev); if (ctx->datadev) disk_close(ctx->datadev); fshandle_destroy(); error = -xfd_close(&ctx->mnt); if (error) str_liberror(ctx, error, _("closing mountpoint fd")); fs_table_destroy(); return error; } /* * Bind to the mountpoint, read the XFS geometry, bind to the block devices. * Anything we've already built will be cleaned up by scrub_cleanup. */ int phase1_func( struct scrub_ctx *ctx) { int error; /* * Open the directory with O_NOATIME. For mountpoints owned * by root, this should be sufficient to ensure that we have * CAP_SYS_ADMIN, which we probably need to do anything fancy * with the (XFS driver) kernel. */ error = -xfd_open(&ctx->mnt, ctx->mntpoint, O_RDONLY | O_NOATIME | O_DIRECTORY); if (error) { if (error == EPERM) str_error(ctx, ctx->mntpoint, _("Must be root to run scrub.")); else if (error == ENOTTY) str_error(ctx, ctx->mntpoint, _("Not an XFS filesystem.")); else str_liberror(ctx, error, ctx->mntpoint); return error; } error = fstat(ctx->mnt.fd, &ctx->mnt_sb); if (error) { str_errno(ctx, ctx->mntpoint); return error; } error = fstatvfs(ctx->mnt.fd, &ctx->mnt_sv); if (error) { str_errno(ctx, ctx->mntpoint); return error; } error = fstatfs(ctx->mnt.fd, &ctx->mnt_sf); if (error) { str_errno(ctx, ctx->mntpoint); return error; } /* * Flush everything out to disk before we start checking. * This seems to reduce the incidence of stale file handle * errors when we open things by handle. */ error = syncfs(ctx->mnt.fd); if (error) { str_errno(ctx, ctx->mntpoint); return error; } error = action_lists_alloc(ctx->mnt.fsgeom.agcount, &ctx->action_lists); if (error) { str_liberror(ctx, error, _("allocating action lists")); return error; } error = path_to_fshandle(ctx->mntpoint, &ctx->fshandle, &ctx->fshandle_len); if (error) { str_errno(ctx, _("getting fshandle")); return error; } /* Do we have kernel-assisted metadata scrubbing? */ if (!xfs_can_scrub_fs_metadata(ctx) || !xfs_can_scrub_inode(ctx) || !xfs_can_scrub_bmap(ctx) || !xfs_can_scrub_dir(ctx) || !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) || !xfs_can_scrub_parent(ctx)) { str_error(ctx, ctx->mntpoint, _("Kernel metadata scrubbing facility is not available.")); return ECANCELED; } /* Do we need kernel-assisted metadata repair? */ if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) { str_error(ctx, ctx->mntpoint, _("Kernel metadata repair facility is not available. Use -n to scrub.")); return ECANCELED; } /* Did we find the log and rt devices, if they're present? */ if (ctx->mnt.fsgeom.logstart == 0 && ctx->fsinfo.fs_log == NULL) { str_error(ctx, ctx->mntpoint, _("Unable to find log device path.")); return ECANCELED; } if (ctx->mnt.fsgeom.rtblocks && ctx->fsinfo.fs_rt == NULL) { str_error(ctx, ctx->mntpoint, _("Unable to find realtime device path.")); return ECANCELED; } /* Open the raw devices. */ ctx->datadev = disk_open(ctx->fsinfo.fs_name); if (error) { str_errno(ctx, ctx->fsinfo.fs_name); return error; } ctx->nr_io_threads = disk_heads(ctx->datadev); if (verbose) { fprintf(stdout, _("%s: using %d threads to scrub.\n"), ctx->mntpoint, scrub_nproc(ctx)); fflush(stdout); } if (ctx->fsinfo.fs_log) { ctx->logdev = disk_open(ctx->fsinfo.fs_log); if (error) { str_errno(ctx, ctx->fsinfo.fs_name); return error; } } if (ctx->fsinfo.fs_rt) { ctx->rtdev = disk_open(ctx->fsinfo.fs_rt); if (error) { str_errno(ctx, ctx->fsinfo.fs_name); return error; } } /* * Everything's set up, which means any failures recorded after * this point are most probably corruption errors (as opposed to * purely setup errors). */ log_info(ctx, _("Invoking online scrub."), ctx); ctx->scrub_setup_succeeded = true; return 0; } xfsprogs-5.3.0/scrub/phase2.c0000644000175000017500000001052413570057155015722 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "list.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "scrub.h" #include "repair.h" /* Phase 2: Check internal metadata. */ /* Scrub each AG's metadata btrees. */ static void scan_ag_metadata( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; bool *aborted = arg; struct action_list alist; struct action_list immediate_alist; unsigned long long broken_primaries; unsigned long long broken_secondaries; char descr[DESCR_BUFSZ]; int ret; if (*aborted) return; action_list_init(&alist); action_list_init(&immediate_alist); snprintf(descr, DESCR_BUFSZ, _("AG %u"), agno); /* * First we scrub and fix the AG headers, because we need * them to work well enough to check the AG btrees. */ ret = xfs_scrub_ag_headers(ctx, agno, &alist); if (ret) goto err; /* Repair header damage. */ ret = action_list_process_or_defer(ctx, agno, &alist); if (ret) goto err; /* Now scrub the AG btrees. */ ret = xfs_scrub_ag_metadata(ctx, agno, &alist); if (ret) goto err; /* * Figure out if we need to perform early fixing. The only * reason we need to do this is if the inobt is broken, which * prevents phase 3 (inode scan) from running. We can rebuild * the inobt from rmapbt data, but if the rmapbt is broken even * at this early phase then we are sunk. */ broken_secondaries = 0; broken_primaries = 0; action_list_find_mustfix(&alist, &immediate_alist, &broken_primaries, &broken_secondaries); if (broken_secondaries && !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) { if (broken_primaries) str_info(ctx, descr, _("Corrupt primary and secondary block mapping metadata.")); else str_info(ctx, descr, _("Corrupt secondary block mapping metadata.")); str_info(ctx, descr, _("Filesystem might not be repairable.")); } /* Repair (inode) btree damage. */ ret = action_list_process_or_defer(ctx, agno, &immediate_alist); if (ret) goto err; /* Everything else gets fixed during phase 4. */ action_list_defer(ctx, agno, &alist); return; err: *aborted = true; } /* Scrub whole-FS metadata btrees. */ static void scan_fs_metadata( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; bool *aborted = arg; struct action_list alist; int ret; if (*aborted) return; action_list_init(&alist); ret = xfs_scrub_fs_metadata(ctx, &alist); if (ret) { *aborted = true; return; } action_list_defer(ctx, agno, &alist); } /* Scan all filesystem metadata. */ int phase2_func( struct scrub_ctx *ctx) { struct action_list alist; struct workqueue wq; xfs_agnumber_t agno; bool aborted = false; int ret, ret2; ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, scrub_nproc_workqueue(ctx)); if (ret) { str_liberror(ctx, ret, _("creating scrub workqueue")); return ret; } /* * In case we ever use the primary super scrubber to perform fs * upgrades (followed by a full scrub), do that before we launch * anything else. */ action_list_init(&alist); ret = xfs_scrub_primary_super(ctx, &alist); if (ret) goto out; ret = action_list_process_or_defer(ctx, 0, &alist); if (ret) goto out; for (agno = 0; !aborted && agno < ctx->mnt.fsgeom.agcount; agno++) { ret = -workqueue_add(&wq, scan_ag_metadata, agno, &aborted); if (ret) { str_liberror(ctx, ret, _("queueing per-AG scrub work")); goto out; } } if (aborted) goto out; ret = -workqueue_add(&wq, scan_fs_metadata, 0, &aborted); if (ret) { str_liberror(ctx, ret, _("queueing per-FS scrub work")); goto out; } out: ret2 = -workqueue_terminate(&wq); if (ret2) { str_liberror(ctx, ret2, _("finishing scrub work")); if (!ret && ret2) ret = ret2; } workqueue_destroy(&wq); if (!ret && aborted) ret = ECANCELED; return ret; } /* Estimate how much work we're going to do. */ int phase2_estimate( struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift) { *items = scrub_estimate_ag_work(ctx); *nr_threads = scrub_nproc(ctx); *rshift = 0; return 0; } xfsprogs-5.3.0/scrub/phase3.c0000644000175000017500000001100713570057155015720 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "list.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "counter.h" #include "inodes.h" #include "progress.h" #include "scrub.h" #include "repair.h" /* Phase 3: Scan all inodes. */ /* * Run a per-file metadata scanner. We use the ino/gen interface to * ensure that the inode we're checking matches what the inode scan * told us to look at. */ static int scrub_fd( struct scrub_ctx *ctx, int (*fn)(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *a), struct xfs_bulkstat *bs, struct action_list *alist) { return fn(ctx, bs->bs_ino, bs->bs_gen, alist); } struct scrub_inode_ctx { struct ptcounter *icount; bool aborted; }; /* Report a filesystem error that the vfs fed us on close. */ static void report_close_error( struct scrub_ctx *ctx, struct xfs_bulkstat *bstat) { char descr[DESCR_BUFSZ]; int old_errno = errno; scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ, bstat->bs_ino, bstat->bs_gen, NULL); errno = old_errno; str_errno(ctx, descr); } /* Verify the contents, xattrs, and extent maps of an inode. */ static int scrub_inode( struct scrub_ctx *ctx, struct xfs_handle *handle, struct xfs_bulkstat *bstat, void *arg) { struct action_list alist; struct scrub_inode_ctx *ictx = arg; struct ptcounter *icount = ictx->icount; xfs_agnumber_t agno; int fd = -1; int error; action_list_init(&alist); agno = cvt_ino_to_agno(&ctx->mnt, bstat->bs_ino); background_sleep(); /* Try to open the inode to pin it. */ if (S_ISREG(bstat->bs_mode)) { fd = scrub_open_handle(handle); /* Stale inode means we scan the whole cluster again. */ if (fd < 0 && errno == ESTALE) return ESTALE; } /* Scrub the inode. */ error = scrub_fd(ctx, xfs_scrub_inode_fields, bstat, &alist); if (error) goto out; error = action_list_process_or_defer(ctx, agno, &alist); if (error) goto out; /* Scrub all block mappings. */ error = scrub_fd(ctx, xfs_scrub_data_fork, bstat, &alist); if (error) goto out; error = scrub_fd(ctx, xfs_scrub_attr_fork, bstat, &alist); if (error) goto out; error = scrub_fd(ctx, xfs_scrub_cow_fork, bstat, &alist); if (error) goto out; error = action_list_process_or_defer(ctx, agno, &alist); if (error) goto out; if (S_ISLNK(bstat->bs_mode)) { /* Check symlink contents. */ error = xfs_scrub_symlink(ctx, bstat->bs_ino, bstat->bs_gen, &alist); } else if (S_ISDIR(bstat->bs_mode)) { /* Check the directory entries. */ error = scrub_fd(ctx, xfs_scrub_dir, bstat, &alist); } if (error) goto out; /* Check all the extended attributes. */ error = scrub_fd(ctx, xfs_scrub_attr, bstat, &alist); if (error) goto out; /* Check parent pointers. */ error = scrub_fd(ctx, xfs_scrub_parent, bstat, &alist); if (error) goto out; /* Try to repair the file while it's open. */ error = action_list_process_or_defer(ctx, agno, &alist); if (error) goto out; out: if (error) ictx->aborted = true; error = ptcounter_add(icount, 1); if (error) { str_liberror(ctx, error, _("incrementing scanned inode counter")); ictx->aborted = true; } progress_add(1); action_list_defer(ctx, agno, &alist); if (fd >= 0) { int err2; err2 = close(fd); if (err2) { report_close_error(ctx, bstat); ictx->aborted = true; } } if (!error && ictx->aborted) error = ECANCELED; return error; } /* Verify all the inodes in a filesystem. */ int phase3_func( struct scrub_ctx *ctx) { struct scrub_inode_ctx ictx = { NULL }; uint64_t val; int err; err = ptcounter_alloc(scrub_nproc(ctx), &ictx.icount); if (err) { str_liberror(ctx, err, _("creating scanned inode counter")); return err; } err = scrub_scan_all_inodes(ctx, scrub_inode, &ictx); if (!err && ictx.aborted) err = ECANCELED; if (err) goto free; xfs_scrub_report_preen_triggers(ctx); err = ptcounter_value(ictx.icount, &val); if (err) { str_liberror(ctx, err, _("summing scanned inode counter")); return err; } ctx->inodes_checked = val; free: ptcounter_free(ictx.icount); return err; } /* Estimate how much work we're going to do. */ int phase3_estimate( struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift) { *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree; *nr_threads = scrub_nproc(ctx); *rshift = 0; return 0; } xfsprogs-5.3.0/scrub/phase4.c0000644000175000017500000000644513570057155015733 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "list.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "progress.h" #include "scrub.h" #include "repair.h" #include "vfs.h" /* Phase 4: Repair filesystem. */ /* Fix all the problems in our per-AG list. */ static void repair_ag( struct workqueue *wq, xfs_agnumber_t agno, void *priv) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; bool *aborted = priv; struct action_list *alist; size_t unfixed; size_t new_unfixed; unsigned int flags = 0; int ret; alist = &ctx->action_lists[agno]; unfixed = action_list_length(alist); /* Repair anything broken until we fail to make progress. */ do { ret = action_list_process(ctx, ctx->mnt.fd, alist, flags); if (ret) { *aborted = true; return; } new_unfixed = action_list_length(alist); if (new_unfixed == unfixed) break; unfixed = new_unfixed; if (*aborted) return; } while (unfixed > 0); /* Try once more, but this time complain if we can't fix things. */ flags |= ALP_COMPLAIN_IF_UNFIXED; ret = action_list_process(ctx, ctx->mnt.fd, alist, flags); if (ret) *aborted = true; } /* Process all the action items. */ static int repair_everything( struct scrub_ctx *ctx) { struct workqueue wq; xfs_agnumber_t agno; bool aborted = false; int ret; ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, scrub_nproc_workqueue(ctx)); if (ret) { str_liberror(ctx, ret, _("creating repair workqueue")); return ret; } for (agno = 0; !aborted && agno < ctx->mnt.fsgeom.agcount; agno++) { if (action_list_length(&ctx->action_lists[agno]) == 0) continue; ret = -workqueue_add(&wq, repair_ag, agno, &aborted); if (ret) { str_liberror(ctx, ret, _("queueing repair work")); break; } } ret = -workqueue_terminate(&wq); if (ret) str_liberror(ctx, ret, _("finishing repair work")); workqueue_destroy(&wq); if (aborted) return ECANCELED; pthread_mutex_lock(&ctx->lock); if (ctx->corruptions_found == 0 && ctx->unfixable_errors == 0 && want_fstrim) { fstrim(ctx); progress_add(1); } pthread_mutex_unlock(&ctx->lock); return 0; } /* Fix everything that needs fixing. */ int phase4_func( struct scrub_ctx *ctx) { int ret; /* * Check the summary counters early. Normally we do this during phase * seven, but some of the cross-referencing requires fairly-accurate * counters, so counter repairs have to be put on the list now so that * they get fixed before we stop retrying unfixed metadata repairs. */ ret = xfs_scrub_fs_summary(ctx, &ctx->action_lists[0]); if (ret) return ret; return repair_everything(ctx); } /* Estimate how much work we're going to do. */ int phase4_estimate( struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift) { xfs_agnumber_t agno; size_t need_fixing = 0; for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) need_fixing += action_list_length(&ctx->action_lists[agno]); need_fixing++; *items = need_fixing; *nr_threads = scrub_nproc(ctx) + 1; *rshift = 0; return 0; } xfsprogs-5.3.0/scrub/phase5.c0000644000175000017500000002146213570057155015730 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #ifdef HAVE_LIBATTR # include #endif #include #include "handle.h" #include "list.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "inodes.h" #include "progress.h" #include "scrub.h" #include "descr.h" #include "unicrash.h" /* Phase 5: Check directory connectivity. */ /* * Warn about problematic bytes in a directory/attribute name. That means * terminal control characters and escape sequences, since that could be used * to do something naughty to the user's computer and/or break scripts. XFS * doesn't consider any byte sequence invalid, so don't flag these as errors. * * Returns 0 for success or -1 for error. This function logs errors. */ static int simple_check_name( struct scrub_ctx *ctx, struct descr *dsc, const char *namedescr, const char *name) { const char *p; bool bad = false; char *errname; /* Complain about zero length names. */ if (*name == '\0' && should_warn_about_name(ctx)) { str_warn(ctx, descr_render(dsc), _("Zero length name found.")); return 0; } /* control characters */ for (p = name; *p; p++) { if ((*p >= 1 && *p <= 31) || *p == 127) { bad = true; break; } } if (bad && should_warn_about_name(ctx)) { errname = string_escape(name); if (!errname) { str_errno(ctx, descr_render(dsc)); return -1; } str_info(ctx, descr_render(dsc), _("Control character found in %s name \"%s\"."), namedescr, errname); free(errname); } return 0; } /* * Iterate a directory looking for filenames with problematic * characters. */ static int check_dirent_names( struct scrub_ctx *ctx, struct descr *dsc, int *fd, struct xfs_bulkstat *bstat) { struct unicrash *uc = NULL; DIR *dir; struct dirent *dentry; int ret; dir = fdopendir(*fd); if (!dir) { str_errno(ctx, descr_render(dsc)); return errno; } *fd = -1; /* closedir will close *fd for us */ ret = unicrash_dir_init(&uc, ctx, bstat); if (ret) { str_liberror(ctx, ret, descr_render(dsc)); goto out_unicrash; } errno = 0; dentry = readdir(dir); while (dentry) { if (uc) ret = unicrash_check_dir_name(uc, dsc, dentry); else ret = simple_check_name(ctx, dsc, _("directory"), dentry->d_name); if (ret) { str_liberror(ctx, ret, descr_render(dsc)); break; } errno = 0; dentry = readdir(dir); } if (errno) { ret = errno; str_liberror(ctx, ret, descr_render(dsc)); } unicrash_free(uc); out_unicrash: closedir(dir); return ret; } #ifdef HAVE_LIBATTR /* Routines to scan all of an inode's xattrs for name problems. */ struct attrns_decode { int flags; const char *name; }; static const struct attrns_decode attr_ns[] = { {0, "user"}, {ATTR_ROOT, "system"}, {ATTR_SECURE, "secure"}, {0, NULL}, }; /* * Check all the xattr names in a particular namespace of a file handle * for Unicode normalization problems or collisions. */ static int check_xattr_ns_names( struct scrub_ctx *ctx, struct descr *dsc, struct xfs_handle *handle, struct xfs_bulkstat *bstat, const struct attrns_decode *attr_ns) { struct attrlist_cursor cur; char attrbuf[XFS_XATTR_LIST_MAX]; char keybuf[XATTR_NAME_MAX + 1]; struct attrlist *attrlist = (struct attrlist *)attrbuf; struct attrlist_ent *ent; struct unicrash *uc = NULL; int i; int error; error = unicrash_xattr_init(&uc, ctx, bstat); if (error) { str_liberror(ctx, error, descr_render(dsc)); return error; } memset(attrbuf, 0, XFS_XATTR_LIST_MAX); memset(&cur, 0, sizeof(cur)); memset(keybuf, 0, XATTR_NAME_MAX + 1); error = attr_list_by_handle(handle, sizeof(*handle), attrbuf, XFS_XATTR_LIST_MAX, attr_ns->flags, &cur); while (!error) { /* Examine the xattrs. */ for (i = 0; i < attrlist->al_count; i++) { ent = ATTR_ENTRY(attrlist, i); snprintf(keybuf, XATTR_NAME_MAX, "%s.%s", attr_ns->name, ent->a_name); if (uc) error = unicrash_check_xattr_name(uc, dsc, keybuf); else error = simple_check_name(ctx, dsc, _("extended attribute"), keybuf); if (error) { str_liberror(ctx, error, descr_render(dsc)); goto out; } } if (!attrlist->al_more) break; error = attr_list_by_handle(handle, sizeof(*handle), attrbuf, XFS_XATTR_LIST_MAX, attr_ns->flags, &cur); } if (error) { if (errno == ESTALE) errno = 0; if (errno) str_errno(ctx, descr_render(dsc)); } out: unicrash_free(uc); return error; } /* * Check all the xattr names in all the xattr namespaces for problematic * characters. */ static int check_xattr_names( struct scrub_ctx *ctx, struct descr *dsc, struct xfs_handle *handle, struct xfs_bulkstat *bstat) { const struct attrns_decode *ns; int ret; for (ns = attr_ns; ns->name; ns++) { ret = check_xattr_ns_names(ctx, dsc, handle, bstat, ns); if (ret) break; } return ret; } #else # define check_xattr_names(c, d, h, b) (0) #endif /* HAVE_LIBATTR */ static int render_ino_from_handle( struct scrub_ctx *ctx, char *buf, size_t buflen, void *data) { struct xfs_bstat *bstat = data; return scrub_render_ino_descr(ctx, buf, buflen, bstat->bs_ino, bstat->bs_gen, NULL); } /* * Verify the connectivity of the directory tree. * We know that the kernel's open-by-handle function will try to reconnect * parents of an opened directory, so we'll accept that as sufficient. * * Check for potential Unicode collisions in names. */ static int check_inode_names( struct scrub_ctx *ctx, struct xfs_handle *handle, struct xfs_bulkstat *bstat, void *arg) { DEFINE_DESCR(dsc, ctx, render_ino_from_handle); bool *aborted = arg; int fd = -1; int error = 0; int err2; descr_set(&dsc, bstat); background_sleep(); /* Warn about naming problems in xattrs. */ if (bstat->bs_xflags & FS_XFLAG_HASATTR) { error = check_xattr_names(ctx, &dsc, handle, bstat); if (error) goto out; } /* Open the dir, let the kernel try to reconnect it to the root. */ if (S_ISDIR(bstat->bs_mode)) { fd = scrub_open_handle(handle); if (fd < 0) { error = errno; if (error == ESTALE) return ESTALE; str_errno(ctx, descr_render(&dsc)); goto out; } } /* Warn about naming problems in the directory entries. */ if (fd >= 0 && S_ISDIR(bstat->bs_mode)) { error = check_dirent_names(ctx, &dsc, &fd, bstat); if (error) goto out; } out: progress_add(1); if (fd >= 0) { err2 = close(fd); if (err2) str_errno(ctx, descr_render(&dsc)); if (!error && err2) error = err2; } if (error) *aborted = true; if (!error && *aborted) error = ECANCELED; return error; } #ifndef FS_IOC_GETFSLABEL # define FSLABEL_MAX 256 # define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX]) #endif /* FS_IOC_GETFSLABEL */ static int scrub_render_mountpoint( struct scrub_ctx *ctx, char *buf, size_t buflen, void *data) { return snprintf(buf, buflen, _("%s"), ctx->mntpoint); } /* * Check the filesystem label for Unicode normalization problems or misleading * sequences. */ static int check_fs_label( struct scrub_ctx *ctx) { DEFINE_DESCR(dsc, ctx, scrub_render_mountpoint); char label[FSLABEL_MAX]; struct unicrash *uc = NULL; int error; error = unicrash_fs_label_init(&uc, ctx); if (error) { str_liberror(ctx, error, descr_render(&dsc)); return error; } descr_set(&dsc, NULL); /* Retrieve label; quietly bail if we don't support that. */ error = ioctl(ctx->mnt.fd, FS_IOC_GETFSLABEL, &label); if (error) { if (errno != EOPNOTSUPP && errno != ENOTTY) { error = errno; perror(ctx->mntpoint); } goto out; } /* Ignore empty labels. */ if (label[0] == 0) goto out; /* Otherwise check for weirdness. */ if (uc) error = unicrash_check_fs_label(uc, &dsc, label); else error = simple_check_name(ctx, &dsc, _("filesystem label"), label); if (error) str_liberror(ctx, error, descr_render(&dsc)); out: unicrash_free(uc); return error; } /* Check directory connectivity. */ int phase5_func( struct scrub_ctx *ctx) { bool aborted = false; int ret; if (ctx->corruptions_found || ctx->unfixable_errors) { str_info(ctx, ctx->mntpoint, _("Filesystem has errors, skipping connectivity checks.")); return 0; } ret = check_fs_label(ctx); if (ret) return ret; ret = scrub_scan_all_inodes(ctx, check_inode_names, &aborted); if (ret) return ret; if (aborted) return ECANCELED; xfs_scrub_report_preen_triggers(ctx); return 0; } /* Estimate how much work we're going to do. */ int phase5_estimate( struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift) { *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree; *nr_threads = scrub_nproc(ctx); *rshift = 0; return 0; } xfsprogs-5.3.0/scrub/phase6.c0000644000175000017500000004233413570057155015732 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "handle.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "libfrog/bitmap.h" #include "disk.h" #include "filemap.h" #include "fscounters.h" #include "inodes.h" #include "read_verify.h" #include "spacemap.h" #include "vfs.h" /* * Phase 6: Verify data file integrity. * * Identify potential data block extents with GETFSMAP, then feed those * extents to the read-verify pool to get the verify commands batched, * issued, and (if there are problems) reported back to us. If there * are errors, we'll record the bad regions and (if available) use rmap * to tell us if metadata are now corrupt. Otherwise, we'll scan the * whole directory tree looking for files that overlap the bad regions * and report the paths of the now corrupt files. */ /* Verify disk blocks with GETFSMAP */ struct media_verify_state { struct read_verify_pool *rvp_data; struct read_verify_pool *rvp_log; struct read_verify_pool *rvp_realtime; struct bitmap *d_bad; /* bytes */ struct bitmap *r_bad; /* bytes */ }; /* Find the fd for a given device identifier. */ static struct read_verify_pool * dev_to_pool( struct scrub_ctx *ctx, struct media_verify_state *vs, dev_t dev) { if (dev == ctx->fsinfo.fs_datadev) return vs->rvp_data; else if (dev == ctx->fsinfo.fs_logdev) return vs->rvp_log; else if (dev == ctx->fsinfo.fs_rtdev) return vs->rvp_realtime; abort(); } /* Find the device major/minor for a given file descriptor. */ static dev_t disk_to_dev( struct scrub_ctx *ctx, struct disk *disk) { if (disk == ctx->datadev) return ctx->fsinfo.fs_datadev; else if (disk == ctx->logdev) return ctx->fsinfo.fs_logdev; else if (disk == ctx->rtdev) return ctx->fsinfo.fs_rtdev; abort(); } /* Find the incore bad blocks bitmap for a given disk. */ static struct bitmap * bitmap_for_disk( struct scrub_ctx *ctx, struct disk *disk, struct media_verify_state *vs) { dev_t dev = disk_to_dev(ctx, disk); if (dev == ctx->fsinfo.fs_datadev) return vs->d_bad; else if (dev == ctx->fsinfo.fs_rtdev) return vs->r_bad; return NULL; } struct disk_ioerr_report { struct scrub_ctx *ctx; struct disk *disk; }; struct owner_decode { uint64_t owner; const char *descr; }; static const struct owner_decode special_owners[] = { {XFS_FMR_OWN_FREE, "free space"}, {XFS_FMR_OWN_UNKNOWN, "unknown owner"}, {XFS_FMR_OWN_FS, "static FS metadata"}, {XFS_FMR_OWN_LOG, "journalling log"}, {XFS_FMR_OWN_AG, "per-AG metadata"}, {XFS_FMR_OWN_INOBT, "inode btree blocks"}, {XFS_FMR_OWN_INODES, "inodes"}, {XFS_FMR_OWN_REFC, "refcount btree"}, {XFS_FMR_OWN_COW, "CoW staging"}, {XFS_FMR_OWN_DEFECTIVE, "bad blocks"}, {0, NULL}, }; /* Decode a special owner. */ static const char * decode_special_owner( uint64_t owner) { const struct owner_decode *od = special_owners; while (od->descr) { if (od->owner == owner) return od->descr; od++; } return NULL; } /* Routines to translate bad physical extents into file paths and offsets. */ struct badfile_report { struct scrub_ctx *ctx; const char *descr; struct media_verify_state *vs; struct file_bmap *bmap; }; /* Report on bad extents found during a media scan. */ static int report_badfile( uint64_t start, uint64_t length, void *arg) { struct badfile_report *br = arg; unsigned long long bad_offset; unsigned long long bad_length; /* Clamp the bad region to the file mapping. */ if (start < br->bmap->bm_physical) { length -= br->bmap->bm_physical - start; start = br->bmap->bm_physical; } length = min(length, br->bmap->bm_length); /* Figure out how far into the bmap is the bad mapping and report it. */ bad_offset = start - br->bmap->bm_physical; bad_length = min(start + length, br->bmap->bm_physical + br->bmap->bm_length) - start; str_unfixable_error(br->ctx, br->descr, _("media error at data offset %llu length %llu."), br->bmap->bm_offset + bad_offset, bad_length); return 0; } /* Report if this extent overlaps a bad region. */ static int report_data_loss( struct scrub_ctx *ctx, int fd, int whichfork, struct fsxattr *fsx, struct file_bmap *bmap, void *arg) { struct badfile_report *br = arg; struct media_verify_state *vs = br->vs; struct bitmap *bmp; br->bmap = bmap; /* Only report errors for real extents. */ if (bmap->bm_flags & (BMV_OF_PREALLOC | BMV_OF_DELALLOC)) return 0; if (fsx->fsx_xflags & FS_XFLAG_REALTIME) bmp = vs->r_bad; else bmp = vs->d_bad; return -bitmap_iterate_range(bmp, bmap->bm_physical, bmap->bm_length, report_badfile, br); } /* Report if the extended attribute data overlaps a bad region. */ static int report_attr_loss( struct scrub_ctx *ctx, int fd, int whichfork, struct fsxattr *fsx, struct file_bmap *bmap, void *arg) { struct badfile_report *br = arg; struct media_verify_state *vs = br->vs; struct bitmap *bmp = vs->d_bad; /* Complain about attr fork extents that don't look right. */ if (bmap->bm_flags & (BMV_OF_PREALLOC | BMV_OF_DELALLOC)) { str_info(ctx, br->descr, _("found unexpected unwritten/delalloc attr fork extent.")); return 0; } if (fsx->fsx_xflags & FS_XFLAG_REALTIME) { str_info(ctx, br->descr, _("found unexpected realtime attr fork extent.")); return 0; } if (bitmap_test(bmp, bmap->bm_physical, bmap->bm_length)) str_corrupt(ctx, br->descr, _("media error in extended attribute data.")); return 0; } /* Iterate the extent mappings of a file to report errors. */ static int report_fd_loss( struct scrub_ctx *ctx, const char *descr, int fd, void *arg) { struct badfile_report br = { .ctx = ctx, .vs = arg, .descr = descr, }; struct file_bmap key = {0}; int ret; /* data fork */ ret = scrub_iterate_filemaps(ctx, fd, XFS_DATA_FORK, &key, report_data_loss, &br); if (ret) { str_liberror(ctx, ret, descr); return ret; } /* attr fork */ ret = scrub_iterate_filemaps(ctx, fd, XFS_ATTR_FORK, &key, report_attr_loss, &br); if (ret) { str_liberror(ctx, ret, descr); return ret; } return 0; } /* Report read verify errors in unlinked (but still open) files. */ static int report_inode_loss( struct scrub_ctx *ctx, struct xfs_handle *handle, struct xfs_bulkstat *bstat, void *arg) { char descr[DESCR_BUFSZ]; int fd; int error, err2; /* Ignore linked files and things we can't open. */ if (bstat->bs_nlink != 0) return 0; if (!S_ISREG(bstat->bs_mode) && !S_ISDIR(bstat->bs_mode)) return 0; scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ, bstat->bs_ino, bstat->bs_gen, _("(unlinked)")); /* Try to open the inode. */ fd = scrub_open_handle(handle); if (fd < 0) { error = errno; if (error == ESTALE) return error; str_info(ctx, descr, _("Disappeared during read error reporting.")); return error; } /* Go find the badness. */ error = report_fd_loss(ctx, descr, fd, arg); err2 = close(fd); if (err2) str_errno(ctx, descr); return error; } /* Scan a directory for matches in the read verify error list. */ static int report_dir_loss( struct scrub_ctx *ctx, const char *path, int dir_fd, void *arg) { return report_fd_loss(ctx, path, dir_fd, arg); } /* * Scan the inode associated with a directory entry for matches with * the read verify error list. */ static int report_dirent_loss( struct scrub_ctx *ctx, const char *path, int dir_fd, struct dirent *dirent, struct stat *sb, void *arg) { int fd; int error, err2; /* Ignore things we can't open. */ if (!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) return 0; /* Ignore . and .. */ if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name)) return 0; /* * If we were given a dirent, open the associated file under * dir_fd for badblocks scanning. If dirent is NULL, then it's * the directory itself we want to scan. */ fd = openat(dir_fd, dirent->d_name, O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); if (fd < 0) { if (errno == ENOENT) return 0; str_errno(ctx, path); return errno; } /* Go find the badness. */ error = report_fd_loss(ctx, path, fd, arg); err2 = close(fd); if (err2) str_errno(ctx, path); if (!error && err2) error = err2; return error; } /* Use a fsmap to report metadata lost to a media error. */ static int report_ioerr_fsmap( struct scrub_ctx *ctx, struct fsmap *map, void *arg) { const char *type; char buf[DESCR_BUFSZ]; uint64_t err_physical = *(uint64_t *)arg; uint64_t err_off; /* Don't care about unwritten extents. */ if (map->fmr_flags & FMR_OF_PREALLOC) return 0; if (err_physical > map->fmr_physical) err_off = err_physical - map->fmr_physical; else err_off = 0; /* Report special owners */ if (map->fmr_flags & FMR_OF_SPECIAL_OWNER) { snprintf(buf, DESCR_BUFSZ, _("disk offset %"PRIu64), (uint64_t)map->fmr_physical + err_off); type = decode_special_owner(map->fmr_owner); str_corrupt(ctx, buf, _("media error in %s."), type); } /* Report extent maps */ if (map->fmr_flags & FMR_OF_EXTENT_MAP) { bool attr = (map->fmr_flags & FMR_OF_ATTR_FORK); scrub_render_ino_descr(ctx, buf, DESCR_BUFSZ, map->fmr_owner, 0, " %s", attr ? _("extended attribute") : _("file data")); str_corrupt(ctx, buf, _("media error in extent map")); } /* * XXX: If we had a getparent() call we could report IO errors * efficiently. Until then, we'll have to scan the dir tree * to find the bad file's pathname. */ return 0; } /* * For a range of bad blocks, visit each space mapping that overlaps the bad * range so that we can report lost metadata. */ static int report_ioerr( uint64_t start, uint64_t length, void *arg) { struct fsmap keys[2]; struct disk_ioerr_report *dioerr = arg; dev_t dev; dev = disk_to_dev(dioerr->ctx, dioerr->disk); /* Go figure out which blocks are bad from the fsmap. */ memset(keys, 0, sizeof(struct fsmap) * 2); keys->fmr_device = dev; keys->fmr_physical = start; (keys + 1)->fmr_device = dev; (keys + 1)->fmr_physical = start + length - 1; (keys + 1)->fmr_owner = ULLONG_MAX; (keys + 1)->fmr_offset = ULLONG_MAX; (keys + 1)->fmr_flags = UINT_MAX; return -scrub_iterate_fsmap(dioerr->ctx, keys, report_ioerr_fsmap, &start); } /* Report all the media errors found on a disk. */ static int report_disk_ioerrs( struct scrub_ctx *ctx, struct disk *disk, struct media_verify_state *vs) { struct disk_ioerr_report dioerr = { .ctx = ctx, .disk = disk, }; struct bitmap *tree; if (!disk) return 0; tree = bitmap_for_disk(ctx, disk, vs); if (!tree) return 0; return -bitmap_iterate(tree, report_ioerr, &dioerr); } /* Given bad extent lists for the data & rtdev, find bad files. */ static int report_all_media_errors( struct scrub_ctx *ctx, struct media_verify_state *vs) { int ret; ret = report_disk_ioerrs(ctx, ctx->datadev, vs); if (ret) { str_liberror(ctx, ret, _("walking datadev io errors")); return ret; } ret = report_disk_ioerrs(ctx, ctx->rtdev, vs); if (ret) { str_liberror(ctx, ret, _("walking rtdev io errors")); return ret; } /* Scan the directory tree to get file paths. */ ret = scan_fs_tree(ctx, report_dir_loss, report_dirent_loss, vs); if (ret) return ret; /* Scan for unlinked files. */ return scrub_scan_all_inodes(ctx, report_inode_loss, vs); } /* Schedule a read-verify of a (data block) extent. */ static int check_rmap( struct scrub_ctx *ctx, struct fsmap *map, void *arg) { struct media_verify_state *vs = arg; struct read_verify_pool *rvp; int ret; rvp = dev_to_pool(ctx, vs, map->fmr_device); dbg_printf("rmap dev %d:%d phys %"PRIu64" owner %"PRId64 " offset %"PRIu64" len %"PRIu64" flags 0x%x\n", major(map->fmr_device), minor(map->fmr_device), (uint64_t)map->fmr_physical, (int64_t)map->fmr_owner, (uint64_t)map->fmr_offset, (uint64_t)map->fmr_length, map->fmr_flags); /* "Unknown" extents should be verified; they could be data. */ if ((map->fmr_flags & FMR_OF_SPECIAL_OWNER) && map->fmr_owner == XFS_FMR_OWN_UNKNOWN) map->fmr_flags &= ~FMR_OF_SPECIAL_OWNER; /* * We only care about read-verifying data extents that have been * written to disk. This means we can skip "special" owners * (metadata), xattr blocks, unwritten extents, and extent maps. * These should all get checked elsewhere in the scrubber. */ if (map->fmr_flags & (FMR_OF_PREALLOC | FMR_OF_ATTR_FORK | FMR_OF_EXTENT_MAP | FMR_OF_SPECIAL_OWNER)) return 0; /* XXX: Filter out directory data blocks. */ /* Schedule the read verify command for (eventual) running. */ ret = read_verify_schedule_io(rvp, map->fmr_physical, map->fmr_length, vs); if (ret) { str_liberror(ctx, ret, _("scheduling media verify command")); return ret; } return 0; } /* Wait for read/verify actions to finish, then return # bytes checked. */ static int clean_pool( struct read_verify_pool *rvp, unsigned long long *bytes_checked) { uint64_t pool_checked; int ret; if (!rvp) return 0; ret = read_verify_force_io(rvp); if (ret) return ret; ret = read_verify_pool_flush(rvp); if (ret) goto out_destroy; ret = read_verify_bytes(rvp, &pool_checked); if (ret) goto out_destroy; *bytes_checked += pool_checked; out_destroy: read_verify_pool_destroy(rvp); return ret; } /* Remember a media error for later. */ static void remember_ioerr( struct scrub_ctx *ctx, struct disk *disk, uint64_t start, uint64_t length, int error, void *arg) { struct media_verify_state *vs = arg; struct bitmap *tree; int ret; tree = bitmap_for_disk(ctx, disk, vs); if (!tree) { str_liberror(ctx, ENOENT, _("finding bad block bitmap")); return; } ret = -bitmap_set(tree, start, length); if (ret) str_liberror(ctx, ret, _("setting bad block bitmap")); } /* * Read verify all the file data blocks in a filesystem. Since XFS doesn't * do data checksums, we trust that the underlying storage will pass back * an IO error if it can't retrieve whatever we previously stored there. * If we hit an IO error, we'll record the bad blocks in a bitmap and then * scan the extent maps of the entire fs tree to figure (and the unlinked * inodes) out which files are now broken. */ int phase6_func( struct scrub_ctx *ctx) { struct media_verify_state vs = { NULL }; int ret, ret2, ret3; ret = -bitmap_alloc(&vs.d_bad); if (ret) { str_liberror(ctx, ret, _("creating datadev badblock bitmap")); return ret; } ret = -bitmap_alloc(&vs.r_bad); if (ret) { str_liberror(ctx, ret, _("creating realtime badblock bitmap")); goto out_dbad; } ret = read_verify_pool_alloc(ctx, ctx->datadev, ctx->mnt.fsgeom.blocksize, remember_ioerr, scrub_nproc(ctx), &vs.rvp_data); if (ret) { str_liberror(ctx, ret, _("creating datadev media verifier")); goto out_rbad; } if (ctx->logdev) { ret = read_verify_pool_alloc(ctx, ctx->logdev, ctx->mnt.fsgeom.blocksize, remember_ioerr, scrub_nproc(ctx), &vs.rvp_log); if (ret) { str_liberror(ctx, ret, _("creating logdev media verifier")); goto out_datapool; } } if (ctx->rtdev) { ret = read_verify_pool_alloc(ctx, ctx->rtdev, ctx->mnt.fsgeom.blocksize, remember_ioerr, scrub_nproc(ctx), &vs.rvp_realtime); if (ret) { str_liberror(ctx, ret, _("creating rtdev media verifier")); goto out_logpool; } } ret = scrub_scan_all_spacemaps(ctx, check_rmap, &vs); if (ret) goto out_rtpool; ret = clean_pool(vs.rvp_data, &ctx->bytes_checked); if (ret) str_liberror(ctx, ret, _("flushing datadev verify pool")); ret2 = clean_pool(vs.rvp_log, &ctx->bytes_checked); if (ret2) str_liberror(ctx, ret2, _("flushing logdev verify pool")); ret3 = clean_pool(vs.rvp_realtime, &ctx->bytes_checked); if (ret3) str_liberror(ctx, ret3, _("flushing rtdev verify pool")); /* * If the verify flush didn't work or we found no bad blocks, we're * done! No errors detected. */ if (ret || ret2 || ret3) goto out_rbad; if (bitmap_empty(vs.d_bad) && bitmap_empty(vs.r_bad)) goto out_rbad; /* Scan the whole dir tree to see what matches the bad extents. */ ret = report_all_media_errors(ctx, &vs); bitmap_free(&vs.r_bad); bitmap_free(&vs.d_bad); return ret; out_rtpool: if (vs.rvp_realtime) { read_verify_pool_abort(vs.rvp_realtime); read_verify_pool_destroy(vs.rvp_realtime); } out_logpool: if (vs.rvp_log) { read_verify_pool_abort(vs.rvp_log); read_verify_pool_destroy(vs.rvp_log); } out_datapool: read_verify_pool_abort(vs.rvp_data); read_verify_pool_destroy(vs.rvp_data); out_rbad: bitmap_free(&vs.r_bad); out_dbad: bitmap_free(&vs.d_bad); return ret; } /* Estimate how much work we're going to do. */ int phase6_estimate( struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift) { unsigned long long d_blocks; unsigned long long d_bfree; unsigned long long r_blocks; unsigned long long r_bfree; unsigned long long f_files; unsigned long long f_free; int ret; ret = scrub_scan_estimate_blocks(ctx, &d_blocks, &d_bfree, &r_blocks, &r_bfree, &f_files, &f_free); if (ret) { str_liberror(ctx, ret, _("estimating verify work")); return ret; } *items = cvt_off_fsb_to_b(&ctx->mnt, (d_blocks - d_bfree) + (r_blocks - r_bfree)); *nr_threads = disk_heads(ctx->datadev); *rshift = 20; return 0; } xfsprogs-5.3.0/scrub/phase7.c0000644000175000017500000001616613570057155015737 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "libfrog/paths.h" #include "libfrog/ptvar.h" #include "list.h" #include "xfs_scrub.h" #include "common.h" #include "scrub.h" #include "fscounters.h" #include "spacemap.h" #include "repair.h" /* Phase 7: Check summary counters. */ struct summary_counts { unsigned long long dbytes; /* data dev bytes */ unsigned long long rbytes; /* rt dev bytes */ unsigned long long next_phys; /* next phys bytes we see? */ unsigned long long agbytes; /* freespace bytes */ }; /* Record block usage. */ static int count_block_summary( struct scrub_ctx *ctx, struct fsmap *fsmap, void *arg) { struct summary_counts *counts; unsigned long long len; int ret; counts = ptvar_get((struct ptvar *)arg, &ret); if (ret) { str_liberror(ctx, -ret, _("retrieving summary counts")); return -ret; } if (fsmap->fmr_device == ctx->fsinfo.fs_logdev) return 0; if ((fsmap->fmr_flags & FMR_OF_SPECIAL_OWNER) && fsmap->fmr_owner == XFS_FMR_OWN_FREE) return 0; len = fsmap->fmr_length; /* freesp btrees live in free space, need to adjust counters later. */ if ((fsmap->fmr_flags & FMR_OF_SPECIAL_OWNER) && fsmap->fmr_owner == XFS_FMR_OWN_AG) { counts->agbytes += fsmap->fmr_length; } if (fsmap->fmr_device == ctx->fsinfo.fs_rtdev) { /* Count realtime extents. */ counts->rbytes += len; } else { /* Count datadev extents. */ if (counts->next_phys >= fsmap->fmr_physical + len) return 0; else if (counts->next_phys > fsmap->fmr_physical) len = counts->next_phys - fsmap->fmr_physical; counts->dbytes += len; counts->next_phys = fsmap->fmr_physical + fsmap->fmr_length; } return 0; } /* Add all the summaries in the per-thread counter */ static int add_summaries( struct ptvar *ptv, void *data, void *arg) { struct summary_counts *total = arg; struct summary_counts *item = data; total->dbytes += item->dbytes; total->rbytes += item->rbytes; total->agbytes += item->agbytes; return 0; } /* * Count all inodes and blocks in the filesystem as told by GETFSMAP and * BULKSTAT, and compare that to summary counters. Since this is a live * filesystem we'll be content if the summary counts are within 10% of * what we observed. */ int phase7_func( struct scrub_ctx *ctx) { struct summary_counts totalcount = {0}; struct action_list alist; struct ptvar *ptvar; unsigned long long used_data; unsigned long long used_rt; unsigned long long used_files; unsigned long long stat_data; unsigned long long stat_rt; uint64_t counted_inodes = 0; unsigned long long absdiff; unsigned long long d_blocks; unsigned long long d_bfree; unsigned long long r_blocks; unsigned long long r_bfree; unsigned long long f_files; unsigned long long f_free; bool complain; int ip; int error; /* Check and fix the fs summary counters. */ action_list_init(&alist); error = xfs_scrub_fs_summary(ctx, &alist); if (error) return error; error = action_list_process(ctx, ctx->mnt.fd, &alist, ALP_COMPLAIN_IF_UNFIXED | ALP_NOPROGRESS); if (error) return error; /* Flush everything out to disk before we start counting. */ error = syncfs(ctx->mnt.fd); if (error) { str_errno(ctx, ctx->mntpoint); return error; } error = -ptvar_alloc(scrub_nproc(ctx), sizeof(struct summary_counts), &ptvar); if (error) { str_liberror(ctx, error, _("setting up block counter")); return error; } /* Use fsmap to count blocks. */ error = scrub_scan_all_spacemaps(ctx, count_block_summary, ptvar); if (error) goto out_free; error = -ptvar_foreach(ptvar, add_summaries, &totalcount); if (error) { str_liberror(ctx, error, _("counting blocks")); goto out_free; } ptvar_free(ptvar); /* Scan the whole fs. */ error = scrub_count_all_inodes(ctx, &counted_inodes); if (error) { str_liberror(ctx, error, _("counting inodes")); return error; } error = scrub_scan_estimate_blocks(ctx, &d_blocks, &d_bfree, &r_blocks, &r_bfree, &f_files, &f_free); if (error) { str_liberror(ctx, error, _("estimating verify work")); return error; } /* * If we counted blocks with fsmap, then dblocks includes * blocks for the AGFL and the freespace/rmap btrees. The * filesystem treats them as "free", but since we scanned * them, we'll consider them used. */ d_bfree -= cvt_b_to_off_fsbt(&ctx->mnt, totalcount.agbytes); /* Report on what we found. */ used_data = cvt_off_fsb_to_b(&ctx->mnt, d_blocks - d_bfree); used_rt = cvt_off_fsb_to_b(&ctx->mnt, r_blocks - r_bfree); used_files = f_files - f_free; stat_data = totalcount.dbytes; stat_rt = totalcount.rbytes; /* * Complain if the counts are off by more than 10% unless * the inaccuracy is less than 32MB worth of blocks or 100 inodes. */ absdiff = 1ULL << 25; complain = verbose; complain |= !within_range(ctx, stat_data, used_data, absdiff, 1, 10, _("data blocks")); complain |= !within_range(ctx, stat_rt, used_rt, absdiff, 1, 10, _("realtime blocks")); complain |= !within_range(ctx, counted_inodes, used_files, 100, 1, 10, _("inodes")); if (complain) { double d, r, i; char *du, *ru, *iu; if (used_rt || stat_rt) { d = auto_space_units(used_data, &du); r = auto_space_units(used_rt, &ru); i = auto_units(used_files, &iu, &ip); fprintf(stdout, _("%.1f%s data used; %.1f%s realtime data used; %.*f%s inodes used.\n"), d, du, r, ru, ip, i, iu); d = auto_space_units(stat_data, &du); r = auto_space_units(stat_rt, &ru); i = auto_units(counted_inodes, &iu, &ip); fprintf(stdout, _("%.1f%s data found; %.1f%s realtime data found; %.*f%s inodes found.\n"), d, du, r, ru, ip, i, iu); } else { d = auto_space_units(used_data, &du); i = auto_units(used_files, &iu, &ip); fprintf(stdout, _("%.1f%s data used; %.*f%s inodes used.\n"), d, du, ip, i, iu); d = auto_space_units(stat_data, &du); i = auto_units(counted_inodes, &iu, &ip); fprintf(stdout, _("%.1f%s data found; %.*f%s inodes found.\n"), d, du, ip, i, iu); } fflush(stdout); } /* * Complain if the checked inode counts are off, which * implies an incomplete check. */ if (verbose || !within_range(ctx, counted_inodes, ctx->inodes_checked, 100, 1, 10, _("checked inodes"))) { double i1, i2; char *i1u, *i2u; int i1p, i2p; i1 = auto_units(counted_inodes, &i1u, &i1p); i2 = auto_units(ctx->inodes_checked, &i2u, &i2p); fprintf(stdout, _("%.*f%s inodes counted; %.*f%s inodes checked.\n"), i1p, i1, i1u, i2p, i2, i2u); fflush(stdout); } /* * Complain if the checked block counts are off, which * implies an incomplete check. */ if (ctx->bytes_checked && (verbose || !within_range(ctx, used_data + used_rt, ctx->bytes_checked, absdiff, 1, 10, _("verified blocks")))) { double b1, b2; char *b1u, *b2u; b1 = auto_space_units(used_data + used_rt, &b1u); b2 = auto_space_units(ctx->bytes_checked, &b2u); fprintf(stdout, _("%.1f%s data counted; %.1f%s data verified.\n"), b1, b1u, b2, b2u); fflush(stdout); } return 0; out_free: ptvar_free(ptvar); return error; } xfsprogs-5.3.0/scrub/progress.c0000644000175000017500000001127213570057155016405 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "libfrog/paths.h" #include "disk.h" #include "read_verify.h" #include "xfs_scrub.h" #include "common.h" #include "counter.h" #include "progress.h" /* * Progress Tracking * * For scrub phases that expect to take a long time, this facility uses * the threaded counter and some phase/state information to report the * progress of a particular phase to stdout. Each phase that wants * progress information needs to set up the tracker with an estimate of * the work to be done and periodic updates when work items finish. In * return, the progress tracker will print a pretty progress bar and * twiddle to a tty, or a raw numeric output compatible with fsck -C. */ struct progress_tracker { FILE *fp; const char *tag; struct ptcounter *ptc; uint64_t max; unsigned int phase; int rshift; int twiddle; bool isatty; bool terminate; pthread_t thread; /* static state */ pthread_mutex_t lock; pthread_cond_t wakeup; }; static struct progress_tracker pt = { .lock = PTHREAD_MUTEX_INITIALIZER, .wakeup = PTHREAD_COND_INITIALIZER, }; /* Add some progress. */ void progress_add( uint64_t x) { if (pt.fp) ptcounter_add(pt.ptc, x); } static const char twiddles[] = "|/-\\"; static void progress_report( uint64_t sum) { char buf[81]; int tag_len; int num_len; int pbar_len; int plen; if (!pt.fp) return; if (sum > pt.max) sum = pt.max; /* Emulate fsck machine-readable output (phase, cur, max, label) */ if (!pt.isatty) { snprintf(buf, sizeof(buf), _("%u %"PRIu64" %"PRIu64" %s"), pt.phase, sum, pt.max, pt.tag); fprintf(pt.fp, "%s\n", buf); fflush(pt.fp); return; } /* Interactive twiddle progress bar. */ if (debug) { num_len = snprintf(buf, sizeof(buf), "%c %"PRIu64"/%"PRIu64" (%.1f%%)", twiddles[pt.twiddle], sum >> pt.rshift, pt.max >> pt.rshift, 100.0 * sum / pt.max); } else { num_len = snprintf(buf, sizeof(buf), "%c (%.1f%%)", twiddles[pt.twiddle], 100.0 * sum / pt.max); } memmove(buf + sizeof(buf) - (num_len + 1), buf, num_len + 1); tag_len = snprintf(buf, sizeof(buf), _("Phase %u: |"), pt.phase); pbar_len = sizeof(buf) - (num_len + 1 + tag_len); plen = (int)((double)pbar_len * sum / pt.max); memset(buf + tag_len, '=', plen); memset(buf + tag_len + plen, ' ', pbar_len - plen); pt.twiddle = (pt.twiddle + 1) % 4; fprintf(pt.fp, "%c%s\r%c", START_IGNORE, buf, END_IGNORE); fflush(pt.fp); } #define NSEC_PER_SEC (1000000000) static void * progress_report_thread(void *arg) { struct timespec abstime; int ret; pthread_mutex_lock(&pt.lock); while (1) { uint64_t progress_val; /* Every half second. */ ret = clock_gettime(CLOCK_REALTIME, &abstime); if (ret) break; abstime.tv_nsec += NSEC_PER_SEC / 2; if (abstime.tv_nsec > NSEC_PER_SEC) { abstime.tv_sec++; abstime.tv_nsec -= NSEC_PER_SEC; } ret = pthread_cond_timedwait(&pt.wakeup, &pt.lock, &abstime); if (ret && ret != ETIMEDOUT) break; if (pt.terminate) break; ret = ptcounter_value(pt.ptc, &progress_val); if (!ret) progress_report(progress_val); } pthread_mutex_unlock(&pt.lock); return NULL; } /* End a phase of progress reporting. */ void progress_end_phase(void) { if (!pt.fp) return; pthread_mutex_lock(&pt.lock); pt.terminate = true; pthread_mutex_unlock(&pt.lock); pthread_cond_broadcast(&pt.wakeup); pthread_join(pt.thread, NULL); progress_report(pt.max); ptcounter_free(pt.ptc); pt.max = 0; pt.ptc = NULL; if (pt.fp) { fprintf(pt.fp, CLEAR_EOL); fflush(pt.fp); } pt.fp = NULL; } /* * Set ourselves up to report progress. If errors are encountered, this * function will log them and return nonzero. */ int progress_init_phase( struct scrub_ctx *ctx, FILE *fp, unsigned int phase, uint64_t max, int rshift, unsigned int nr_threads) { int ret; assert(pt.fp == NULL); if (fp == NULL || max == 0) { pt.fp = NULL; return 0; } pt.fp = fp; pt.isatty = isatty(fileno(fp)); pt.tag = ctx->mntpoint; pt.max = max; pt.phase = phase; pt.rshift = rshift; pt.twiddle = 0; pt.terminate = false; ret = ptcounter_alloc(nr_threads, &pt.ptc); if (ret) { str_liberror(ctx, ret, _("allocating progress counter")); goto out_max; } ret = pthread_create(&pt.thread, NULL, progress_report_thread, NULL); if (ret) { str_liberror(ctx, ret, _("creating progress reporting thread")); goto out_ptcounter; } return 0; out_ptcounter: ptcounter_free(pt.ptc); pt.ptc = NULL; out_max: pt.max = 0; pt.fp = NULL; return ret; } xfsprogs-5.3.0/scrub/progress.h0000644000175000017500000000103013570057155016401 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_PROGRESS_H_ #define XFS_SCRUB_PROGRESS_H_ #define CLEAR_EOL "\033[K" #define START_IGNORE '\001' #define END_IGNORE '\002' int progress_init_phase(struct scrub_ctx *ctx, FILE *progress_fp, unsigned int phase, uint64_t max, int rshift, unsigned int nr_threads); void progress_end_phase(void); void progress_add(uint64_t x); #endif /* XFS_SCRUB_PROGRESS_H_ */ xfsprogs-5.3.0/scrub/read_verify.c0000644000175000017500000002360613570057155017044 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include "libfrog/ptvar.h" #include "libfrog/workqueue.h" #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "counter.h" #include "disk.h" #include "read_verify.h" #include "progress.h" /* * Read Verify Pool * * Manages the data block read verification phase. The caller schedules * verification requests, which are then scheduled to be run by a thread * pool worker. Adjacent (or nearly adjacent) requests can be combined * to reduce overhead when free space fragmentation is high. The thread * pool takes care of issuing multiple IOs to the device, if possible. */ /* * Perform all IO in 32M chunks. This cannot exceed 65536 sectors * because that's the biggest SCSI VERIFY(16) we dare to send. */ #define RVP_IO_MAX_SIZE (33554432) /* * If we're running in the background then we perform IO in 128k chunks * to reduce the load on the IO subsystem. */ #define RVP_BACKGROUND_IO_MAX_SIZE (131072) /* What's the real maximum IO size? */ static inline unsigned int rvp_io_max_size(void) { return bg_mode > 0 ? RVP_BACKGROUND_IO_MAX_SIZE : RVP_IO_MAX_SIZE; } /* Tolerate 64k holes in adjacent read verify requests. */ #define RVP_IO_BATCH_LOCALITY (65536) struct read_verify { void *io_end_arg; struct disk *io_disk; uint64_t io_start; /* bytes */ uint64_t io_length; /* bytes */ }; struct read_verify_pool { struct workqueue wq; /* thread pool */ struct scrub_ctx *ctx; /* scrub context */ void *readbuf; /* read buffer */ struct ptcounter *verified_bytes; struct ptvar *rvstate; /* combines read requests */ struct disk *disk; /* which disk? */ read_verify_ioerr_fn_t ioerr_fn; /* io error callback */ size_t miniosz; /* minimum io size, bytes */ /* * Store a runtime error code here so that we can stop the pool and * return it to the caller. */ int runtime_error; }; /* * Create a thread pool to run read verifiers. * * @disk is the disk we want to verify. * @miniosz is the minimum size of an IO to expect (in bytes). * @ioerr_fn will be called when IO errors occur. * @submitter_threads is the number of threads that may be sending verify * requests at any given time. */ int read_verify_pool_alloc( struct scrub_ctx *ctx, struct disk *disk, size_t miniosz, read_verify_ioerr_fn_t ioerr_fn, unsigned int submitter_threads, struct read_verify_pool **prvp) { struct read_verify_pool *rvp; unsigned int verifier_threads = disk_heads(disk); int ret; /* * The minimum IO size must be a multiple of the disk sector size * and a factor of the max io size. */ if (miniosz % disk->d_lbasize) return EINVAL; if (rvp_io_max_size() % miniosz) return EINVAL; rvp = calloc(1, sizeof(struct read_verify_pool)); if (!rvp) return errno; ret = posix_memalign((void **)&rvp->readbuf, page_size, rvp_io_max_size()); if (ret) goto out_free; ret = ptcounter_alloc(verifier_threads, &rvp->verified_bytes); if (ret) goto out_buf; rvp->miniosz = miniosz; rvp->ctx = ctx; rvp->disk = disk; rvp->ioerr_fn = ioerr_fn; ret = -ptvar_alloc(submitter_threads, sizeof(struct read_verify), &rvp->rvstate); if (ret) goto out_counter; ret = -workqueue_create(&rvp->wq, (struct xfs_mount *)rvp, verifier_threads == 1 ? 0 : verifier_threads); if (ret) goto out_rvstate; *prvp = rvp; return 0; out_rvstate: ptvar_free(rvp->rvstate); out_counter: ptcounter_free(rvp->verified_bytes); out_buf: free(rvp->readbuf); out_free: free(rvp); return ret; } /* Abort all verification work. */ void read_verify_pool_abort( struct read_verify_pool *rvp) { if (!rvp->runtime_error) rvp->runtime_error = ECANCELED; workqueue_terminate(&rvp->wq); } /* Finish up any read verification work. */ int read_verify_pool_flush( struct read_verify_pool *rvp) { return -workqueue_terminate(&rvp->wq); } /* Finish up any read verification work and tear it down. */ void read_verify_pool_destroy( struct read_verify_pool *rvp) { workqueue_destroy(&rvp->wq); ptvar_free(rvp->rvstate); ptcounter_free(rvp->verified_bytes); free(rvp->readbuf); free(rvp); } /* * Issue a read-verify IO in big batches. */ static void read_verify( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct read_verify *rv = arg; struct read_verify_pool *rvp; unsigned long long verified = 0; ssize_t io_max_size; ssize_t sz; ssize_t len; int read_error; int ret; rvp = (struct read_verify_pool *)wq->wq_ctx; if (rvp->runtime_error) return; io_max_size = rvp_io_max_size(); while (rv->io_length > 0) { read_error = 0; len = min(rv->io_length, io_max_size); dbg_printf("diskverify %d %"PRIu64" %zu\n", rvp->disk->d_fd, rv->io_start, len); sz = disk_read_verify(rvp->disk, rvp->readbuf, rv->io_start, len); if (sz == len && io_max_size < rvp->miniosz) { /* * If the verify request was 100% successful and less * than a single block in length, we were trying to * read to the end of a block after a short read. That * suggests there's something funny with this device, * so single-step our way through the rest of the @rv * range. */ io_max_size = rvp->miniosz; } else if (sz < 0) { read_error = errno; /* Runtime error, bail out... */ if (read_error != EIO && read_error != EILSEQ) { rvp->runtime_error = read_error; return; } /* * A direct read encountered an error while performing * a multi-block read. Reduce the transfer size to a * single block so that we can identify the exact range * of bad blocks and good blocks. We single-step all * the way to the end of the @rv range, (re)starting * with the block that just failed. */ if (io_max_size > rvp->miniosz) { io_max_size = rvp->miniosz; continue; } /* * A direct read hit an error while we were stepping * through single blocks. Mark everything bad from * io_start to the next miniosz block. */ sz = rvp->miniosz - (rv->io_start % rvp->miniosz); dbg_printf("IOERR %d @ %"PRIu64" %zu err %d\n", rvp->disk->d_fd, rv->io_start, sz, read_error); rvp->ioerr_fn(rvp->ctx, rvp->disk, rv->io_start, sz, read_error, rv->io_end_arg); } else if (sz < len) { /* * A short direct read suggests that we might have hit * an IO error midway through the read but still had to * return the number of bytes that were actually read. * * We need to force an EIO, so try reading the rest of * the block (if it was a partial block read) or the * next full block. */ io_max_size = rvp->miniosz - (sz % rvp->miniosz); dbg_printf("SHORT %d READ @ %"PRIu64" %zu try for %zd\n", rvp->disk->d_fd, rv->io_start, sz, io_max_size); } else { /* We should never get back more bytes than we asked. */ assert(sz == len); } progress_add(sz); if (read_error == 0) verified += sz; rv->io_start += sz; rv->io_length -= sz; background_sleep(); } free(rv); ret = ptcounter_add(rvp->verified_bytes, verified); if (ret) rvp->runtime_error = ret; } /* Queue a read verify request. */ static int read_verify_queue( struct read_verify_pool *rvp, struct read_verify *rv) { struct read_verify *tmp; bool ret; dbg_printf("verify fd %d start %"PRIu64" len %"PRIu64"\n", rvp->disk->d_fd, rv->io_start, rv->io_length); /* Worker thread saw a runtime error, don't queue more. */ if (rvp->runtime_error) return rvp->runtime_error; /* Otherwise clone the request and queue the copy. */ tmp = malloc(sizeof(struct read_verify)); if (!tmp) { rvp->runtime_error = errno; return errno; } memcpy(tmp, rv, sizeof(*tmp)); ret = -workqueue_add(&rvp->wq, read_verify, 0, tmp); if (ret) { free(tmp); rvp->runtime_error = ret; return ret; } rv->io_length = 0; return 0; } /* * Issue an IO request. We'll batch subsequent requests if they're * within 64k of each other */ int read_verify_schedule_io( struct read_verify_pool *rvp, uint64_t start, uint64_t length, void *end_arg) { struct read_verify *rv; uint64_t req_end; uint64_t rv_end; int ret; assert(rvp->readbuf); /* Round up and down to the start of a miniosz chunk. */ start &= ~(rvp->miniosz - 1); length = roundup(length, rvp->miniosz); rv = ptvar_get(rvp->rvstate, &ret); if (ret) return -ret; req_end = start + length; rv_end = rv->io_start + rv->io_length; /* * If we have a stashed IO, we haven't changed fds, the error * reporting is the same, and the two extents are close, * we can combine them. */ if (rv->io_length > 0 && end_arg == rv->io_end_arg && ((start >= rv->io_start && start <= rv_end + RVP_IO_BATCH_LOCALITY) || (rv->io_start >= start && rv->io_start <= req_end + RVP_IO_BATCH_LOCALITY))) { rv->io_start = min(rv->io_start, start); rv->io_length = max(req_end, rv_end) - rv->io_start; } else { /* Otherwise, issue the stashed IO (if there is one) */ if (rv->io_length > 0) { int res; res = read_verify_queue(rvp, rv); if (res) return res; } /* Stash the new IO. */ rv->io_start = start; rv->io_length = length; rv->io_end_arg = end_arg; } return 0; } /* Force any per-thread stashed IOs into the verifier. */ static int force_one_io( struct ptvar *ptv, void *data, void *foreach_arg) { struct read_verify_pool *rvp = foreach_arg; struct read_verify *rv = data; if (rv->io_length == 0) return 0; return -read_verify_queue(rvp, rv); } /* Force any stashed IOs into the verifier. */ int read_verify_force_io( struct read_verify_pool *rvp) { assert(rvp->readbuf); return -ptvar_foreach(rvp->rvstate, force_one_io, rvp); } /* How many bytes has this process verified? */ int read_verify_bytes( struct read_verify_pool *rvp, uint64_t *bytes_checked) { return ptcounter_value(rvp->verified_bytes, bytes_checked); } xfsprogs-5.3.0/scrub/read_verify.h0000644000175000017500000000212113570057155017036 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_READ_VERIFY_H_ #define XFS_SCRUB_READ_VERIFY_H_ struct scrub_ctx; struct read_verify_pool; struct disk; /* Function called when an IO error happens. */ typedef void (*read_verify_ioerr_fn_t)(struct scrub_ctx *ctx, struct disk *disk, uint64_t start, uint64_t length, int error, void *arg); int read_verify_pool_alloc(struct scrub_ctx *ctx, struct disk *disk, size_t miniosz, read_verify_ioerr_fn_t ioerr_fn, unsigned int submitter_threads, struct read_verify_pool **prvp); void read_verify_pool_abort(struct read_verify_pool *rvp); int read_verify_pool_flush(struct read_verify_pool *rvp); void read_verify_pool_destroy(struct read_verify_pool *rvp); int read_verify_schedule_io(struct read_verify_pool *rvp, uint64_t start, uint64_t length, void *end_arg); int read_verify_force_io(struct read_verify_pool *rvp); int read_verify_bytes(struct read_verify_pool *rvp, uint64_t *bytes); #endif /* XFS_SCRUB_READ_VERIFY_H_ */ xfsprogs-5.3.0/scrub/repair.c0000644000175000017500000001505313570057155016024 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "list.h" #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "scrub.h" #include "progress.h" #include "repair.h" /* * Prioritize action items in order of how long we can wait. * 0 = do it now, 10000 = do it later. * * To minimize the amount of repair work, we want to prioritize metadata * objects by perceived corruptness. If CORRUPT is set, the fields are * just plain bad; try fixing that first. Otherwise if XCORRUPT is set, * the fields could be bad, but the xref data could also be bad; we'll * try fixing that next. Finally, if XFAIL is set, some other metadata * structure failed validation during xref, so we'll recheck this * metadata last since it was probably fine. * * For metadata that lie in the critical path of checking other metadata * (superblock, AG{F,I,FL}, inobt) we scrub and fix those things before * we even get to handling their dependencies, so things should progress * in order. */ /* Sort action items in severity order. */ static int PRIO( struct action_item *aitem, int order) { if (aitem->flags & XFS_SCRUB_OFLAG_CORRUPT) return order; else if (aitem->flags & XFS_SCRUB_OFLAG_XCORRUPT) return 100 + order; else if (aitem->flags & XFS_SCRUB_OFLAG_XFAIL) return 200 + order; else if (aitem->flags & XFS_SCRUB_OFLAG_PREEN) return 300 + order; abort(); } /* Sort the repair items in dependency order. */ static int xfs_action_item_priority( struct action_item *aitem) { switch (aitem->type) { case XFS_SCRUB_TYPE_SB: case XFS_SCRUB_TYPE_AGF: case XFS_SCRUB_TYPE_AGFL: case XFS_SCRUB_TYPE_AGI: case XFS_SCRUB_TYPE_BNOBT: case XFS_SCRUB_TYPE_CNTBT: case XFS_SCRUB_TYPE_INOBT: case XFS_SCRUB_TYPE_FINOBT: case XFS_SCRUB_TYPE_REFCNTBT: case XFS_SCRUB_TYPE_RMAPBT: case XFS_SCRUB_TYPE_INODE: case XFS_SCRUB_TYPE_BMBTD: case XFS_SCRUB_TYPE_BMBTA: case XFS_SCRUB_TYPE_BMBTC: return PRIO(aitem, aitem->type - 1); case XFS_SCRUB_TYPE_DIR: case XFS_SCRUB_TYPE_XATTR: case XFS_SCRUB_TYPE_SYMLINK: case XFS_SCRUB_TYPE_PARENT: return PRIO(aitem, XFS_SCRUB_TYPE_DIR); case XFS_SCRUB_TYPE_RTBITMAP: case XFS_SCRUB_TYPE_RTSUM: return PRIO(aitem, XFS_SCRUB_TYPE_RTBITMAP); case XFS_SCRUB_TYPE_UQUOTA: case XFS_SCRUB_TYPE_GQUOTA: case XFS_SCRUB_TYPE_PQUOTA: return PRIO(aitem, XFS_SCRUB_TYPE_UQUOTA); case XFS_SCRUB_TYPE_FSCOUNTERS: /* This should always go after AG headers no matter what. */ return PRIO(aitem, INT_MAX); } abort(); } /* Make sure that btrees get repaired before headers. */ static int xfs_action_item_compare( void *priv, struct list_head *a, struct list_head *b) { struct action_item *ra; struct action_item *rb; ra = container_of(a, struct action_item, list); rb = container_of(b, struct action_item, list); return xfs_action_item_priority(ra) - xfs_action_item_priority(rb); } /* * Figure out which AG metadata must be fixed before we can move on * to the inode scan. */ void action_list_find_mustfix( struct action_list *alist, struct action_list *immediate_alist, unsigned long long *broken_primaries, unsigned long long *broken_secondaries) { struct action_item *n; struct action_item *aitem; list_for_each_entry_safe(aitem, n, &alist->list, list) { if (!(aitem->flags & XFS_SCRUB_OFLAG_CORRUPT)) continue; switch (aitem->type) { case XFS_SCRUB_TYPE_RMAPBT: (*broken_secondaries)++; break; case XFS_SCRUB_TYPE_FINOBT: case XFS_SCRUB_TYPE_INOBT: alist->nr--; list_move_tail(&aitem->list, &immediate_alist->list); immediate_alist->nr++; /* fall through */ case XFS_SCRUB_TYPE_BNOBT: case XFS_SCRUB_TYPE_CNTBT: case XFS_SCRUB_TYPE_REFCNTBT: (*broken_primaries)++; break; default: abort(); break; } } } /* * Allocate a certain number of repair lists for the scrub context. Returns * zero or a positive error number. */ int action_lists_alloc( size_t nr, struct action_list **listsp) { struct action_list *lists; xfs_agnumber_t agno; lists = calloc(nr, sizeof(struct action_list)); if (!lists) return errno; for (agno = 0; agno < nr; agno++) action_list_init(&lists[agno]); *listsp = lists; return 0; } /* Free the repair lists. */ void action_lists_free( struct action_list **listsp) { free(*listsp); *listsp = NULL; } /* Initialize repair list */ void action_list_init( struct action_list *alist) { INIT_LIST_HEAD(&alist->list); alist->nr = 0; alist->sorted = false; } /* Number of repairs in this list. */ size_t action_list_length( struct action_list *alist) { return alist->nr; }; /* Add to the list of repairs. */ void action_list_add( struct action_list *alist, struct action_item *aitem) { list_add_tail(&aitem->list, &alist->list); alist->nr++; alist->sorted = false; } /* Splice two repair lists. */ void action_list_splice( struct action_list *dest, struct action_list *src) { if (src->nr == 0) return; list_splice_tail_init(&src->list, &dest->list); dest->nr += src->nr; src->nr = 0; dest->sorted = false; } /* Repair everything on this list. */ int action_list_process( struct scrub_ctx *ctx, int fd, struct action_list *alist, unsigned int repair_flags) { struct action_item *aitem; struct action_item *n; enum check_outcome fix; if (!alist->sorted) { list_sort(NULL, &alist->list, xfs_action_item_compare); alist->sorted = true; } list_for_each_entry_safe(aitem, n, &alist->list, list) { fix = xfs_repair_metadata(ctx, fd, aitem, repair_flags); switch (fix) { case CHECK_DONE: if (!(repair_flags & ALP_NOPROGRESS)) progress_add(1); alist->nr--; list_del(&aitem->list); free(aitem); continue; case CHECK_ABORT: return ECANCELED; case CHECK_RETRY: continue; case CHECK_REPAIR: abort(); } } if (xfs_scrub_excessive_errors(ctx)) return ECANCELED; return 0; } /* Defer all the repairs until phase 4. */ void action_list_defer( struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist) { ASSERT(agno < ctx->mnt.fsgeom.agcount); action_list_splice(&ctx->action_lists[agno], alist); } /* Run actions now and defer unfinished items for later. */ int action_list_process_or_defer( struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist) { int ret; ret = action_list_process(ctx, ctx->mnt.fd, alist, ALP_REPAIR_ONLY | ALP_NOPROGRESS); if (ret) return ret; action_list_defer(ctx, agno, alist); return 0; } xfsprogs-5.3.0/scrub/repair.h0000644000175000017500000000254013570057155016026 0ustar nathansnathans/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_REPAIR_H_ #define XFS_SCRUB_REPAIR_H_ struct action_list { struct list_head list; size_t nr; bool sorted; }; int action_lists_alloc(size_t nr, struct action_list **listsp); void action_lists_free(struct action_list **listsp); void action_list_init(struct action_list *alist); size_t action_list_length(struct action_list *alist); void action_list_add(struct action_list *dest, struct action_item *item); void action_list_splice(struct action_list *dest, struct action_list *src); void action_list_find_mustfix(struct action_list *actions, struct action_list *immediate_alist, unsigned long long *broken_primaries, unsigned long long *broken_secondaries); /* Passed through to xfs_repair_metadata() */ #define ALP_REPAIR_ONLY (XRM_REPAIR_ONLY) #define ALP_COMPLAIN_IF_UNFIXED (XRM_COMPLAIN_IF_UNFIXED) #define ALP_NOPROGRESS (1U << 31) int action_list_process(struct scrub_ctx *ctx, int fd, struct action_list *alist, unsigned int repair_flags); void action_list_defer(struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist); int action_list_process_or_defer(struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist); #endif /* XFS_SCRUB_REPAIR_H_ */ xfsprogs-5.3.0/scrub/scrub.c0000644000175000017500000004455613570057155015672 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include #include "list.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "libfrog/scrub.h" #include "xfs_scrub.h" #include "common.h" #include "progress.h" #include "scrub.h" #include "xfs_errortag.h" #include "repair.h" #include "descr.h" /* Online scrub and repair wrappers. */ /* Format a scrub description. */ static int format_scrub_descr( struct scrub_ctx *ctx, char *buf, size_t buflen, void *where) { struct xfs_scrub_metadata *meta = where; const struct xfrog_scrub_descr *sc = &xfrog_scrubbers[meta->sm_type]; switch (sc->type) { case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: return snprintf(buf, buflen, _("AG %u %s"), meta->sm_agno, _(sc->descr)); break; case XFROG_SCRUB_TYPE_INODE: return scrub_render_ino_descr(ctx, buf, buflen, meta->sm_ino, meta->sm_gen, "%s", _(sc->descr)); break; case XFROG_SCRUB_TYPE_FS: return snprintf(buf, buflen, _("%s"), _(sc->descr)); break; case XFROG_SCRUB_TYPE_NONE: assert(0); break; } return -1; } /* Predicates for scrub flag state. */ static inline bool is_corrupt(struct xfs_scrub_metadata *sm) { return sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT; } static inline bool is_unoptimized(struct xfs_scrub_metadata *sm) { return sm->sm_flags & XFS_SCRUB_OFLAG_PREEN; } static inline bool xref_failed(struct xfs_scrub_metadata *sm) { return sm->sm_flags & XFS_SCRUB_OFLAG_XFAIL; } static inline bool xref_disagrees(struct xfs_scrub_metadata *sm) { return sm->sm_flags & XFS_SCRUB_OFLAG_XCORRUPT; } static inline bool is_incomplete(struct xfs_scrub_metadata *sm) { return sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE; } static inline bool is_suspicious(struct xfs_scrub_metadata *sm) { return sm->sm_flags & XFS_SCRUB_OFLAG_WARNING; } /* Should we fix it? */ static inline bool needs_repair(struct xfs_scrub_metadata *sm) { return is_corrupt(sm) || xref_disagrees(sm); } /* Warn about strange circumstances after scrub. */ static inline void xfs_scrub_warn_incomplete_scrub( struct scrub_ctx *ctx, struct descr *dsc, struct xfs_scrub_metadata *meta) { if (is_incomplete(meta)) str_info(ctx, descr_render(dsc), _("Check incomplete.")); if (is_suspicious(meta)) { if (debug) str_info(ctx, descr_render(dsc), _("Possibly suspect metadata.")); else str_warn(ctx, descr_render(dsc), _("Possibly suspect metadata.")); } if (xref_failed(meta)) str_info(ctx, descr_render(dsc), _("Cross-referencing failed.")); } /* Do a read-only check of some metadata. */ static enum check_outcome xfs_check_metadata( struct scrub_ctx *ctx, struct xfs_scrub_metadata *meta, bool is_inode) { DEFINE_DESCR(dsc, ctx, format_scrub_descr); unsigned int tries = 0; int error; assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); assert(meta->sm_type < XFS_SCRUB_TYPE_NR); descr_set(&dsc, meta); dbg_printf("check %s flags %xh\n", descr_render(&dsc), meta->sm_flags); retry: error = -xfrog_scrub_metadata(&ctx->mnt, meta); if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !error) meta->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; switch (error) { case 0: /* No operational errors encountered. */ break; case ENOENT: /* Metadata not present, just skip it. */ return CHECK_DONE; case ESHUTDOWN: /* FS already crashed, give up. */ str_error(ctx, descr_render(&dsc), _("Filesystem is shut down, aborting.")); return CHECK_ABORT; case EIO: case ENOMEM: /* Abort on I/O errors or insufficient memory. */ str_errno(ctx, descr_render(&dsc)); return CHECK_ABORT; case EDEADLOCK: case EBUSY: case EFSBADCRC: case EFSCORRUPTED: /* * The first two should never escape the kernel, * and the other two should be reported via sm_flags. */ str_liberror(ctx, error, _("Kernel bug")); /* fall through */ default: /* Operational error. */ str_errno(ctx, descr_render(&dsc)); return CHECK_DONE; } /* * If the kernel says the test was incomplete or that there was * a cross-referencing discrepancy but no obvious corruption, * we'll try the scan again, just in case the fs was busy. * Only retry so many times. */ if (tries < 10 && (is_incomplete(meta) || (xref_disagrees(meta) && !is_corrupt(meta)))) { tries++; goto retry; } /* Complain about incomplete or suspicious metadata. */ xfs_scrub_warn_incomplete_scrub(ctx, &dsc, meta); /* * If we need repairs or there were discrepancies, schedule a * repair if desired, otherwise complain. */ if (is_corrupt(meta) || xref_disagrees(meta)) { if (ctx->mode < SCRUB_MODE_REPAIR) { str_corrupt(ctx, descr_render(&dsc), _("Repairs are required.")); return CHECK_DONE; } return CHECK_REPAIR; } /* * If we could optimize, schedule a repair if desired, * otherwise complain. */ if (is_unoptimized(meta)) { if (ctx->mode != SCRUB_MODE_REPAIR) { if (!is_inode) { /* AG or FS metadata, always warn. */ str_info(ctx, descr_render(&dsc), _("Optimization is possible.")); } else if (!ctx->preen_triggers[meta->sm_type]) { /* File metadata, only warn once per type. */ pthread_mutex_lock(&ctx->lock); if (!ctx->preen_triggers[meta->sm_type]) ctx->preen_triggers[meta->sm_type] = true; pthread_mutex_unlock(&ctx->lock); } return CHECK_DONE; } return CHECK_REPAIR; } /* Everything is ok. */ return CHECK_DONE; } /* Bulk-notify user about things that could be optimized. */ void xfs_scrub_report_preen_triggers( struct scrub_ctx *ctx) { int i; for (i = 0; i < XFS_SCRUB_TYPE_NR; i++) { pthread_mutex_lock(&ctx->lock); if (ctx->preen_triggers[i]) { ctx->preen_triggers[i] = false; pthread_mutex_unlock(&ctx->lock); str_info(ctx, ctx->mntpoint, _("Optimizations of %s are possible."), _(xfrog_scrubbers[i].descr)); } else { pthread_mutex_unlock(&ctx->lock); } } } /* Save a scrub context for later repairs. */ static int xfs_scrub_save_repair( struct scrub_ctx *ctx, struct action_list *alist, struct xfs_scrub_metadata *meta) { struct action_item *aitem; /* Schedule this item for later repairs. */ aitem = malloc(sizeof(struct action_item)); if (!aitem) { str_errno(ctx, _("adding item to repair list")); return errno; } memset(aitem, 0, sizeof(*aitem)); aitem->type = meta->sm_type; aitem->flags = meta->sm_flags; switch (xfrog_scrubbers[meta->sm_type].type) { case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: aitem->agno = meta->sm_agno; break; case XFROG_SCRUB_TYPE_INODE: aitem->ino = meta->sm_ino; aitem->gen = meta->sm_gen; break; default: break; } action_list_add(alist, aitem); return 0; } /* * Scrub a single XFS_SCRUB_TYPE_*, saving corruption reports for later. * * Returns 0 for success. If errors occur, this function will log them and * return a positive error code. */ static int xfs_scrub_meta_type( struct scrub_ctx *ctx, unsigned int type, xfs_agnumber_t agno, struct action_list *alist) { struct xfs_scrub_metadata meta = { .sm_type = type, .sm_agno = agno, }; enum check_outcome fix; int ret; background_sleep(); /* Check the item. */ fix = xfs_check_metadata(ctx, &meta, false); progress_add(1); switch (fix) { case CHECK_ABORT: return ECANCELED; case CHECK_REPAIR: ret = xfs_scrub_save_repair(ctx, alist, &meta); if (ret) return ret; /* fall through */ case CHECK_DONE: return 0; default: /* CHECK_RETRY should never happen. */ abort(); } } /* * Scrub all metadata types that are assigned to the given XFROG_SCRUB_TYPE_*, * saving corruption reports for later. This should not be used for * XFROG_SCRUB_TYPE_INODE or for checking summary metadata. */ static bool xfs_scrub_all_types( struct scrub_ctx *ctx, enum xfrog_scrub_type scrub_type, xfs_agnumber_t agno, struct action_list *alist) { const struct xfrog_scrub_descr *sc; unsigned int type; sc = xfrog_scrubbers; for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) { int ret; if (sc->type != scrub_type) continue; if (sc->flags & XFROG_SCRUB_DESCR_SUMMARY) continue; ret = xfs_scrub_meta_type(ctx, type, agno, alist); if (ret) return ret; } return 0; } /* * Scrub primary superblock. This will be useful if we ever need to hook * a filesystem-wide pre-scrub activity off of the sb 0 scrubber (which * currently does nothing). If errors occur, this function will log them and * return nonzero. */ int xfs_scrub_primary_super( struct scrub_ctx *ctx, struct action_list *alist) { return xfs_scrub_meta_type(ctx, XFS_SCRUB_TYPE_SB, 0, alist); } /* Scrub each AG's header blocks. */ int xfs_scrub_ag_headers( struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist) { return xfs_scrub_all_types(ctx, XFROG_SCRUB_TYPE_AGHEADER, agno, alist); } /* Scrub each AG's metadata btrees. */ int xfs_scrub_ag_metadata( struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist) { return xfs_scrub_all_types(ctx, XFROG_SCRUB_TYPE_PERAG, agno, alist); } /* Scrub whole-FS metadata btrees. */ int xfs_scrub_fs_metadata( struct scrub_ctx *ctx, struct action_list *alist) { return xfs_scrub_all_types(ctx, XFROG_SCRUB_TYPE_FS, 0, alist); } /* Scrub FS summary metadata. */ int xfs_scrub_fs_summary( struct scrub_ctx *ctx, struct action_list *alist) { return xfs_scrub_meta_type(ctx, XFS_SCRUB_TYPE_FSCOUNTERS, 0, alist); } /* How many items do we have to check? */ unsigned int scrub_estimate_ag_work( struct scrub_ctx *ctx) { const struct xfrog_scrub_descr *sc; int type; unsigned int estimate = 0; sc = xfrog_scrubbers; for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) { switch (sc->type) { case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: estimate += ctx->mnt.fsgeom.agcount; break; case XFROG_SCRUB_TYPE_FS: estimate++; break; default: break; } } return estimate; } /* * Scrub inode metadata. If errors occur, this function will log them and * return nonzero. */ static int __xfs_scrub_file( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, unsigned int type, struct action_list *alist) { struct xfs_scrub_metadata meta = {0}; enum check_outcome fix; assert(type < XFS_SCRUB_TYPE_NR); assert(xfrog_scrubbers[type].type == XFROG_SCRUB_TYPE_INODE); meta.sm_type = type; meta.sm_ino = ino; meta.sm_gen = gen; /* Scrub the piece of metadata. */ fix = xfs_check_metadata(ctx, &meta, true); if (fix == CHECK_ABORT) return ECANCELED; if (fix == CHECK_DONE) return 0; return xfs_scrub_save_repair(ctx, alist, &meta); } int xfs_scrub_inode_fields( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_INODE, alist); } int xfs_scrub_data_fork( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTD, alist); } int xfs_scrub_attr_fork( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTA, alist); } int xfs_scrub_cow_fork( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTC, alist); } int xfs_scrub_dir( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_DIR, alist); } int xfs_scrub_attr( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_XATTR, alist); } int xfs_scrub_symlink( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_SYMLINK, alist); } int xfs_scrub_parent( struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist) { return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_PARENT, alist); } /* * Test the availability of a kernel scrub command. If errors occur (or the * scrub ioctl is rejected) the errors will be logged and this function will * return false. */ static bool __xfs_scrub_test( struct scrub_ctx *ctx, unsigned int type, bool repair) { struct xfs_scrub_metadata meta = {0}; struct xfs_error_injection inject; static bool injected; int error; if (debug_tweak_on("XFS_SCRUB_NO_KERNEL")) return false; if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected) { inject.fd = ctx->mnt.fd; inject.errtag = XFS_ERRTAG_FORCE_SCRUB_REPAIR; error = ioctl(ctx->mnt.fd, XFS_IOC_ERROR_INJECTION, &inject); if (error == 0) injected = true; } meta.sm_type = type; if (repair) meta.sm_flags |= XFS_SCRUB_IFLAG_REPAIR; error = -xfrog_scrub_metadata(&ctx->mnt, &meta); switch (error) { case 0: return true; case EROFS: str_info(ctx, ctx->mntpoint, _("Filesystem is mounted read-only; cannot proceed.")); return false; case ENOTRECOVERABLE: str_info(ctx, ctx->mntpoint, _("Filesystem is mounted norecovery; cannot proceed.")); return false; case EOPNOTSUPP: case ENOTTY: if (debug || verbose) str_info(ctx, ctx->mntpoint, _("Kernel %s %s facility not detected."), _(xfrog_scrubbers[type].descr), repair ? _("repair") : _("scrub")); return false; case ENOENT: /* Scrubber says not present on this fs; that's fine. */ return true; default: str_info(ctx, ctx->mntpoint, "%s", strerror(errno)); return true; } } bool xfs_can_scrub_fs_metadata( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, false); } bool xfs_can_scrub_inode( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_INODE, false); } bool xfs_can_scrub_bmap( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_BMBTD, false); } bool xfs_can_scrub_dir( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_DIR, false); } bool xfs_can_scrub_attr( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_XATTR, false); } bool xfs_can_scrub_symlink( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_SYMLINK, false); } bool xfs_can_scrub_parent( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PARENT, false); } bool xfs_can_repair( struct scrub_ctx *ctx) { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, true); } /* General repair routines. */ /* Repair some metadata. */ enum check_outcome xfs_repair_metadata( struct scrub_ctx *ctx, int fd, struct action_item *aitem, unsigned int repair_flags) { struct xfs_scrub_metadata meta = { 0 }; struct xfs_scrub_metadata oldm; DEFINE_DESCR(dsc, ctx, format_scrub_descr); int error; assert(aitem->type < XFS_SCRUB_TYPE_NR); assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); meta.sm_type = aitem->type; meta.sm_flags = aitem->flags | XFS_SCRUB_IFLAG_REPAIR; switch (xfrog_scrubbers[aitem->type].type) { case XFROG_SCRUB_TYPE_AGHEADER: case XFROG_SCRUB_TYPE_PERAG: meta.sm_agno = aitem->agno; break; case XFROG_SCRUB_TYPE_INODE: meta.sm_ino = aitem->ino; meta.sm_gen = aitem->gen; break; default: break; } if (!is_corrupt(&meta) && (repair_flags & XRM_REPAIR_ONLY)) return CHECK_RETRY; memcpy(&oldm, &meta, sizeof(oldm)); descr_set(&dsc, &oldm); if (needs_repair(&meta)) str_info(ctx, descr_render(&dsc), _("Attempting repair.")); else if (debug || verbose) str_info(ctx, descr_render(&dsc), _("Attempting optimization.")); error = -xfrog_scrub_metadata(&ctx->mnt, &meta); switch (error) { case 0: /* No operational errors encountered. */ break; case EDEADLOCK: case EBUSY: /* Filesystem is busy, try again later. */ if (debug || verbose) str_info(ctx, descr_render(&dsc), _("Filesystem is busy, deferring repair.")); return CHECK_RETRY; case ESHUTDOWN: /* Filesystem is already shut down, abort. */ str_error(ctx, descr_render(&dsc), _("Filesystem is shut down, aborting.")); return CHECK_ABORT; case ENOTTY: case EOPNOTSUPP: /* * If we're in no-complain mode, requeue the check for * later. It's possible that an error in another * component caused us to flag an error in this * component. Even if the kernel didn't think it * could fix this, it's at least worth trying the scan * again to see if another repair fixed it. */ if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED)) return CHECK_RETRY; /* * If we forced repairs or this is a preen, don't * error out if the kernel doesn't know how to fix. */ if (is_unoptimized(&oldm) || debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) return CHECK_DONE; /* fall through */ case EINVAL: /* Kernel doesn't know how to repair this? */ str_corrupt(ctx, _("%s: Don't know how to fix; offline repair required."), descr_render(&dsc)); return CHECK_DONE; case EROFS: /* Read-only filesystem, can't fix. */ if (verbose || debug || needs_repair(&oldm)) str_error(ctx, descr_render(&dsc), _("Read-only filesystem; cannot make changes.")); return CHECK_ABORT; case ENOENT: /* Metadata not present, just skip it. */ return CHECK_DONE; case ENOMEM: case ENOSPC: /* Don't care if preen fails due to low resources. */ if (is_unoptimized(&oldm) && !needs_repair(&oldm)) return CHECK_DONE; /* fall through */ default: /* * Operational error. If the caller doesn't want us * to complain about repair failures, tell the caller * to requeue the repair for later and don't say a * thing. Otherwise, print error and bail out. */ if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED)) return CHECK_RETRY; str_liberror(ctx, error, descr_render(&dsc)); return CHECK_DONE; } if (repair_flags & XRM_COMPLAIN_IF_UNFIXED) xfs_scrub_warn_incomplete_scrub(ctx, &dsc, &meta); if (needs_repair(&meta)) { /* * Still broken; if we've been told not to complain then we * just requeue this and try again later. Otherwise we * log the error loudly and don't try again. */ if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED)) return CHECK_RETRY; str_corrupt(ctx, descr_render(&dsc), _("Repair unsuccessful; offline repair required.")); } else { /* Clean operation, no corruption detected. */ if (needs_repair(&oldm)) record_repair(ctx, descr_render(&dsc), _("Repairs successful.")); else record_preen(ctx, descr_render(&dsc), _("Optimization successful.")); } return CHECK_DONE; } xfsprogs-5.3.0/scrub/scrub.h0000644000175000017500000000547213570057155015671 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_SCRUB_H_ #define XFS_SCRUB_SCRUB_H_ /* Online scrub and repair. */ enum check_outcome { CHECK_DONE, /* no further processing needed */ CHECK_REPAIR, /* schedule this for repairs */ CHECK_ABORT, /* end program */ CHECK_RETRY, /* repair failed, try again later */ }; struct action_item; void xfs_scrub_report_preen_triggers(struct scrub_ctx *ctx); int xfs_scrub_primary_super(struct scrub_ctx *ctx, struct action_list *alist); int xfs_scrub_ag_headers(struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist); int xfs_scrub_ag_metadata(struct scrub_ctx *ctx, xfs_agnumber_t agno, struct action_list *alist); int xfs_scrub_fs_metadata(struct scrub_ctx *ctx, struct action_list *alist); int xfs_scrub_fs_summary(struct scrub_ctx *ctx, struct action_list *alist); bool xfs_can_scrub_fs_metadata(struct scrub_ctx *ctx); bool xfs_can_scrub_inode(struct scrub_ctx *ctx); bool xfs_can_scrub_bmap(struct scrub_ctx *ctx); bool xfs_can_scrub_dir(struct scrub_ctx *ctx); bool xfs_can_scrub_attr(struct scrub_ctx *ctx); bool xfs_can_scrub_symlink(struct scrub_ctx *ctx); bool xfs_can_scrub_parent(struct scrub_ctx *ctx); bool xfs_can_repair(struct scrub_ctx *ctx); int xfs_scrub_inode_fields(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_data_fork(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_attr_fork(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_cow_fork(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_dir(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_attr(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_symlink(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); int xfs_scrub_parent(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen, struct action_list *alist); /* Repair parameters are the scrub inputs and retry count. */ struct action_item { struct list_head list; __u64 ino; __u32 type; __u32 flags; __u32 gen; __u32 agno; }; /* * Only ask the kernel to repair this object if the kernel directly told us it * was corrupt. Objects that are only flagged as having cross-referencing * errors or flagged as eligible for optimization are left for later. */ #define XRM_REPAIR_ONLY (1U << 0) /* Complain if still broken even after fix. */ #define XRM_COMPLAIN_IF_UNFIXED (1U << 1) enum check_outcome xfs_repair_metadata(struct scrub_ctx *ctx, int fd, struct action_item *aitem, unsigned int repair_flags); #endif /* XFS_SCRUB_SCRUB_H_ */ xfsprogs-5.3.0/scrub/spacemap.c0000644000175000017500000001321013570057155016324 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "libfrog/workqueue.h" #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "spacemap.h" /* * Filesystem space map iterators. * * Logically, we call GETFSMAP to fetch a set of space map records and * call a function to iterate over the records. However, that's not * what actually happens -- the work is split into separate items, with * each AG, the realtime device, and the log device getting their own * work items. For an XFS with a realtime device and an external log, * this means that we can have up to ($agcount + 2) threads running at * once. * * This comes into play if we want to have per-workitem memory. Maybe. * XXX: do we really need all that ? */ #define FSMAP_NR 65536 /* * Iterate all the fs block mappings between the two keys. Returns 0 or a * positive error number. */ int scrub_iterate_fsmap( struct scrub_ctx *ctx, struct fsmap *keys, scrub_fsmap_iter_fn fn, void *arg) { struct fsmap_head *head; struct fsmap *p; int i; int error; head = malloc(fsmap_sizeof(FSMAP_NR)); if (!head) return errno; memset(head, 0, sizeof(*head)); memcpy(head->fmh_keys, keys, sizeof(struct fsmap) * 2); head->fmh_count = FSMAP_NR; while ((error = ioctl(ctx->mnt.fd, FS_IOC_GETFSMAP, head)) == 0) { for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { error = fn(ctx, p, arg); if (error) goto out; if (xfs_scrub_excessive_errors(ctx)) goto out; } if (head->fmh_entries == 0) break; p = &head->fmh_recs[head->fmh_entries - 1]; if (p->fmr_flags & FMR_OF_LAST) break; fsmap_advance(head); } if (error) error = errno; out: free(head); return error; } /* GETFSMAP wrappers routines. */ struct scan_blocks { scrub_fsmap_iter_fn fn; void *arg; bool aborted; }; /* Iterate all the reverse mappings of an AG. */ static void scan_ag_rmaps( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; struct scan_blocks *sbx = arg; struct fsmap keys[2]; off64_t bperag; int ret; bperag = (off64_t)ctx->mnt.fsgeom.agblocks * (off64_t)ctx->mnt.fsgeom.blocksize; memset(keys, 0, sizeof(struct fsmap) * 2); keys->fmr_device = ctx->fsinfo.fs_datadev; keys->fmr_physical = agno * bperag; (keys + 1)->fmr_device = ctx->fsinfo.fs_datadev; (keys + 1)->fmr_physical = ((agno + 1) * bperag) - 1; (keys + 1)->fmr_owner = ULLONG_MAX; (keys + 1)->fmr_offset = ULLONG_MAX; (keys + 1)->fmr_flags = UINT_MAX; if (sbx->aborted) return; ret = scrub_iterate_fsmap(ctx, keys, sbx->fn, sbx->arg); if (ret) { char descr[DESCR_BUFSZ]; snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u fsmap"), major(ctx->fsinfo.fs_datadev), minor(ctx->fsinfo.fs_datadev), agno); str_liberror(ctx, ret, descr); sbx->aborted = true; } } /* Iterate all the reverse mappings of a standalone device. */ static void scan_dev_rmaps( struct scrub_ctx *ctx, int idx, dev_t dev, struct scan_blocks *sbx) { struct fsmap keys[2]; int ret; memset(keys, 0, sizeof(struct fsmap) * 2); keys->fmr_device = dev; (keys + 1)->fmr_device = dev; (keys + 1)->fmr_physical = ULLONG_MAX; (keys + 1)->fmr_owner = ULLONG_MAX; (keys + 1)->fmr_offset = ULLONG_MAX; (keys + 1)->fmr_flags = UINT_MAX; if (sbx->aborted) return; ret = scrub_iterate_fsmap(ctx, keys, sbx->fn, sbx->arg); if (ret) { char descr[DESCR_BUFSZ]; snprintf(descr, DESCR_BUFSZ, _("dev %d:%d fsmap"), major(dev), minor(dev)); str_liberror(ctx, ret, descr); sbx->aborted = true; } } /* Iterate all the reverse mappings of the realtime device. */ static void scan_rt_rmaps( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; scan_dev_rmaps(ctx, agno, ctx->fsinfo.fs_rtdev, arg); } /* Iterate all the reverse mappings of the log device. */ static void scan_log_rmaps( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; scan_dev_rmaps(ctx, agno, ctx->fsinfo.fs_logdev, arg); } /* * Scan all the blocks in a filesystem. If errors occur, this function will * log them and return nonzero. */ int scrub_scan_all_spacemaps( struct scrub_ctx *ctx, scrub_fsmap_iter_fn fn, void *arg) { struct workqueue wq; struct scan_blocks sbx = { .fn = fn, .arg = arg, }; xfs_agnumber_t agno; int ret; ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, scrub_nproc_workqueue(ctx)); if (ret) { str_liberror(ctx, ret, _("creating fsmap workqueue")); return ret; } if (ctx->fsinfo.fs_rt) { ret = -workqueue_add(&wq, scan_rt_rmaps, ctx->mnt.fsgeom.agcount + 1, &sbx); if (ret) { sbx.aborted = true; str_liberror(ctx, ret, _("queueing rtdev fsmap work")); goto out; } } if (ctx->fsinfo.fs_log) { ret = -workqueue_add(&wq, scan_log_rmaps, ctx->mnt.fsgeom.agcount + 2, &sbx); if (ret) { sbx.aborted = true; str_liberror(ctx, ret, _("queueing logdev fsmap work")); goto out; } } for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) { ret = -workqueue_add(&wq, scan_ag_rmaps, agno, &sbx); if (ret) { sbx.aborted = true; str_liberror(ctx, ret, _("queueing per-AG fsmap work")); break; } } out: ret = -workqueue_terminate(&wq); if (ret) { sbx.aborted = true; str_liberror(ctx, ret, _("finishing fsmap work")); } workqueue_destroy(&wq); if (!ret && sbx.aborted) ret = -1; return ret; } xfsprogs-5.3.0/scrub/spacemap.h0000644000175000017500000000126313570057155016336 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_SPACEMAP_H_ #define XFS_SCRUB_SPACEMAP_H_ /* * Visit each space mapping in the filesystem. Return 0 to continue iteration * or a positive error code to stop iterating and return to the caller. */ typedef int (*scrub_fsmap_iter_fn)(struct scrub_ctx *ctx, struct fsmap *fsr, void *arg); int scrub_iterate_fsmap(struct scrub_ctx *ctx, struct fsmap *keys, scrub_fsmap_iter_fn fn, void *arg); int scrub_scan_all_spacemaps(struct scrub_ctx *ctx, scrub_fsmap_iter_fn fn, void *arg); #endif /* XFS_SCRUB_SPACEMAP_H_ */ xfsprogs-5.3.0/scrub/unicrash.c0000644000175000017500000004466713570057155016373 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include #include #include #include #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "descr.h" #include "unicrash.h" /* * Detect Unicode confusable names in directories and attributes. * * Record all the name->ino mappings in a directory/xattr, with a twist! The * twist is to record the Unicode skeleton and normalized version of every * name we see so that we can check for a name space (directory, extended * attribute set) containing names containing malicious characters or that * could be confused for one another. These entries are at best a sign of * Unicode mishandling, or some sort of weird name substitution attack if the * entries do not point to the same inode. Warn if we see multiple dirents * that do not all point to the same inode. * * For extended attributes we perform the same collision checks on the * attribute, though any collision is enough to trigger a warning. * * We avoid flagging these problems as errors because XFS treats names as a * sequence of arbitrary nonzero bytes. While a Unicode collision is not * technically a filesystem corruption, we ought to say something if there's a * possibility for misleading a user. Unquestionably bad things (direction * overrides, control characters, names that normalize to the same string) * produce warnings, whereas potentially confusable names produce * informational messages. * * The skeleton algorithm is detailed in section 4 ("Confusable Detection") of * the Unicode technical standard #39. First we normalize the name, then we * substitute code points according to the confusable code point table, then * normalize again. * * We take the extra step of removing non-identifier code points such as * formatting characters, control characters, zero width characters, etc. * from the skeleton so that we can complain about names that are confusable * due to invisible control characters. * * In other words, skel = remove_invisible(nfd(remap_confusables(nfd(name)))). */ struct name_entry { struct name_entry *next; /* NFKC normalized name */ UChar *normstr; size_t normstrlen; /* Unicode skeletonized name */ UChar *skelstr; size_t skelstrlen; xfs_ino_t ino; /* Raw UTF8 name */ size_t namelen; char name[0]; }; #define NAME_ENTRY_SZ(nl) (sizeof(struct name_entry) + 1 + \ (nl * sizeof(uint8_t))) struct unicrash { struct scrub_ctx *ctx; USpoofChecker *spoof; const UNormalizer2 *normalizer; bool compare_ino; bool is_only_root_writeable; size_t nr_buckets; struct name_entry *buckets[0]; }; #define UNICRASH_SZ(nr) (sizeof(struct unicrash) + \ (nr * sizeof(struct name_entry *))) /* Things to complain about in Unicode naming. */ /* * Multiple names resolve to the same normalized string and therefore render * identically. */ #define UNICRASH_NOT_UNIQUE (1 << 0) /* Name contains directional overrides. */ #define UNICRASH_BIDI_OVERRIDE (1 << 1) /* Name mixes left-to-right and right-to-left characters. */ #define UNICRASH_BIDI_MIXED (1 << 2) /* Control characters in name. */ #define UNICRASH_CONTROL_CHAR (1 << 3) /* Invisible characters. Only a problem if we have collisions. */ #define UNICRASH_ZERO_WIDTH (1 << 4) /* Multiple names resolve to the same skeleton string. */ #define UNICRASH_CONFUSABLE (1 << 5) /* * We only care about validating utf8 collisions if the underlying * system configuration says we're using utf8. If the language * specifier string used to output messages has ".UTF-8" somewhere in * its name, then we conclude utf8 is in use. Otherwise, no checking is * performed. * * Most modern Linux systems default to utf8, so the only time this * check will return false is if the administrator configured things * this way or if things are so messed up there is no locale data at * all. */ #define UTF8_STR ".UTF-8" #define UTF8_STRLEN (sizeof(UTF8_STR) - 1) static bool is_utf8_locale(void) { const char *msg_locale; static int answer = -1; if (answer != -1) return answer; msg_locale = setlocale(LC_MESSAGES, NULL); if (msg_locale == NULL) return false; if (strstr(msg_locale, UTF8_STR) != NULL) answer = 1; else answer = 0; return answer; } /* * Generate normalized form and skeleton of the name. If this fails, just * forget everything and return false; this is an advisory checker. */ static bool name_entry_compute_checknames( struct unicrash *uc, struct name_entry *entry) { UChar *normstr; UChar *unistr; UChar *skelstr; int32_t normstrlen; int32_t unistrlen; int32_t skelstrlen; UChar32 uchr; int32_t i, j; UErrorCode uerr = U_ZERO_ERROR; /* Convert bytestr to unistr for normalization */ u_strFromUTF8(NULL, 0, &unistrlen, entry->name, entry->namelen, &uerr); if (uerr != U_BUFFER_OVERFLOW_ERROR) return false; uerr = U_ZERO_ERROR; unistr = calloc(unistrlen + 1, sizeof(UChar)); if (!unistr) return false; u_strFromUTF8(unistr, unistrlen, NULL, entry->name, entry->namelen, &uerr); if (U_FAILURE(uerr)) goto out_unistr; /* Normalize the string. */ normstrlen = unorm2_normalize(uc->normalizer, unistr, unistrlen, NULL, 0, &uerr); if (uerr != U_BUFFER_OVERFLOW_ERROR) goto out_unistr; uerr = U_ZERO_ERROR; normstr = calloc(normstrlen + 1, sizeof(UChar)); if (!normstr) goto out_unistr; unorm2_normalize(uc->normalizer, unistr, unistrlen, normstr, normstrlen, &uerr); if (U_FAILURE(uerr)) goto out_normstr; /* Compute skeleton. */ skelstrlen = uspoof_getSkeleton(uc->spoof, 0, unistr, unistrlen, NULL, 0, &uerr); if (uerr != U_BUFFER_OVERFLOW_ERROR) goto out_normstr; uerr = U_ZERO_ERROR; skelstr = calloc(skelstrlen + 1, sizeof(UChar)); if (!skelstr) goto out_normstr; uspoof_getSkeleton(uc->spoof, 0, unistr, unistrlen, skelstr, skelstrlen, &uerr); if (U_FAILURE(uerr)) goto out_skelstr; /* Remove control/formatting characters from skeleton. */ for (i = 0, j = 0; i < skelstrlen; j = i) { U16_NEXT_UNSAFE(skelstr, i, uchr); if (!u_isIDIgnorable(uchr)) continue; memmove(&skelstr[j], &skelstr[i], (skelstrlen - i + 1) * sizeof(UChar)); skelstrlen -= (i - j); i = j; } entry->skelstr = skelstr; entry->skelstrlen = skelstrlen; entry->normstr = normstr; entry->normstrlen = normstrlen; free(unistr); return true; out_skelstr: free(skelstr); out_normstr: free(normstr); out_unistr: free(unistr); return false; } /* Create a new name entry, returns false if we could not succeed. */ static bool name_entry_create( struct unicrash *uc, const char *name, xfs_ino_t ino, struct name_entry **entry) { struct name_entry *new_entry; size_t namelen = strlen(name); /* Create new entry */ new_entry = calloc(NAME_ENTRY_SZ(namelen), 1); if (!new_entry) return false; new_entry->next = NULL; new_entry->ino = ino; memcpy(new_entry->name, name, namelen); new_entry->name[namelen] = 0; new_entry->namelen = namelen; /* Normalize/skeletonize name to find collisions. */ if (!name_entry_compute_checknames(uc, new_entry)) goto out; *entry = new_entry; return true; out: free(new_entry); return false; } /* Free a name entry */ static void name_entry_free( struct name_entry *entry) { free(entry->normstr); free(entry->skelstr); free(entry); } /* Adapt the dirhash function from libxfs, avoid linking with libxfs. */ #define rol32(x, y) (((x) << (y)) | ((x) >> (32 - (y)))) /* * Implement a simple hash on a character string. * Rotate the hash value by 7 bits, then XOR each character in. * This is implemented with some source-level loop unrolling. */ static xfs_dahash_t name_entry_hash( struct name_entry *entry) { uint8_t *name; size_t namelen; xfs_dahash_t hash; name = (uint8_t *)entry->skelstr; namelen = entry->skelstrlen * sizeof(UChar); /* * Do four characters at a time as long as we can. */ for (hash = 0; namelen >= 4; namelen -= 4, name += 4) hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ (name[3] << 0) ^ rol32(hash, 7 * 4); /* * Now do the rest of the characters. */ switch (namelen) { case 3: return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ rol32(hash, 7 * 3); case 2: return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2); case 1: return (name[0] << 0) ^ rol32(hash, 7 * 1); default: /* case 0: */ return hash; } } /* * Check a name for suspicious elements that have appeared in filename * spoofing attacks. This includes names that mixed directions or contain * direction overrides control characters, both of which have appeared in * filename spoofing attacks. */ static void name_entry_examine( struct name_entry *entry, unsigned int *badflags) { UChar32 uchr; int32_t i; uint8_t mask = 0; for (i = 0; i < entry->normstrlen;) { U16_NEXT_UNSAFE(entry->normstr, i, uchr); /* zero width character sequences */ switch (uchr) { case 0x200B: /* zero width space */ case 0x200C: /* zero width non-joiner */ case 0x200D: /* zero width joiner */ case 0xFEFF: /* zero width non breaking space */ case 0x2060: /* word joiner */ case 0x2061: /* function application */ case 0x2062: /* invisible times (multiply) */ case 0x2063: /* invisible separator (comma) */ case 0x2064: /* invisible plus (addition) */ *badflags |= UNICRASH_ZERO_WIDTH; break; } /* control characters */ if (u_iscntrl(uchr)) *badflags |= UNICRASH_CONTROL_CHAR; switch (u_charDirection(uchr)) { case U_LEFT_TO_RIGHT: mask |= 0x01; break; case U_RIGHT_TO_LEFT: mask |= 0x02; break; case U_RIGHT_TO_LEFT_OVERRIDE: *badflags |= UNICRASH_BIDI_OVERRIDE; break; case U_LEFT_TO_RIGHT_OVERRIDE: *badflags |= UNICRASH_BIDI_OVERRIDE; break; default: break; } } /* mixing left-to-right and right-to-left chars */ if (mask == 0x3) *badflags |= UNICRASH_BIDI_MIXED; } /* Initialize the collision detector. */ static int unicrash_init( struct unicrash **ucp, struct scrub_ctx *ctx, bool compare_ino, size_t nr_buckets, bool is_only_root_writeable) { struct unicrash *p; UErrorCode uerr = U_ZERO_ERROR; if (!is_utf8_locale()) { *ucp = NULL; return 0; } if (nr_buckets > 65536) nr_buckets = 65536; else if (nr_buckets < 16) nr_buckets = 16; p = calloc(1, UNICRASH_SZ(nr_buckets)); if (!p) return errno; p->ctx = ctx; p->nr_buckets = nr_buckets; p->compare_ino = compare_ino; p->normalizer = unorm2_getNFKCInstance(&uerr); if (U_FAILURE(uerr)) goto out_free; p->spoof = uspoof_open(&uerr); if (U_FAILURE(uerr)) goto out_free; uspoof_setChecks(p->spoof, USPOOF_ALL_CHECKS, &uerr); if (U_FAILURE(uerr)) goto out_spoof; p->is_only_root_writeable = is_only_root_writeable; *ucp = p; return 0; out_spoof: uspoof_close(p->spoof); out_free: free(p); return ENOMEM; } /* * Is this inode owned by root and not writable by others? If so, skip * even the informational messages, because this was put in place by the * administrator. */ static bool is_only_root_writable( struct xfs_bulkstat *bstat) { if (bstat->bs_uid != 0 || bstat->bs_gid != 0) return false; return !(bstat->bs_mode & S_IWOTH); } /* Initialize the collision detector for a directory. */ int unicrash_dir_init( struct unicrash **ucp, struct scrub_ctx *ctx, struct xfs_bulkstat *bstat) { /* * Assume 64 bytes per dentry, clamp buckets between 16 and 64k. * Same general idea as dir_hash_init in xfs_repair. */ return unicrash_init(ucp, ctx, true, bstat->bs_size / 64, is_only_root_writable(bstat)); } /* Initialize the collision detector for an extended attribute. */ int unicrash_xattr_init( struct unicrash **ucp, struct scrub_ctx *ctx, struct xfs_bulkstat *bstat) { /* Assume 16 attributes per extent for lack of a better idea. */ return unicrash_init(ucp, ctx, false, 16 * (1 + bstat->bs_aextents), is_only_root_writable(bstat)); } /* Initialize the collision detector for a filesystem label. */ int unicrash_fs_label_init( struct unicrash **ucp, struct scrub_ctx *ctx) { return unicrash_init(ucp, ctx, false, 16, true); } /* Free the crash detector. */ void unicrash_free( struct unicrash *uc) { struct name_entry *ne; struct name_entry *x; size_t i; if (!uc) return; uspoof_close(uc->spoof); for (i = 0; i < uc->nr_buckets; i++) { for (ne = uc->buckets[i]; ne != NULL; ne = x) { x = ne->next; name_entry_free(ne); } } free(uc); } /* Complain about Unicode problems. */ static void unicrash_complain( struct unicrash *uc, struct descr *dsc, const char *what, struct name_entry *entry, unsigned int badflags, struct name_entry *dup_entry) { char *bad1 = NULL; char *bad2 = NULL; bad1 = string_escape(entry->name); if (dup_entry) bad2 = string_escape(dup_entry->name); /* * Most filechooser UIs do not look for bidirectional overrides when * they render names. This can result in misleading name presentation * that makes "higgnp.sh" render like "highs.png". */ if (badflags & UNICRASH_BIDI_OVERRIDE) { str_warn(uc->ctx, descr_render(dsc), _("Unicode name \"%s\" in %s contains suspicious text direction overrides."), bad1, what); goto out; } /* * Two names that normalize to the same string will render * identically even though the filesystem considers them unique * names. "cafe\xcc\x81" and "caf\xc3\xa9" have different byte * sequences, but they both appear as "café". */ if (badflags & UNICRASH_NOT_UNIQUE) { str_warn(uc->ctx, descr_render(dsc), _("Unicode name \"%s\" in %s renders identically to \"%s\"."), bad1, what, bad2); goto out; } /* * If a name contains invisible/nonprinting characters and can be * confused with another name as a result, we should complain. * "moocow" and "moocow" are misleading. */ if ((badflags & UNICRASH_ZERO_WIDTH) && (badflags & UNICRASH_CONFUSABLE)) { str_warn(uc->ctx, descr_render(dsc), _("Unicode name \"%s\" in %s could be confused with '%s' due to invisible characters."), bad1, what, bad2); goto out; } /* * Unfiltered control characters can mess up your terminal and render * invisibly in filechooser UIs. */ if (badflags & UNICRASH_CONTROL_CHAR) { str_warn(uc->ctx, descr_render(dsc), _("Unicode name \"%s\" in %s contains control characters."), bad1, what); goto out; } /* * Skip the informational messages if the inode owning the name is * only writeable by root, because those files were put there by the * sysadmin. Also skip names less than four letters long because * there's a much higher chance of collisions with short names. */ if (!verbose && (uc->is_only_root_writeable || entry->namelen < 4)) goto out; /* * It's not considered good practice (says Unicode) to mix LTR * characters with RTL characters. The mere presence of different * bidirectional characters isn't enough to trip up software, so don't * warn about this too loudly. */ if (badflags & UNICRASH_BIDI_MIXED) { str_info(uc->ctx, descr_render(dsc), _("Unicode name \"%s\" in %s mixes bidirectional characters."), bad1, what); goto out; } /* * We'll note if two names could be confusable with each other, but * whether or not the user will actually confuse them is dependent * on the rendering system and the typefaces in use. Maybe "foo.1" * and "moo.l" look the same, maybe they do not. */ if (badflags & UNICRASH_CONFUSABLE) { str_info(uc->ctx, descr_render(dsc), _("Unicode name \"%s\" in %s could be confused with \"%s\"."), bad1, what, bad2); } out: free(bad1); free(bad2); } /* * Try to add a name -> ino entry to the collision detector. The name * must be skeletonized according to Unicode TR39 to detect names that * could be visually confused with each other. */ static void unicrash_add( struct unicrash *uc, struct name_entry *new_entry, unsigned int *badflags, struct name_entry **existing_entry) { struct name_entry *entry; size_t bucket; xfs_dahash_t hash; /* Store name in hashtable. */ hash = name_entry_hash(new_entry); bucket = hash % uc->nr_buckets; entry = uc->buckets[bucket]; new_entry->next = entry; uc->buckets[bucket] = new_entry; while (entry != NULL) { /* Same normalization? */ if (new_entry->normstrlen == entry->normstrlen && !u_strcmp(new_entry->normstr, entry->normstr) && (uc->compare_ino ? entry->ino != new_entry->ino : true)) { *badflags |= UNICRASH_NOT_UNIQUE; *existing_entry = entry; return; } /* Confusable? */ if (new_entry->skelstrlen == entry->skelstrlen && !u_strcmp(new_entry->skelstr, entry->skelstr) && (uc->compare_ino ? entry->ino != new_entry->ino : true)) { *badflags |= UNICRASH_CONFUSABLE; *existing_entry = entry; return; } entry = entry->next; } } /* Check a name for unicode normalization problems or collisions. */ static int __unicrash_check_name( struct unicrash *uc, struct descr *dsc, const char *namedescr, const char *name, xfs_ino_t ino) { struct name_entry *dup_entry = NULL; struct name_entry *new_entry = NULL; unsigned int badflags = 0; /* If we can't create entry data, just skip it. */ if (!name_entry_create(uc, name, ino, &new_entry)) return 0; name_entry_examine(new_entry, &badflags); unicrash_add(uc, new_entry, &badflags, &dup_entry); if (badflags) unicrash_complain(uc, dsc, namedescr, new_entry, badflags, dup_entry); return 0; } /* * Check a directory entry for unicode normalization problems or collisions. * If errors occur, this function will log them and return nonzero. */ int unicrash_check_dir_name( struct unicrash *uc, struct descr *dsc, struct dirent *dentry) { if (!uc) return 0; return __unicrash_check_name(uc, dsc, _("directory"), dentry->d_name, dentry->d_ino); } /* * Check an extended attribute name for unicode normalization problems * or collisions. If errors occur, this function will log them and return * nonzero. */ int unicrash_check_xattr_name( struct unicrash *uc, struct descr *dsc, const char *attrname) { if (!uc) return 0; return __unicrash_check_name(uc, dsc, _("extended attribute"), attrname, 0); } /* * Check the fs label for unicode normalization problems or misleading bits. * If errors occur, this function will log them and return nonzero. */ int unicrash_check_fs_label( struct unicrash *uc, struct descr *dsc, const char *label) { if (!uc) return 0; return __unicrash_check_name(uc, dsc, _("filesystem label"), label, 0); } xfsprogs-5.3.0/scrub/unicrash.h0000644000175000017500000000240613570057155016361 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_UNICRASH_H_ #define XFS_SCRUB_UNICRASH_H_ struct unicrash; /* Unicode name collision detection. */ #ifdef HAVE_LIBICU struct dirent; int unicrash_dir_init(struct unicrash **ucp, struct scrub_ctx *ctx, struct xfs_bulkstat *bstat); int unicrash_xattr_init(struct unicrash **ucp, struct scrub_ctx *ctx, struct xfs_bulkstat *bstat); int unicrash_fs_label_init(struct unicrash **ucp, struct scrub_ctx *ctx); void unicrash_free(struct unicrash *uc); int unicrash_check_dir_name(struct unicrash *uc, struct descr *dsc, struct dirent *dirent); int unicrash_check_xattr_name(struct unicrash *uc, struct descr *dsc, const char *attrname); int unicrash_check_fs_label(struct unicrash *uc, struct descr *dsc, const char *label); #else # define unicrash_dir_init(u, c, b) (0) # define unicrash_xattr_init(u, c, b) (0) # define unicrash_fs_label_init(u, c) (0) # define unicrash_free(u) do {(u) = (u);} while (0) # define unicrash_check_dir_name(u, d, n) (0) # define unicrash_check_xattr_name(u, d, n) (0) # define unicrash_check_fs_label(u, d, n) (0) #endif /* HAVE_LIBICU */ #endif /* XFS_SCRUB_UNICRASH_H_ */ xfsprogs-5.3.0/scrub/vfs.c0000644000175000017500000001521213570057155015335 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include "handle.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" #include "xfs_scrub.h" #include "common.h" #include "vfs.h" #ifndef AT_NO_AUTOMOUNT # define AT_NO_AUTOMOUNT 0x800 #endif /* * Helper functions to assist in traversing a directory tree using regular * VFS calls. */ /* Scan a filesystem tree. */ struct scan_fs_tree { unsigned int nr_dirs; pthread_mutex_t lock; pthread_cond_t wakeup; struct stat root_sb; bool aborted; scan_fs_tree_dir_fn dir_fn; scan_fs_tree_dirent_fn dirent_fn; void *arg; }; /* Per-work-item scan context. */ struct scan_fs_tree_dir { char *path; struct scan_fs_tree *sft; bool rootdir; }; static void scan_fs_dir(struct workqueue *wq, xfs_agnumber_t agno, void *arg); /* Increment the number of directories that are queued for processing. */ static void inc_nr_dirs( struct scan_fs_tree *sft) { pthread_mutex_lock(&sft->lock); sft->nr_dirs++; pthread_mutex_unlock(&sft->lock); } /* * Decrement the number of directories that are queued for processing and if * we ran out of dirs to process, wake up anyone who was waiting for processing * to finish. */ static void dec_nr_dirs( struct scan_fs_tree *sft) { pthread_mutex_lock(&sft->lock); sft->nr_dirs--; if (sft->nr_dirs == 0) pthread_cond_signal(&sft->wakeup); pthread_mutex_unlock(&sft->lock); } /* Queue a directory for scanning. */ static int queue_subdir( struct scrub_ctx *ctx, struct scan_fs_tree *sft, struct workqueue *wq, const char *path, bool is_rootdir) { struct scan_fs_tree_dir *new_sftd; int error; new_sftd = malloc(sizeof(struct scan_fs_tree_dir)); if (!new_sftd) return errno; new_sftd->path = strdup(path); if (!new_sftd->path) { error = errno; goto out_sftd; } new_sftd->sft = sft; new_sftd->rootdir = is_rootdir; inc_nr_dirs(sft); error = -workqueue_add(wq, scan_fs_dir, 0, new_sftd); if (error) { dec_nr_dirs(sft); str_liberror(ctx, error, _("queueing directory scan work")); goto out_path; } return 0; out_path: free(new_sftd->path); out_sftd: free(new_sftd); return error; } /* Scan a directory sub tree. */ static void scan_fs_dir( struct workqueue *wq, xfs_agnumber_t agno, void *arg) { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; struct scan_fs_tree_dir *sftd = arg; struct scan_fs_tree *sft = sftd->sft; DIR *dir; struct dirent *dirent; char newpath[PATH_MAX]; struct stat sb; int dir_fd; int error; /* Open the directory. */ dir_fd = open(sftd->path, O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); if (dir_fd < 0) { if (errno != ENOENT) str_errno(ctx, sftd->path); goto out; } /* Caller-specific directory checks. */ error = sft->dir_fn(ctx, sftd->path, dir_fd, sft->arg); if (error) { sft->aborted = true; error = close(dir_fd); if (error) str_errno(ctx, sftd->path); goto out; } /* Iterate the directory entries. */ dir = fdopendir(dir_fd); if (!dir) { str_errno(ctx, sftd->path); sft->aborted = true; close(dir_fd); goto out; } rewinddir(dir); for (dirent = readdir(dir); !sft->aborted && dirent != NULL; dirent = readdir(dir)) { snprintf(newpath, PATH_MAX, "%s/%s", sftd->path, dirent->d_name); /* Get the stat info for this directory entry. */ error = fstatat(dir_fd, dirent->d_name, &sb, AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW); if (error) { str_errno(ctx, newpath); continue; } /* Ignore files on other filesystems. */ if (sb.st_dev != sft->root_sb.st_dev) continue; /* Caller-specific directory entry function. */ error = sft->dirent_fn(ctx, newpath, dir_fd, dirent, &sb, sft->arg); if (error) { sft->aborted = true; break; } if (xfs_scrub_excessive_errors(ctx)) { sft->aborted = true; break; } /* If directory, call ourselves recursively. */ if (S_ISDIR(sb.st_mode) && strcmp(".", dirent->d_name) && strcmp("..", dirent->d_name)) { error = queue_subdir(ctx, sft, wq, newpath, false); if (error) { str_liberror(ctx, error, _("queueing subdirectory scan")); sft->aborted = true; break; } } } /* Close dir, go away. */ error = closedir(dir); if (error) str_errno(ctx, sftd->path); out: dec_nr_dirs(sft); free(sftd->path); free(sftd); } /* * Scan the entire filesystem. This function returns 0 on success; if there * are errors, this function will log them and returns nonzero. */ int scan_fs_tree( struct scrub_ctx *ctx, scan_fs_tree_dir_fn dir_fn, scan_fs_tree_dirent_fn dirent_fn, void *arg) { struct workqueue wq; struct scan_fs_tree sft = { .root_sb = ctx->mnt_sb, .dir_fn = dir_fn, .dirent_fn = dirent_fn, .arg = arg, }; int ret; ret = pthread_mutex_init(&sft.lock, NULL); if (ret) { str_liberror(ctx, ret, _("creating directory scan lock")); return ret; } ret = pthread_cond_init(&sft.wakeup, NULL); if (ret) { str_liberror(ctx, ret, _("creating directory scan signal")); goto out_mutex; } ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, scrub_nproc_workqueue(ctx)); if (ret) { str_liberror(ctx, ret, _("creating directory scan workqueue")); goto out_cond; } ret = queue_subdir(ctx, &sft, &wq, ctx->mntpoint, true); if (ret) { str_liberror(ctx, ret, _("queueing directory scan")); goto out_wq; } /* * Wait for the wakeup to trigger, which should only happen when the * last worker thread decrements nr_dirs to zero. Once the worker * triggers the wakeup and unlocks the sft lock, it's no longer safe * for any worker thread to access sft, as we now own the lock and are * about to tear everything down. */ pthread_mutex_lock(&sft.lock); if (sft.nr_dirs) pthread_cond_wait(&sft.wakeup, &sft.lock); assert(sft.nr_dirs == 0); pthread_mutex_unlock(&sft.lock); ret = -workqueue_terminate(&wq); if (ret) { str_liberror(ctx, ret, _("finishing directory scan work")); goto out_wq; } if (!ret && sft.aborted) ret = -1; out_wq: workqueue_destroy(&wq); out_cond: pthread_cond_destroy(&sft.wakeup); out_mutex: pthread_mutex_destroy(&sft.lock); return ret; } #ifndef FITRIM struct fstrim_range { __u64 start; __u64 len; __u64 minlen; }; #define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */ #endif /* Call FITRIM to trim all the unused space in a filesystem. */ void fstrim( struct scrub_ctx *ctx) { struct fstrim_range range = {0}; int error; range.len = ULLONG_MAX; error = ioctl(ctx->mnt.fd, FITRIM, &range); if (error && errno != EOPNOTSUPP && errno != ENOTTY) perror(_("fstrim")); } xfsprogs-5.3.0/scrub/vfs.h0000644000175000017500000000164613570057155015350 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_VFS_H_ #define XFS_SCRUB_VFS_H_ /* * Visit a subdirectory prior to iterating entries in that subdirectory. * Return 0 to continue iteration or a positive error code to stop iterating * and return to the caller. */ typedef int (*scan_fs_tree_dir_fn)(struct scrub_ctx *, const char *, int, void *); /* * Visit each directory entry in a directory. Return 0 to continue iteration * or a positive error code to stop iterating and return to the caller. */ typedef int (*scan_fs_tree_dirent_fn)(struct scrub_ctx *, const char *, int, struct dirent *, struct stat *, void *); int scan_fs_tree(struct scrub_ctx *ctx, scan_fs_tree_dir_fn dir_fn, scan_fs_tree_dirent_fn dirent_fn, void *arg); void fstrim(struct scrub_ctx *ctx); #endif /* XFS_SCRUB_VFS_H_ */ xfsprogs-5.3.0/scrub/xfs_scrub.c0000644000175000017500000005431313570057155016542 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "xfs.h" #include #include #include #include #include #include #include "platform_defs.h" #include "input.h" #include "libfrog/paths.h" #include "xfs_scrub.h" #include "common.h" #include "descr.h" #include "unicrash.h" #include "progress.h" /* * XFS Online Metadata Scrub (and Repair) * * The XFS scrubber uses custom XFS ioctls to probe more deeply into the * internals of the filesystem. It takes advantage of scrubbing ioctls * to check all the records stored in a metadata object and to * cross-reference those records against the other filesystem metadata. * * After the program gathers command line arguments to figure out * exactly what the program is going to do, scrub execution is split up * into several separate phases: * * The "find geometry" phase queries XFS for the filesystem geometry. * The block devices for the data, realtime, and log devices are opened. * Kernel ioctls are test-queried to see if they actually work (the scrub * ioctl in particular), and any other filesystem-specific information * is gathered. * * In the "check internal metadata" phase, we call the metadata scrub * ioctl to check the filesystem's internal per-AG btrees. This * includes the AG superblock, AGF, AGFL, and AGI headers, freespace * btrees, the regular and free inode btrees, the reverse mapping * btrees, and the reference counting btrees. If the realtime device is * enabled, the realtime bitmap and reverse mapping btrees are checked. * Quotas, if enabled, are also checked in this phase. * * Each AG (and the realtime device) has its metadata checked in a * separate thread for better performance. Errors in the internal * metadata can be fixed here prior to the inode scan; refer to the * section about the "repair filesystem" phase for more information. * * The "scan all inodes" phase uses BULKSTAT to scan all the inodes in * an AG in disk order. The BULKSTAT information provides enough * information to construct a file handle that is used to check the * following parts of every file: * * - The inode record * - All three block forks (data, attr, CoW) * - If it's a symlink, the symlink target. * - If it's a directory, the directory entries. * - All extended attributes * - The parent pointer * * Multiple threads are started to check each the inodes of each AG in * parallel. Errors in file metadata can be fixed here; see the section * about the "repair filesystem" phase for more information. * * Next comes the (configurable) "repair filesystem" phase. The user * can instruct this program to fix all problems encountered; to fix * only optimality problems and leave the corruptions; or not to touch * the filesystem at all. Any metadata repairs that did not succeed in * the previous two phases are retried here; if there are uncorrectable * errors, xfs_scrub stops here. * * To perform the actual repairs (or optimizations), we iterate all the * items on the per-AG action item list and ask the kernel to repair * them. Items which are successfully repaired are removed from the * list. If an item is not acted upon successfully (or the kernel asks us * to try again), we retry the actions until there is nothing left to * fix or we fail to make forward progress. In that event, the * unfinished items are recorded as errors. If there are no errors at * this point, we call FSTRIM on the filesystem. * * The next phase is the "check directory tree" phase. In this phase, * every directory is opened (via file handle) to confirm that each * directory is connected to the root. Directory entries are checked * for ambiguous Unicode normalization mappings, which is to say that we * look for pairs of entries whose utf-8 strings normalize to the same * code point sequence and map to different inodes, because that could * be used to trick a user into opening the wrong file. The names of * extended attributes are checked for Unicode normalization collisions. * * In the "verify data file integrity" phase, we employ GETFSMAP to read * the reverse-mappings of all AGs and issue direct-reads of the * underlying disk blocks. We rely on the underlying storage to have * checksummed the data blocks appropriately. Multiple threads are * started to check each AG in parallel; a separate thread pool is used * to handle the direct reads. * * In the "check summary counters" phase, use GETFSMAP to tally up the * blocks and BULKSTAT to tally up the inodes we saw and compare that to * the statfs output. This gives the user a rough estimate of how * thorough the scrub was. */ /* * Known debug tweaks (pass -d and set the environment variable): * XFS_SCRUB_FORCE_ERROR -- pretend all metadata is corrupt * XFS_SCRUB_FORCE_REPAIR -- repair all metadata even if it's ok * XFS_SCRUB_NO_KERNEL -- pretend there is no kernel ioctl * XFS_SCRUB_NO_SCSI_VERIFY -- disable SCSI VERIFY (if present) * XFS_SCRUB_PHASE -- run only this scrub phase * XFS_SCRUB_THREADS -- start exactly this number of threads * XFS_SCRUB_DISK_ERROR_INTERVAL-- simulate a disk error every this many bytes * XFS_SCRUB_DISK_VERIFY_SKIP -- pretend disk verify read calls succeeded * * Available even in non-debug mode: * SERVICE_MODE -- compress all error codes to 1 for LSB * service action compliance */ /* Program name; needed for libfrog error reports. */ char *progname = "xfs_scrub"; /* Debug level; higher values mean more verbosity. */ unsigned int debug; /* Display resource usage at the end of each phase? */ static bool display_rusage; /* Background mode; higher values insert more pauses between scrub calls. */ unsigned int bg_mode; /* Number of threads we're allowed to use. */ unsigned int force_nr_threads; /* Verbosity; higher values print more information. */ bool verbose; /* Should we scrub the data blocks? */ static bool scrub_data; /* Size of a memory page. */ long page_size; /* Should we FSTRIM after a successful run? */ bool want_fstrim = true; /* If stdout/stderr are ttys, we can use richer terminal control. */ bool stderr_isatty; bool stdout_isatty; /* * If we are running as a service, we need to be careful about what * error codes we return to the calling process. */ bool is_service; #define SCRUB_RET_SUCCESS (0) /* no problems left behind */ #define SCRUB_RET_CORRUPT (1) /* corruption remains on fs */ #define SCRUB_RET_UNOPTIMIZED (2) /* fs could be optimized */ #define SCRUB_RET_OPERROR (4) /* operational problems */ #define SCRUB_RET_SYNTAX (8) /* cmdline args rejected */ static void __attribute__((noreturn)) usage(void) { fprintf(stderr, _("Usage: %s [OPTIONS] mountpoint\n"), progname); fprintf(stderr, "\n"); fprintf(stderr, _("Options:\n")); fprintf(stderr, _(" -a count Stop after this many errors are found.\n")); fprintf(stderr, _(" -b Background mode.\n")); fprintf(stderr, _(" -C fd Print progress information to this fd.\n")); fprintf(stderr, _(" -e behavior What to do if errors are found.\n")); fprintf(stderr, _(" -k Do not FITRIM the free space.\n")); fprintf(stderr, _(" -m path Path to /etc/mtab.\n")); fprintf(stderr, _(" -n Dry run. Do not modify anything.\n")); fprintf(stderr, _(" -T Display timing/usage information.\n")); fprintf(stderr, _(" -v Verbose output.\n")); fprintf(stderr, _(" -V Print version.\n")); fprintf(stderr, _(" -x Scrub file data too.\n")); exit(SCRUB_RET_SYNTAX); } #ifndef RUSAGE_BOTH # define RUSAGE_BOTH (-2) #endif /* Get resource usage for ourselves and all children. */ static int scrub_getrusage( struct rusage *usage) { struct rusage cusage; int err; err = getrusage(RUSAGE_BOTH, usage); if (!err) return err; err = getrusage(RUSAGE_SELF, usage); if (err) return err; err = getrusage(RUSAGE_CHILDREN, &cusage); if (err) return err; usage->ru_minflt += cusage.ru_minflt; usage->ru_majflt += cusage.ru_majflt; usage->ru_nswap += cusage.ru_nswap; usage->ru_inblock += cusage.ru_inblock; usage->ru_oublock += cusage.ru_oublock; usage->ru_msgsnd += cusage.ru_msgsnd; usage->ru_msgrcv += cusage.ru_msgrcv; usage->ru_nsignals += cusage.ru_nsignals; usage->ru_nvcsw += cusage.ru_nvcsw; usage->ru_nivcsw += cusage.ru_nivcsw; return 0; } /* * Scrub Phase Dispatch * * The operations of the scrub program are split up into several * different phases. Each phase builds upon the metadata checked in the * previous phase, which is to say that we may skip phase (X + 1) if our * scans in phase (X) reveal corruption. A phase may be skipped * entirely. */ /* Resource usage for each phase. */ struct phase_rusage { struct rusage ruse; struct timeval time; unsigned long long verified_bytes; void *brk_start; const char *descr; }; /* Operations for each phase. */ #define DATASCAN_DUMMY_FN ((void *)1) #define REPAIR_DUMMY_FN ((void *)2) struct phase_ops { char *descr; int (*fn)(struct scrub_ctx *ctx); int (*estimate_work)(struct scrub_ctx *ctx, uint64_t *items, unsigned int *threads, int *rshift); bool must_run; }; /* Start tracking resource usage for a phase. */ static int phase_start( struct phase_rusage *pi, unsigned int phase, const char *descr) { int error; memset(pi, 0, sizeof(*pi)); error = scrub_getrusage(&pi->ruse); if (error) { perror(_("getrusage")); return error; } pi->brk_start = sbrk(0); error = gettimeofday(&pi->time, NULL); if (error) { perror(_("gettimeofday")); return error; } pi->descr = descr; if ((verbose || display_rusage) && descr) { fprintf(stdout, _("Phase %u: %s\n"), phase, descr); fflush(stdout); } return error; } /* Report usage stats. */ static int phase_end( struct phase_rusage *pi, unsigned int phase) { struct rusage ruse_now; #ifdef HAVE_MALLINFO struct mallinfo mall_now; #endif struct timeval time_now; char phasebuf[DESCR_BUFSZ]; double dt; unsigned long long in, out; unsigned long long io; double i, o, t; double din, dout, dtot; char *iu, *ou, *tu, *dinu, *doutu, *dtotu; int error; if (!display_rusage) return 0; error = gettimeofday(&time_now, NULL); if (error) { perror(_("gettimeofday")); return error; } dt = timeval_subtract(&time_now, &pi->time); error = scrub_getrusage(&ruse_now); if (error) { perror(_("getrusage")); return error; } if (phase) snprintf(phasebuf, DESCR_BUFSZ, _("Phase %u: "), phase); else phasebuf[0] = 0; #define kbytes(x) (((unsigned long)(x) + 1023) / 1024) #ifdef HAVE_MALLINFO mall_now = mallinfo(); fprintf(stdout, _("%sMemory used: %luk/%luk (%luk/%luk), "), phasebuf, kbytes(mall_now.arena), kbytes(mall_now.hblkhd), kbytes(mall_now.uordblks), kbytes(mall_now.fordblks)); #else fprintf(stdout, _("%sMemory used: %luk, "), phasebuf, (unsigned long) kbytes(((char *) sbrk(0)) - ((char *) pi->brk_start))); #endif #undef kbytes fprintf(stdout, _("time: %5.2f/%5.2f/%5.2fs\n"), timeval_subtract(&time_now, &pi->time), timeval_subtract(&ruse_now.ru_utime, &pi->ruse.ru_utime), timeval_subtract(&ruse_now.ru_stime, &pi->ruse.ru_stime)); /* I/O usage */ in = ((unsigned long long)ruse_now.ru_inblock - pi->ruse.ru_inblock) << BBSHIFT; out = ((unsigned long long)ruse_now.ru_oublock - pi->ruse.ru_oublock) << BBSHIFT; io = in + out; if (io) { i = auto_space_units(in, &iu); o = auto_space_units(out, &ou); t = auto_space_units(io, &tu); din = auto_space_units(in / dt, &dinu); dout = auto_space_units(out / dt, &doutu); dtot = auto_space_units(io / dt, &dtotu); fprintf(stdout, _("%sI/O: %.1f%s in, %.1f%s out, %.1f%s tot\n"), phasebuf, i, iu, o, ou, t, tu); fprintf(stdout, _("%sI/O rate: %.1f%s/s in, %.1f%s/s out, %.1f%s/s tot\n"), phasebuf, din, dinu, dout, doutu, dtot, dtotu); } fflush(stdout); return 0; } /* Run all the phases of the scrubber. */ static bool run_scrub_phases( struct scrub_ctx *ctx, FILE *progress_fp) { struct phase_ops phases[] = { { .descr = _("Find filesystem geometry."), .fn = phase1_func, .must_run = true, }, { .descr = _("Check internal metadata."), .fn = phase2_func, .estimate_work = phase2_estimate, }, { .descr = _("Scan all inodes."), .fn = phase3_func, .estimate_work = phase3_estimate, }, { .descr = _("Defer filesystem repairs."), .fn = REPAIR_DUMMY_FN, .estimate_work = phase4_estimate, }, { .descr = _("Check directory tree."), .fn = phase5_func, .estimate_work = phase5_estimate, }, { .descr = _("Verify data file integrity."), .fn = DATASCAN_DUMMY_FN, .estimate_work = phase6_estimate, }, { .descr = _("Check summary counters."), .fn = phase7_func, .must_run = true, }, { NULL }, }; struct phase_rusage pi; struct phase_ops *sp; uint64_t max_work; unsigned int debug_phase = 0; unsigned int phase; int rshift; int ret = 0; if (debug_tweak_on("XFS_SCRUB_PHASE")) debug_phase = atoi(getenv("XFS_SCRUB_PHASE")); /* Run all phases of the scrub tool. */ for (phase = 1, sp = phases; sp->fn; sp++, phase++) { /* Turn on certain phases if user said to. */ if (sp->fn == DATASCAN_DUMMY_FN && scrub_data) { sp->fn = phase6_func; } else if (sp->fn == REPAIR_DUMMY_FN && ctx->mode == SCRUB_MODE_REPAIR) { sp->descr = _("Repair filesystem."); sp->fn = phase4_func; sp->must_run = true; } /* Skip certain phases unless they're turned on. */ if (sp->fn == REPAIR_DUMMY_FN || sp->fn == DATASCAN_DUMMY_FN) continue; /* Allow debug users to force a particular phase. */ if (debug_phase && phase != debug_phase && !sp->must_run) continue; /* Run this phase. */ ret = phase_start(&pi, phase, sp->descr); if (ret) break; if (sp->estimate_work) { unsigned int work_threads; ret = sp->estimate_work(ctx, &max_work, &work_threads, &rshift); if (ret) break; /* * The thread that starts the worker threads is also * allowed to contribute to the progress counters and * whatever other per-thread data we need to allocate. */ work_threads++; ret = progress_init_phase(ctx, progress_fp, phase, max_work, rshift, work_threads); if (ret) break; ret = descr_init_phase(ctx, work_threads); } else { ret = progress_init_phase(ctx, NULL, phase, 0, 0, 0); if (ret) break; ret = descr_init_phase(ctx, 1); } if (ret) break; ret = sp->fn(ctx); if (ret) { str_info(ctx, ctx->mntpoint, _("Scrub aborted after phase %d."), phase); break; } progress_end_phase(); descr_end_phase(); ret = phase_end(&pi, phase); if (ret) break; /* Too many errors? */ if (xfs_scrub_excessive_errors(ctx)) { ret = ECANCELED; break; } } return ret; } static void report_modifications( struct scrub_ctx *ctx) { if (ctx->repairs == 0 && ctx->preens == 0) return; if (ctx->repairs && ctx->preens) fprintf(stdout, _("%s: repairs made: %llu; optimizations made: %llu.\n"), ctx->mntpoint, ctx->repairs, ctx->preens); else if (ctx->preens == 0) fprintf(stdout, _("%s: repairs made: %llu.\n"), ctx->mntpoint, ctx->repairs); else if (ctx->repairs == 0) fprintf(stdout, _("%s: optimizations made: %llu.\n"), ctx->mntpoint, ctx->preens); } static void report_outcome( struct scrub_ctx *ctx) { unsigned long long actionable_errors; actionable_errors = ctx->corruptions_found + ctx->runtime_errors; if (actionable_errors == 0 && ctx->unfixable_errors == 0 && ctx->warnings_found == 0) { log_info(ctx, _("No problems found.")); return; } if (ctx->unfixable_errors) { fprintf(stderr, _("%s: unfixable errors found: %llu\n"), ctx->mntpoint, ctx->unfixable_errors); log_err(ctx, _("unfixable errors found: %llu"), ctx->unfixable_errors); } if (ctx->corruptions_found > 0) { fprintf(stderr, _("%s: corruptions found: %llu\n"), ctx->mntpoint, ctx->corruptions_found); log_err(ctx, _("corruptions found: %llu"), ctx->corruptions_found); } if (ctx->runtime_errors > 0) { fprintf(stderr, _("%s: operational errors found: %llu\n"), ctx->mntpoint, ctx->runtime_errors); log_err(ctx, _("operational errors found: %llu"), ctx->runtime_errors); } if (ctx->warnings_found > 0) { fprintf(stderr, _("%s: warnings found: %llu\n"), ctx->mntpoint, ctx->warnings_found); log_warn(ctx, _("warnings found: %llu"), ctx->warnings_found); } /* * Don't advise the user to run repair unless we were successful in * setting up the scrub and we actually saw corruptions. Warnings * are not corruptions. */ if (ctx->scrub_setup_succeeded && actionable_errors > 0) { char *msg; if (ctx->mode == SCRUB_MODE_DRY_RUN) msg = _("%s: Re-run xfs_scrub without -n.\n"); else msg = _("%s: Unmount and run xfs_repair.\n"); fprintf(stderr, msg, ctx->mntpoint); } } int main( int argc, char **argv) { struct scrub_ctx ctx = {0}; struct phase_rusage all_pi; char *mtab = NULL; FILE *progress_fp = NULL; struct fs_path *fsp; int c; int fd; int ret = SCRUB_RET_SUCCESS; int error; fprintf(stdout, "EXPERIMENTAL xfs_scrub program in use! Use at your own risk!\n"); progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); pthread_mutex_init(&ctx.lock, NULL); ctx.mode = SCRUB_MODE_REPAIR; ctx.error_action = ERRORS_CONTINUE; while ((c = getopt(argc, argv, "a:bC:de:km:nTvxV")) != EOF) { switch (c) { case 'a': ctx.max_errors = cvt_u64(optarg, 10); if (errno) { perror(optarg); usage(); } break; case 'b': force_nr_threads = 1; bg_mode++; break; case 'C': errno = 0; fd = cvt_u32(optarg, 10); if (errno) { perror(optarg); usage(); } progress_fp = fdopen(fd, "w"); if (!progress_fp) { perror(optarg); usage(); } break; case 'd': debug++; break; case 'e': if (!strcmp("continue", optarg)) ctx.error_action = ERRORS_CONTINUE; else if (!strcmp("shutdown", optarg)) ctx.error_action = ERRORS_SHUTDOWN; else { fprintf(stderr, _("Unknown error behavior \"%s\".\n"), optarg); usage(); } break; case 'k': want_fstrim = false; break; case 'm': mtab = optarg; break; case 'n': ctx.mode = SCRUB_MODE_DRY_RUN; break; case 'T': display_rusage = true; break; case 'v': verbose = true; break; case 'V': fprintf(stdout, _("%s version %s\n"), progname, VERSION); fflush(stdout); return SCRUB_RET_SUCCESS; case 'x': scrub_data = true; break; case '?': /* fall through */ default: usage(); } } /* Override thread count if debugger */ if (debug_tweak_on("XFS_SCRUB_THREADS")) { unsigned int x; x = cvt_u32(getenv("XFS_SCRUB_THREADS"), 10); if (errno) { perror("nr_threads"); usage(); } force_nr_threads = x; } if (optind != argc - 1) usage(); ctx.mntpoint = argv[optind]; stdout_isatty = isatty(STDOUT_FILENO); stderr_isatty = isatty(STDERR_FILENO); /* If interactive, start the progress bar. */ if (stdout_isatty && !progress_fp) progress_fp = fdopen(1, "w+"); if (getenv("SERVICE_MODE")) is_service = true; /* Initialize overall phase stats. */ error = phase_start(&all_pi, 0, NULL); if (error) return SCRUB_RET_OPERROR; /* Find the mount record for the passed-in argument. */ if (stat(argv[optind], &ctx.mnt_sb) < 0) { fprintf(stderr, _("%s: could not stat: %s: %s\n"), progname, argv[optind], strerror(errno)); ctx.runtime_errors++; goto out; } /* * If the user did not specify an explicit mount table, try to use * /proc/mounts if it is available, else /etc/mtab. We prefer * /proc/mounts because it is kernel controlled, while /etc/mtab * may contain garbage that userspace tools like pam_mounts wrote * into it. */ if (!mtab) { if (access(_PATH_PROC_MOUNTS, R_OK) == 0) mtab = _PATH_PROC_MOUNTS; else mtab = _PATH_MOUNTED; } fs_table_initialise(0, NULL, 0, NULL); fsp = fs_table_lookup_mount(ctx.mntpoint); if (!fsp) { fprintf(stderr, _("%s: Not a XFS mount point.\n"), ctx.mntpoint); ret |= SCRUB_RET_SYNTAX; goto out; } memcpy(&ctx.fsinfo, fsp, sizeof(struct fs_path)); /* Set up a page-aligned buffer for read verification. */ page_size = sysconf(_SC_PAGESIZE); if (page_size < 0) { str_errno(&ctx, ctx.mntpoint); goto out; } if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) ctx.mode = SCRUB_MODE_REPAIR; /* Scrub a filesystem. */ error = run_scrub_phases(&ctx, progress_fp); if (error && ctx.runtime_errors == 0) ctx.runtime_errors++; /* * Excessive errors will cause the scrub phases to bail out early. * We don't want every thread yelling that into the output, so check * if we hit the threshold and tell the user *once*. */ if (xfs_scrub_excessive_errors(&ctx)) str_info(&ctx, ctx.mntpoint, _("Too many errors; aborting.")); if (debug_tweak_on("XFS_SCRUB_FORCE_ERROR")) str_info(&ctx, ctx.mntpoint, _("Injecting error.")); /* Clean up scan data. */ error = scrub_cleanup(&ctx); if (error && ctx.runtime_errors == 0) ctx.runtime_errors++; out: report_modifications(&ctx); report_outcome(&ctx); if (ctx.corruptions_found) { if (ctx.error_action == ERRORS_SHUTDOWN) xfs_shutdown_fs(&ctx); ret |= SCRUB_RET_CORRUPT; } if (ctx.warnings_found) ret |= SCRUB_RET_UNOPTIMIZED; if (ctx.runtime_errors) ret |= SCRUB_RET_OPERROR; phase_end(&all_pi, 0); if (progress_fp) fclose(progress_fp); /* * If we're being run as a service, the return code must fit the LSB * init script action error guidelines, which is to say that we * compress all errors to 1 ("generic or unspecified error", LSB 5.0 * section 22.2) and hope the admin will scan the log for what * actually happened. * * We have to sleep 2 seconds here because journald uses the pid to * connect our log messages to the systemd service. This is critical * for capturing all the log messages if the scrub fails, because the * fail service uses the service name to gather log messages for the * error report. * * Note: We don't count a lack of kernel support as a service failure * because we haven't determined that there's anything wrong with the * filesystem. */ if (is_service) { sleep(2); if (!ctx.scrub_setup_succeeded) return 0; if (ret != SCRUB_RET_SUCCESS) return 1; } return ret; } xfsprogs-5.3.0/scrub/xfs_scrub.h0000644000175000017500000000571713570057155016553 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef XFS_SCRUB_XFS_SCRUB_H_ #define XFS_SCRUB_XFS_SCRUB_H_ #include "libfrog/fsgeom.h" extern char *progname; #define _PATH_PROC_MOUNTS "/proc/mounts" extern unsigned int force_nr_threads; extern unsigned int bg_mode; extern unsigned int debug; extern bool verbose; extern long page_size; extern bool want_fstrim; extern bool stderr_isatty; extern bool stdout_isatty; extern bool is_service; enum scrub_mode { SCRUB_MODE_DRY_RUN, SCRUB_MODE_REPAIR, }; enum error_action { ERRORS_CONTINUE, ERRORS_SHUTDOWN, }; struct scrub_ctx { /* Immutable scrub state. */ /* Strings we need for presentation */ char *mntpoint; /* Mountpoint info */ struct stat mnt_sb; struct statvfs mnt_sv; struct statfs mnt_sf; /* Open block devices */ struct disk *datadev; struct disk *logdev; struct disk *rtdev; /* What does the user want us to do? */ enum scrub_mode mode; /* How does the user want us to react to errors? */ enum error_action error_action; /* xfrog context for the mount point */ struct xfs_fd mnt; /* Number of threads for metadata scrubbing */ unsigned int nr_io_threads; /* XFS specific geometry */ struct fs_path fsinfo; void *fshandle; size_t fshandle_len; /* Data block read verification buffer */ void *readbuf; /* Mutable scrub state; use lock. */ pthread_mutex_t lock; struct action_list *action_lists; unsigned long long max_errors; unsigned long long runtime_errors; unsigned long long corruptions_found; unsigned long long unfixable_errors; unsigned long long warnings_found; unsigned long long inodes_checked; unsigned long long bytes_checked; unsigned long long naming_warnings; unsigned long long repairs; unsigned long long preens; bool scrub_setup_succeeded; bool preen_triggers[XFS_SCRUB_TYPE_NR]; }; /* Phase helper functions */ void xfs_shutdown_fs(struct scrub_ctx *ctx); int scrub_cleanup(struct scrub_ctx *ctx); int phase1_func(struct scrub_ctx *ctx); int phase2_func(struct scrub_ctx *ctx); int phase3_func(struct scrub_ctx *ctx); int phase4_func(struct scrub_ctx *ctx); int phase5_func(struct scrub_ctx *ctx); int phase6_func(struct scrub_ctx *ctx); int phase7_func(struct scrub_ctx *ctx); /* Progress estimator functions */ unsigned int scrub_estimate_ag_work(struct scrub_ctx *ctx); int phase2_estimate(struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift); int phase3_estimate(struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift); int phase4_estimate(struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift); int phase5_estimate(struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift); int phase6_estimate(struct scrub_ctx *ctx, uint64_t *items, unsigned int *nr_threads, int *rshift); #endif /* XFS_SCRUB_XFS_SCRUB_H_ */ xfsprogs-5.3.0/scrub/xfs_scrub@.service.in0000644000175000017500000000107013435336037020454 0ustar nathansnathans[Unit] Description=Online XFS Metadata Check for %I OnFailure=xfs_scrub_fail@%i.service Documentation=man:xfs_scrub(8) [Service] Type=oneshot WorkingDirectory=%I PrivateNetwork=true ProtectSystem=full ProtectHome=read-only # Disable private /tmp just in case %i is a path under /tmp. PrivateTmp=no AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_SYS_RAWIO NoNewPrivileges=yes User=nobody IOSchedulingClass=idle CPUSchedulingPolicy=idle Environment=SERVICE_MODE=1 ExecStart=@sbindir@/xfs_scrub @scrub_args@ %I SyslogIdentifier=%N xfsprogs-5.3.0/scrub/xfs_scrub_all.cron.in0000644000175000017500000000010713242461543020502 0ustar nathansnathans10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all xfsprogs-5.3.0/scrub/xfs_scrub_all.in0000644000175000017500000001360413466663244017562 0ustar nathansnathans#!/usr/bin/python3 # SPDX-License-Identifier: GPL-2.0+ # Copyright (C) 2018 Oracle. All rights reserved. # # Author: Darrick J. Wong # Run online scrubbers in parallel, but avoid thrashing. import subprocess import json import threading import time import sys import os import argparse retcode = 0 terminate = False def DEVNULL(): '''Return /dev/null in subprocess writable format.''' try: from subprocess import DEVNULL return DEVNULL except ImportError: return open(os.devnull, 'wb') def find_mounts(): '''Map mountpoints to physical disks.''' def find_xfs_mounts(bdev, fs, lastdisk): '''Attach lastdisk to each fs found under bdev.''' if bdev['fstype'] == 'xfs' and bdev['mountpoint'] is not None: mnt = bdev['mountpoint'] if mnt in fs: fs[mnt].add(lastdisk) else: fs[mnt] = set([lastdisk]) if 'children' not in bdev: return for child in bdev['children']: find_xfs_mounts(child, fs, lastdisk) fs = {} cmd=['lsblk', '-o', 'NAME,KNAME,TYPE,FSTYPE,MOUNTPOINT', '-J'] result = subprocess.Popen(cmd, stdout=subprocess.PIPE) result.wait() if result.returncode != 0: return fs sarray = [x.decode(sys.stdout.encoding) for x in result.stdout.readlines()] output = ' '.join(sarray) bdevdata = json.loads(output) # The lsblk output had better be in disks-then-partitions order for bdev in bdevdata['blockdevices']: lastdisk = bdev['kname'] find_xfs_mounts(bdev, fs, lastdisk) return fs def kill_systemd(unit, proc): '''Kill systemd unit.''' proc.terminate() cmd=['systemctl', 'stop', unit] x = subprocess.Popen(cmd) x.wait() def run_killable(cmd, stdout, killfuncs, kill_fn): '''Run a killable program. Returns program retcode or -1 if we can't start it.''' try: proc = subprocess.Popen(cmd, stdout = stdout) real_kill_fn = lambda: kill_fn(proc) killfuncs.add(real_kill_fn) proc.wait() try: killfuncs.remove(real_kill_fn) except: pass return proc.returncode except: return -1 # systemd doesn't like unit instance names with slashes in them, so it # replaces them with dashes when it invokes the service. However, it's not # smart enough to convert the dashes to something else, so when it unescapes # the instance name to feed to xfs_scrub, it turns all dashes into slashes. # "/moo-cow" becomes "-moo-cow" becomes "/moo/cow", which is wrong. systemd # actually /can/ escape the dashes correctly if it is told that this is a path # (and not a unit name), but it didn't do this prior to January 2017, so fix # this for them. # # systemd path escaping also drops the initial slash so we add that back in so # that log messages from the service units preserve the full path and users can # look up log messages using full paths. However, for "/" the escaping rules # do /not/ drop the initial slash, so we have to special-case that here. def systemd_escape(path): '''Escape a path to avoid mangled systemd mangling.''' if path == '/': return '-' cmd = ['systemd-escape', '--path', path] try: proc = subprocess.Popen(cmd, stdout = subprocess.PIPE) proc.wait() for line in proc.stdout: return '-' + line.decode(sys.stdout.encoding).strip() except: return path def run_scrub(mnt, cond, running_devs, mntdevs, killfuncs): '''Run a scrub process.''' global retcode, terminate print("Scrubbing %s..." % mnt) sys.stdout.flush() try: if terminate: return # Try it the systemd way cmd=['systemctl', 'start', 'xfs_scrub@%s' % systemd_escape(mnt)] ret = run_killable(cmd, DEVNULL(), killfuncs, \ lambda proc: kill_systemd('xfs_scrub@%s' % mnt, proc)) if ret == 0 or ret == 1: print("Scrubbing %s done, (err=%d)" % (mnt, ret)) sys.stdout.flush() retcode |= ret return if terminate: return # Invoke xfs_scrub manually cmd=['@sbindir@/xfs_scrub', '@scrub_args@', mnt] ret = run_killable(cmd, None, killfuncs, \ lambda proc: proc.terminate()) if ret >= 0: print("Scrubbing %s done, (err=%d)" % (mnt, ret)) sys.stdout.flush() retcode |= ret return if terminate: return print("Unable to start scrub tool.") sys.stdout.flush() finally: running_devs -= mntdevs cond.acquire() cond.notify() cond.release() def main(): '''Find mounts, schedule scrub runs.''' def thr(mnt, devs): a = (mnt, cond, running_devs, devs, killfuncs) thr = threading.Thread(target = run_scrub, args = a) thr.start() global retcode, terminate parser = argparse.ArgumentParser( \ description = "Scrub all mounted XFS filesystems.") parser.add_argument("-V", help = "Report version and exit.", \ action = "store_true") args = parser.parse_args() if args.V: print("xfs_scrub_all version @pkg_version@") sys.exit(0) fs = find_mounts() # Tail the journal if we ourselves aren't a service... journalthread = None if 'SERVICE_MODE' not in os.environ: try: cmd=['journalctl', '--no-pager', '-q', '-S', 'now', \ '-f', '-u', 'xfs_scrub@*', '-o', \ 'cat'] journalthread = subprocess.Popen(cmd) except: pass # Schedule scrub jobs... running_devs = set() killfuncs = set() cond = threading.Condition() while len(fs) > 0: if len(running_devs) == 0: mnt, devs = fs.popitem() running_devs.update(devs) thr(mnt, devs) poppers = set() for mnt in fs: devs = fs[mnt] can_run = True for dev in devs: if dev in running_devs: can_run = False break if can_run: running_devs.update(devs) poppers.add(mnt) thr(mnt, devs) for p in poppers: fs.pop(p) cond.acquire() try: cond.wait() except KeyboardInterrupt: terminate = True print("Terminating...") sys.stdout.flush() while len(killfuncs) > 0: fn = killfuncs.pop() fn() fs = [] cond.release() if journalthread is not None: journalthread.terminate() # See the service mode comments in xfs_scrub.c for why we do this. if 'SERVICE_MODE' in os.environ: time.sleep(2) if retcode != 0: retcode = 1 sys.exit(retcode) if __name__ == '__main__': main() xfsprogs-5.3.0/scrub/xfs_scrub_all.service.in0000644000175000017500000000057013466663244021217 0ustar nathansnathans[Unit] Description=Online XFS Metadata Check for All Filesystems ConditionACPower=true Documentation=man:xfs_scrub_all(8) After=paths.target multi-user.target network.target network-online.target systemd-networkd.service NetworkManager.service connman.service [Service] Type=oneshot Environment=SERVICE_MODE=1 ExecStart=@sbindir@/xfs_scrub_all SyslogIdentifier=xfs_scrub_all xfsprogs-5.3.0/scrub/xfs_scrub_all.timer0000644000175000017500000000037213242461543020260 0ustar nathansnathans[Unit] Description=Periodic XFS Online Metadata Check for All Filesystems [Timer] # Run on Sunday at 3:10am, to avoid running afoul of DST changes OnCalendar=Sun *-*-* 03:10:00 RandomizedDelaySec=60 Persistent=true [Install] WantedBy=timers.target xfsprogs-5.3.0/scrub/xfs_scrub_fail0000755000175000017500000000120113242461543017277 0ustar nathansnathans#!/bin/bash # Email logs of failed xfs_scrub unit runs mailer=/usr/sbin/sendmail recipient="$1" test -z "${recipient}" && exit 0 mntpoint="$2" test -z "${mntpoint}" && exit 0 hostname="$(hostname -f 2>/dev/null)" test -z "${hostname}" && hostname="${HOSTNAME}" if [ ! -x "${mailer}" ]; then echo "${mailer}: Mailer program not found." exit 1 fi (cat << ENDL To: $1 From: Subject: xfs_scrub failure on ${mntpoint} So sorry, the automatic xfs_scrub of ${mntpoint} on ${hostname} failed. A log of what happened follows: ENDL systemctl status --full --lines 4294967295 "xfs_scrub@${mntpoint}") | "${mailer}" -t -i xfsprogs-5.3.0/scrub/xfs_scrub_fail@.service.in0000644000175000017500000000042713245074644021456 0ustar nathansnathans[Unit] Description=Online XFS Metadata Check Failure Reporting for %I Documentation=man:xfs_scrub(8) [Service] Type=oneshot Environment=EMAIL_ADDR=root ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" %I User=mail Group=mail SupplementaryGroups=systemd-journal xfsprogs-5.3.0/spaceman/Makefile0000644000175000017500000000170713570057155016510 0ustar nathansnathans# SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2012 Red Hat, Inc. All Rights Reserved. # TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_spaceman HFILES = init.h space.h CFILES = info.c init.c file.c health.c prealloc.c trim.c LSRCFILES = xfs_info.sh LLDLIBS = $(LIBXCMD) $(LIBFROG) LTDEPENDENCIES = $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static ifeq ($(ENABLE_READLINE),yes) LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP) endif ifeq ($(ENABLE_EDITLINE),yes) LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP) endif # On linux we get fsmap from the system or define it ourselves # so include this unconditionally. If this reverts to only # the autoconf check w/o local definition, test HAVE_GETFSMAP CFILES += freesp.c default: depend $(LTCOMMAND) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) $(INSTALL) -m 755 xfs_info.sh $(PKG_SBIN_DIR)/xfs_info install-dev: -include .dep xfsprogs-5.3.0/spaceman/file.c0000644000175000017500000000434513570057155016134 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004-2005 Silicon Graphics, Inc. * Copyright (c) 2012 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs.h" #include #include "command.h" #include "input.h" #include "init.h" #include "libfrog/logging.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "space.h" static cmdinfo_t print_cmd; struct fileio *filetable; int filecount; struct fileio *file; static void print_fileio( struct fileio *file, int index, int braces) { printf(_("%c%03d%c %-14s\n"), braces? '[' : ' ', index, braces? ']' : ' ', file->name); } static int print_f( int argc, char **argv) { int i; for (i = 0; i < filecount; i++) print_fileio(&filetable[i], i, &filetable[i] == file); return 0; } int openfile( char *path, struct xfs_fd *xfd, struct fs_path *fs_path) { struct fs_path *fsp; int ret; ret = -xfd_open(xfd, path, O_RDONLY); if (ret) { if (ret == ENOTTY) fprintf(stderr, _("%s: Not on a mounted XFS filesystem.\n"), path); else xfrog_perror(ret, path); return -1; } fsp = fs_table_lookup(path, FS_MOUNT_POINT); if (!fsp) { fprintf(stderr, _("%s: cannot find mount point."), path); xfd_close(xfd); return -1; } memcpy(fs_path, fsp, sizeof(struct fs_path)); return xfd->fd; } int addfile( char *name, struct xfs_fd *xfd, struct fs_path *fs_path) { char *filename; filename = strdup(name); if (!filename) { perror("strdup"); xfd_close(xfd); return -1; } /* Extend the table of currently open files */ filetable = (struct fileio *)realloc(filetable, /* growing */ ++filecount * sizeof(struct fileio)); if (!filetable) { perror("realloc"); filecount = 0; free(filename); xfd_close(xfd); return -1; } /* Finally, make this the new active open file */ file = &filetable[filecount - 1]; file->name = filename; memcpy(&file->xfd, xfd, sizeof(struct xfs_fd)); memcpy(&file->fs_path, fs_path, sizeof(file->fs_path)); return 0; } void print_init(void) { print_cmd.name = "print"; print_cmd.altname = "p"; print_cmd.cfunc = print_f; print_cmd.argmin = 0; print_cmd.argmax = 0; print_cmd.flags = CMD_FLAG_ONESHOT; print_cmd.oneline = _("list current open files"); add_command(&print_cmd); } xfsprogs-5.3.0/spaceman/freesp.c0000644000175000017500000001770413570057155016504 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * Copyright (c) 2012 Red Hat, Inc. * Copyright (c) 2017 Oracle. * All Rights Reserved. */ #include "libxfs.h" #include #include "libfrog/fsgeom.h" #include "command.h" #include "init.h" #include "libfrog/paths.h" #include "space.h" #include "input.h" struct histent { long long low; long long high; long long count; long long blocks; }; static int agcount; static xfs_agnumber_t *aglist; static struct histent *hist; static int dumpflag; static long long equalsize; static long long multsize; static int histcount; static int seen1; static int summaryflag; static int gflag; static bool rtflag; static long long totblocks; static long long totexts; static cmdinfo_t freesp_cmd; static void addhistent( long long h) { if (histcount == INT_MAX) { printf(_("Too many histogram buckets.\n")); return; } hist = realloc(hist, (histcount + 1) * sizeof(*hist)); if (h == 0) h = 1; hist[histcount].low = h; hist[histcount].count = hist[histcount].blocks = 0; histcount++; if (h == 1) seen1 = 1; } static void addtohist( xfs_agnumber_t agno, xfs_agblock_t agbno, off64_t len) { long i; if (dumpflag) printf("%8d %8d %8"PRId64"\n", agno, agbno, len); totexts++; totblocks += len; for (i = 0; i < histcount; i++) { if (hist[i].high >= len) { hist[i].count++; hist[i].blocks += len; break; } } } static int hcmp( const void *a, const void *b) { return ((struct histent *)a)->low - ((struct histent *)b)->low; } static void histinit( long long maxlen) { long long i; if (equalsize) { for (i = 1; i < maxlen; i += equalsize) addhistent(i); } else if (multsize) { for (i = 1; i < maxlen; i *= multsize) addhistent(i); } else { if (!seen1) addhistent(1); qsort(hist, histcount, sizeof(*hist), hcmp); } for (i = 0; i < histcount; i++) { if (i < histcount - 1) hist[i].high = hist[i + 1].low - 1; else hist[i].high = maxlen; } } static void printhist(void) { int i; printf("%7s %7s %7s %7s %6s\n", _("from"), _("to"), _("extents"), _("blocks"), _("pct")); for (i = 0; i < histcount; i++) { if (hist[i].count) printf("%7lld %7lld %7lld %7lld %6.2f\n", hist[i].low, hist[i].high, hist[i].count, hist[i].blocks, hist[i].blocks * 100.0 / totblocks); } } static int inaglist( xfs_agnumber_t agno) { int i; if (agcount == 0) return 1; for (i = 0; i < agcount; i++) if (aglist[i] == agno) return 1; return 0; } #define NR_EXTENTS 128 static void scan_ag( xfs_agnumber_t agno) { struct fsmap_head *fsmap; struct fsmap *extent; struct fsmap *l, *h; struct fsmap *p; struct xfs_fd *xfd = &file->xfd; off64_t aglen; xfs_agblock_t agbno; unsigned long long freeblks = 0; unsigned long long freeexts = 0; int ret; int i; fsmap = malloc(fsmap_sizeof(NR_EXTENTS)); if (!fsmap) { fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname); exitcode = 1; return; } memset(fsmap, 0, sizeof(*fsmap)); fsmap->fmh_count = NR_EXTENTS; l = fsmap->fmh_keys; h = fsmap->fmh_keys + 1; if (agno != NULLAGNUMBER) { l->fmr_physical = cvt_agbno_to_b(xfd, agno, 0); h->fmr_physical = cvt_agbno_to_b(xfd, agno + 1, 0); l->fmr_device = h->fmr_device = file->fs_path.fs_datadev; } else { l->fmr_physical = 0; h->fmr_physical = ULLONG_MAX; l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev; } h->fmr_owner = ULLONG_MAX; h->fmr_flags = UINT_MAX; h->fmr_offset = ULLONG_MAX; while (true) { ret = ioctl(file->xfd.fd, FS_IOC_GETFSMAP, fsmap); if (ret < 0) { fprintf(stderr, _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"), progname, file->name, strerror(errno)); free(fsmap); exitcode = 1; return; } /* No more extents to map, exit */ if (!fsmap->fmh_entries) break; for (i = 0, extent = fsmap->fmh_recs; i < fsmap->fmh_entries; i++, extent++) { if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) || extent->fmr_owner != XFS_FMR_OWN_FREE) continue; agbno = cvt_b_to_agbno(xfd, extent->fmr_physical); aglen = cvt_b_to_off_fsbt(xfd, extent->fmr_length); freeblks += aglen; freeexts++; addtohist(agno, agbno, aglen); } p = &fsmap->fmh_recs[fsmap->fmh_entries - 1]; if (p->fmr_flags & FMR_OF_LAST) break; fsmap_advance(fsmap); } if (gflag) { if (agno == NULLAGNUMBER) printf(_(" rtdev %10llu %10llu\n"), freeexts, freeblks); else printf(_("%10u %10llu %10llu\n"), agno, freeexts, freeblks); } free(fsmap); } static void aglistadd( char *a) { xfs_agnumber_t x; aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist)); x = cvt_u32(a, 0); if (errno) { printf(_("Unrecognized AG number: %s\n"), a); return; } aglist[agcount] = x; agcount++; } static int init( int argc, char **argv) { struct xfs_fsop_geom *fsgeom = &file->xfd.fsgeom; long long x; int c; int speced = 0; /* only one of -b -e -h or -m */ agcount = dumpflag = equalsize = multsize = optind = gflag = 0; histcount = seen1 = summaryflag = 0; totblocks = totexts = 0; aglist = NULL; hist = NULL; rtflag = false; while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) { switch (c) { case 'a': aglistadd(optarg); break; case 'b': if (speced) goto many_spec; multsize = 2; speced = 1; break; case 'd': dumpflag = 1; break; case 'e': if (speced) goto many_spec; equalsize = cvt_s64(optarg, 0); if (errno) return command_usage(&freesp_cmd); speced = 1; break; case 'g': histcount = 0; gflag++; break; case 'h': if (speced && !histcount) goto many_spec; /* addhistent increments histcount */ x = cvt_s64(optarg, 0); if (errno) return command_usage(&freesp_cmd); addhistent(x); speced = 1; break; case 'm': if (speced) goto many_spec; multsize = cvt_s64(optarg, 0); if (errno) return command_usage(&freesp_cmd); speced = 1; break; case 'r': rtflag = true; break; case 's': summaryflag = 1; break; case '?': default: return command_usage(&freesp_cmd); } } if (optind != argc) return 0; if (!speced) multsize = 2; histinit(fsgeom->agblocks); return 1; many_spec: return command_usage(&freesp_cmd); } /* * Report on freespace usage in xfs filesystem. */ static int freesp_f( int argc, char **argv) { struct xfs_fsop_geom *fsgeom = &file->xfd.fsgeom; xfs_agnumber_t agno; if (!init(argc, argv)) return 0; if (gflag) printf(_(" AG extents blocks\n")); if (rtflag) scan_ag(NULLAGNUMBER); for (agno = 0; !rtflag && agno < fsgeom->agcount; agno++) { if (inaglist(agno)) scan_ag(agno); } if (histcount && !gflag) printhist(); if (summaryflag) { printf(_("total free extents %lld\n"), totexts); printf(_("total free blocks %lld\n"), totblocks); printf(_("average free extent size %g\n"), (double)totblocks / (double)totexts); } if (aglist) free(aglist); if (hist) free(hist); return 0; } static void freesp_help(void) { printf(_( "\n" "Examine filesystem free space\n" "\n" " -a agno -- Scan only the given AG agno.\n" " -b -- binary histogram bin size\n" " -d -- debug output\n" " -e bsize -- Use fixed histogram bin size of bsize\n" " -g -- Print only a per-AG summary.\n" " -h hbsz -- Use custom histogram bin size of h1.\n" " Multiple specifications are allowed.\n" " -m bmult -- Use histogram bin size multiplier of bmult.\n" " -r -- Display realtime device free space information.\n" " -s -- Emit freespace summary information.\n" "\n" "Only one of -b, -e, -h, or -m may be specified.\n" "\n")); } void freesp_init(void) { freesp_cmd.name = "freesp"; freesp_cmd.altname = "fsp"; freesp_cmd.cfunc = freesp_f; freesp_cmd.argmin = 0; freesp_cmd.argmax = -1; freesp_cmd.args = "[-dgrs] [-a agno]... [ -b | -e bsize | -h h1... | -m bmult ]"; freesp_cmd.flags = CMD_FLAG_ONESHOT; freesp_cmd.oneline = _("Examine filesystem free space"); freesp_cmd.help = freesp_help; add_command(&freesp_cmd); } xfsprogs-5.3.0/spaceman/health.c0000644000175000017500000002141113570057155016453 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2019 Oracle. * All Rights Reserved. */ #include "platform_defs.h" #include "libxfs.h" #include "command.h" #include "init.h" #include "input.h" #include "libfrog/logging.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" #include "space.h" static cmdinfo_t health_cmd; static unsigned long long reported; static bool comprehensive; static bool quiet; static bool has_realtime(const struct xfs_fsop_geom *g) { return g->rtblocks > 0; } static bool has_finobt(const struct xfs_fsop_geom *g) { return g->flags & XFS_FSOP_GEOM_FLAGS_FINOBT; } static bool has_rmapbt(const struct xfs_fsop_geom *g) { return g->flags & XFS_FSOP_GEOM_FLAGS_RMAPBT; } static bool has_reflink(const struct xfs_fsop_geom *g) { return g->flags & XFS_FSOP_GEOM_FLAGS_REFLINK; } struct flag_map { unsigned int mask; bool (*has_fn)(const struct xfs_fsop_geom *g); const char *descr; }; static const struct flag_map fs_flags[] = { { .mask = XFS_FSOP_GEOM_SICK_COUNTERS, .descr = "summary counters", }, { .mask = XFS_FSOP_GEOM_SICK_UQUOTA, .descr = "user quota", }, { .mask = XFS_FSOP_GEOM_SICK_GQUOTA, .descr = "group quota", }, { .mask = XFS_FSOP_GEOM_SICK_PQUOTA, .descr = "project quota", }, { .mask = XFS_FSOP_GEOM_SICK_RT_BITMAP, .descr = "realtime bitmap", .has_fn = has_realtime, }, { .mask = XFS_FSOP_GEOM_SICK_RT_SUMMARY, .descr = "realtime summary", .has_fn = has_realtime, }, {0}, }; static const struct flag_map ag_flags[] = { { .mask = XFS_AG_GEOM_SICK_SB, .descr = "superblock", }, { .mask = XFS_AG_GEOM_SICK_AGF, .descr = "AGF header", }, { .mask = XFS_AG_GEOM_SICK_AGFL, .descr = "AGFL header", }, { .mask = XFS_AG_GEOM_SICK_AGI, .descr = "AGI header", }, { .mask = XFS_AG_GEOM_SICK_BNOBT, .descr = "free space by block btree", }, { .mask = XFS_AG_GEOM_SICK_CNTBT, .descr = "free space by length btree", }, { .mask = XFS_AG_GEOM_SICK_INOBT, .descr = "inode btree", }, { .mask = XFS_AG_GEOM_SICK_FINOBT, .descr = "free inode btree", .has_fn = has_finobt, }, { .mask = XFS_AG_GEOM_SICK_RMAPBT, .descr = "reverse mappings btree", .has_fn = has_rmapbt, }, { .mask = XFS_AG_GEOM_SICK_REFCNTBT, .descr = "reference count btree", .has_fn = has_reflink, }, {0}, }; static const struct flag_map inode_flags[] = { { .mask = XFS_BS_SICK_INODE, .descr = "inode core", }, { .mask = XFS_BS_SICK_BMBTD, .descr = "data fork", }, { .mask = XFS_BS_SICK_BMBTA, .descr = "extended attribute fork", }, { .mask = XFS_BS_SICK_BMBTC, .descr = "copy on write fork", }, { .mask = XFS_BS_SICK_DIR, .descr = "directory", }, { .mask = XFS_BS_SICK_XATTR, .descr = "extended attributes", }, { .mask = XFS_BS_SICK_SYMLINK, .descr = "symbolic link target", }, { .mask = XFS_BS_SICK_PARENT, .descr = "parent pointers", }, {0}, }; /* Convert a flag mask to a report. */ static void report_sick( const char *descr, const struct flag_map *maps, unsigned int sick, unsigned int checked) { const struct flag_map *f; bool bad; for (f = maps; f->mask != 0; f++) { if (f->has_fn && !f->has_fn(&file->xfd.fsgeom)) continue; bad = sick & f->mask; if (!bad && !(checked & f->mask)) continue; reported++; if (!bad && quiet) continue; printf("%s %s: %s\n", descr, _(f->descr), bad ? _("unhealthy") : _("ok")); } } /* Report on an AG's health. */ static int report_ag_sick( xfs_agnumber_t agno) { struct xfs_ag_geometry ageo = { 0 }; char descr[256]; int ret; ret = -xfrog_ag_geometry(file->xfd.fd, agno, &ageo); if (ret) { xfrog_perror(ret, "ag_geometry"); return 1; } snprintf(descr, sizeof(descr) - 1, _("AG %u"), agno); report_sick(descr, ag_flags, ageo.ag_sick, ageo.ag_checked); return 0; } /* Report on an inode's health. */ static int report_inode_health( unsigned long long ino, const char *descr) { struct xfs_bulkstat bs; char d[256]; int ret; if (!descr) { snprintf(d, sizeof(d) - 1, _("inode %llu"), ino); descr = d; } ret = -xfrog_bulkstat_single(&file->xfd, ino, 0, &bs); if (ret) { xfrog_perror(ret, descr); return 1; } report_sick(descr, inode_flags, bs.bs_sick, bs.bs_checked); return 0; } /* Report on a file's health. */ static int report_file_health( const char *path) { struct stat stata, statb; int ret; ret = lstat(path, &statb); if (ret) { perror(path); return 1; } ret = fstat(file->xfd.fd, &stata); if (ret) { perror(file->name); return 1; } if (stata.st_dev != statb.st_dev) { fprintf(stderr, _("%s: not on the open filesystem"), path); return 1; } return report_inode_health(statb.st_ino, path); } #define BULKSTAT_NR (128) /* * Report on all files' health for a given @agno. If @agno is NULLAGNUMBER, * report on all files in the filesystem. */ static int report_bulkstat_health( xfs_agnumber_t agno) { struct xfs_bulkstat_req *breq; char descr[256]; uint32_t i; int error; error = -xfrog_bulkstat_alloc_req(BULKSTAT_NR, 0, &breq); if (error) { xfrog_perror(error, "bulk alloc req"); exitcode = 1; return 1; } if (agno != NULLAGNUMBER) xfrog_bulkstat_set_ag(breq, agno); do { error = -xfrog_bulkstat(&file->xfd, breq); if (error) break; for (i = 0; i < breq->hdr.ocount; i++) { snprintf(descr, sizeof(descr) - 1, _("inode %"PRIu64), breq->bulkstat[i].bs_ino); report_sick(descr, inode_flags, breq->bulkstat[i].bs_sick, breq->bulkstat[i].bs_checked); } } while (breq->hdr.ocount > 0); if (error) xfrog_perror(error, "bulkstat"); free(breq); return error; } #define OPT_STRING ("a:cfi:q") /* Report on health problems in XFS filesystem. */ static int health_f( int argc, char **argv) { unsigned long long x; xfs_agnumber_t agno; bool default_report = true; int c; int ret; reported = 0; if (file->xfd.fsgeom.version != XFS_FSOP_GEOM_VERSION_V5) { perror("health"); return 1; } /* Set our reporting options appropriately in the first pass. */ while ((c = getopt(argc, argv, OPT_STRING)) != EOF) { switch (c) { case 'a': default_report = false; errno = 0; x = strtoll(optarg, NULL, 10); if (!errno && x >= NULLAGNUMBER) errno = ERANGE; if (errno) { perror("ag health"); return 1; } break; case 'c': comprehensive = true; break; case 'f': default_report = false; break; case 'i': default_report = false; errno = 0; x = strtoll(optarg, NULL, 10); if (errno) { perror("inode health"); return 1; } break; case 'q': quiet = true; break; default: return command_usage(&health_cmd); } } if (optind < argc) default_report = false; /* Reparse arguments, this time for reporting actions. */ optind = 1; while ((c = getopt(argc, argv, OPT_STRING)) != EOF) { switch (c) { case 'a': agno = strtoll(optarg, NULL, 10); ret = report_ag_sick(agno); if (!ret && comprehensive) ret = report_bulkstat_health(agno); if (ret) return 1; break; case 'f': report_sick(_("filesystem"), fs_flags, file->xfd.fsgeom.sick, file->xfd.fsgeom.checked); if (comprehensive) { ret = report_bulkstat_health(NULLAGNUMBER); if (ret) return 1; } break; case 'i': x = strtoll(optarg, NULL, 10); ret = report_inode_health(x, NULL); if (ret) return 1; break; default: break; } } for (c = optind; c < argc; c++) { ret = report_file_health(argv[c]); if (ret) return 1; } /* No arguments gets us a summary of fs state. */ if (default_report) { report_sick(_("filesystem"), fs_flags, file->xfd.fsgeom.sick, file->xfd.fsgeom.checked); for (agno = 0; agno < file->xfd.fsgeom.agcount; agno++) { ret = report_ag_sick(agno); if (ret) return 1; } if (comprehensive) { ret = report_bulkstat_health(NULLAGNUMBER); if (ret) return 1; } } if (!reported) { fprintf(stderr, _("Health status has not been collected for this filesystem.\n")); fprintf(stderr, _("Please run xfs_scrub(8) to remedy this situation.\n")); } return 0; } static void health_help(void) { printf(_( "\n" "Report all observed filesystem health problems.\n" "\n" " -a agno -- Report health of the given allocation group.\n" " -c -- Report on the health of all inodes.\n" " -f -- Report health of the overall filesystem.\n" " -i inum -- Report health of a given inode number.\n" " -q -- Only report unhealthy metadata.\n" " paths -- Report health of the given file path.\n" "\n")); } static cmdinfo_t health_cmd = { .name = "health", .cfunc = health_f, .argmin = 0, .argmax = -1, .args = "[-a agno] [-c] [-f] [-i inum] [-q] [paths]", .flags = CMD_FLAG_ONESHOT, .help = health_help, }; void health_init(void) { health_cmd.oneline = _("Report observed XFS health problems."), add_command(&health_cmd); } xfsprogs-5.3.0/spaceman/info.c0000644000175000017500000000221113570057155016136 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #include "libxfs.h" #include "command.h" #include "init.h" #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "space.h" static void info_help(void) { printf(_( "\n" " Pretty-prints the filesystem geometry as derived from the superblock.\n" " The output has the same format as mkfs.xfs, xfs_info, and other utilities.\n" " The opened file must be an XFS mount point.\n" "\n" )); } static int info_f( int argc, char **argv) { if (fs_table_lookup_mount(file->name) == NULL) { fprintf(stderr, _("%s: Not a XFS mount point.\n"), file->name); return 1; } xfs_report_geom(&file->xfd.fsgeom, file->fs_path.fs_name, file->fs_path.fs_log, file->fs_path.fs_rt); return 0; } static const struct cmdinfo info_cmd = { .name = "info", .altname = "i", .cfunc = info_f, .argmin = 0, .argmax = 0, .canpush = 0, .args = NULL, .flags = CMD_FLAG_ONESHOT, .oneline = N_("pretty-print superblock geometry info"), .help = info_help, }; void info_init(void) { add_command(&info_cmd); } xfsprogs-5.3.0/spaceman/init.c0000644000175000017500000000335713570057155016162 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2012 Red Hat, Inc * All Rights Reserved. */ #include "libxfs.h" #include "libfrog/fsgeom.h" #include "command.h" #include "input.h" #include "init.h" #include "libfrog/paths.h" #include "space.h" char *progname; int exitcode; static void usage(void) { fprintf(stderr, _("Usage: %s [-c cmd] file\n"), progname); exit(1); } static void init_commands(void) { print_init(); help_init(); info_init(); prealloc_init(); quit_init(); trim_init(); freesp_init(); health_init(); } static int init_args_command( int index) { if (index >= filecount) return 0; file = &filetable[index++]; return index; } static int init_check_command( const cmdinfo_t *ct) { if (!(ct->flags & CMD_FLAG_ONESHOT)) return 0; return 1; } static void init( int argc, char **argv) { int c; struct xfs_fd xfd = XFS_FD_INIT_EMPTY; struct fs_path fsp; progname = basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); fs_table_initialise(0, NULL, 0, NULL); while ((c = getopt(argc, argv, "c:p:V")) != EOF) { switch (c) { case 'c': add_user_command(optarg); break; case 'p': progname = optarg; break; case 'V': printf(_("%s version %s\n"), progname, VERSION); exit(0); default: usage(); } } if (optind != argc - 1) usage(); c = openfile(argv[optind], &xfd, &fsp); if (c < 0) exit(1); if (!platform_test_xfs_fd(xfd.fd)) printf(_("Not an XFS filesystem!\n")); c = addfile(argv[optind], &xfd, &fsp); if (c < 0) exit(1); init_commands(); add_command_iterator(init_args_command); add_check_command(init_check_command); } int main( int argc, char **argv) { init(argc, argv); command_loop(); return exitcode; } xfsprogs-5.3.0/spaceman/init.h0000644000175000017500000000036113435336037016156 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2012 Red Hat, Inc. * All Rights Reserved. */ #ifndef XFS_SPACEMAN_INIT_H_ #define XFS_SPACEMAN_INIT_H_ extern char *progname; extern int exitcode; #endif /* XFS_SPACEMAN_INIT_H_ */ xfsprogs-5.3.0/spaceman/prealloc.c0000644000175000017500000000475013570057155017016 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2012 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libfrog/fsgeom.h" #include "command.h" #include "input.h" #include "init.h" #include "libfrog/paths.h" #include "space.h" static cmdinfo_t prealloc_cmd; /* * Control preallocation amounts. */ static int prealloc_f( int argc, char **argv) { struct xfs_fs_eofblocks eofb = {0}; struct xfs_fsop_geom *fsgeom = &file->xfd.fsgeom; int c; eofb.eof_version = XFS_EOFBLOCKS_VERSION; while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) { switch (c) { case 'g': eofb.eof_flags |= XFS_EOF_FLAGS_GID; eofb.eof_gid = cvt_u32(optarg, 10); if (errno) return command_usage(&prealloc_cmd); break; case 'u': eofb.eof_flags |= XFS_EOF_FLAGS_UID; eofb.eof_uid = cvt_u32(optarg, 10); if (errno) return command_usage(&prealloc_cmd); break; case 'p': eofb.eof_flags |= XFS_EOF_FLAGS_PRID; eofb.eof_prid = cvt_u32(optarg, 10); if (errno) return command_usage(&prealloc_cmd); break; case 's': eofb.eof_flags |= XFS_EOF_FLAGS_SYNC; break; case 'm': eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE; eofb.eof_min_file_size = cvtnum(fsgeom->blocksize, fsgeom->sectsize, optarg); break; case '?': default: return command_usage(&prealloc_cmd); } } if (optind != argc) return command_usage(&prealloc_cmd); if (ioctl(file->xfd.fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) { fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"), progname, file->name, strerror(errno)); } return 0; } static void prealloc_help(void) { printf(_( "\n" "Remove speculative preallocation\n" "\n" " -g gid -- remove prealloc on files matching group \n" " -m minlen -- only consider files larger than \n" " -p prid -- remove prealloc on files matching project \n" " -s -- wait for removal to complete\n" " -u uid -- remove prealloc on files matching user \n" "\n" "If none of -u, -g, or -p are specified, this command acts on all files.\n" "minlen can take units.\n" "\n")); } void prealloc_init(void) { prealloc_cmd.name = "prealloc"; prealloc_cmd.altname = "prealloc"; prealloc_cmd.cfunc = prealloc_f; prealloc_cmd.argmin = 1; prealloc_cmd.argmax = -1; prealloc_cmd.args = "[-s] [-u id] [-g id] [-p id] [-m minlen]"; prealloc_cmd.flags = CMD_FLAG_ONESHOT; prealloc_cmd.oneline = _("Remove speculative preallocation"); prealloc_cmd.help = prealloc_help; add_command(&prealloc_cmd); } xfsprogs-5.3.0/spaceman/space.h0000644000175000017500000000177313570057155016317 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2012 Red Hat, Inc. * All Rights Reserved. */ #ifndef XFS_SPACEMAN_SPACE_H_ #define XFS_SPACEMAN_SPACE_H_ struct fileio { struct xfs_fd xfd; /* XFS runtime support context */ struct fs_path fs_path; /* XFS path information */ char *name; /* file name at time of open */ }; extern struct fileio *filetable; /* open file table */ extern int filecount; /* number of open files */ extern struct fileio *file; /* active file in file table */ extern int openfile(char *path, struct xfs_fd *xfd, struct fs_path *fs_path); extern int addfile(char *path, struct xfs_fd *xfd, struct fs_path *fs_path); extern void print_init(void); extern void help_init(void); extern void prealloc_init(void); extern void quit_init(void); extern void trim_init(void); #ifdef HAVE_GETFSMAP extern void freesp_init(void); #else # define freesp_init() do { } while (0) #endif extern void info_init(void); extern void health_init(void); #endif /* XFS_SPACEMAN_SPACE_H_ */ xfsprogs-5.3.0/spaceman/trim.c0000644000175000017500000000512113570057155016161 0ustar nathansnathans// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2012 Red Hat, Inc. * All Rights Reserved. */ #include "libxfs.h" #include "libfrog/fsgeom.h" #include "command.h" #include "init.h" #include "libfrog/paths.h" #include "space.h" #include "input.h" static cmdinfo_t trim_cmd; /* * Trim unused space in xfs filesystem. */ static int trim_f( int argc, char **argv) { struct fstrim_range trim = {0}; struct xfs_fd *xfd = &file->xfd; struct xfs_fsop_geom *fsgeom = &xfd->fsgeom; xfs_agnumber_t agno = 0; off64_t offset = 0; ssize_t length = 0; ssize_t minlen = 0; int aflag = 0; int fflag = 0; int ret; int c; while ((c = getopt(argc, argv, "a:fm:")) != EOF) { switch (c) { case 'a': aflag = 1; agno = cvt_u32(optarg, 10); if (errno) { printf(_("bad agno value %s\n"), optarg); return command_usage(&trim_cmd); } break; case 'f': fflag = 1; break; case 'm': minlen = cvtnum(fsgeom->blocksize, fsgeom->sectsize, optarg); break; default: return command_usage(&trim_cmd); } } if (aflag && fflag) return command_usage(&trim_cmd); if (optind != argc - 2 && !(aflag || fflag)) return command_usage(&trim_cmd); if (optind != argc) { offset = cvtnum(fsgeom->blocksize, fsgeom->sectsize, argv[optind]); length = cvtnum(fsgeom->blocksize, fsgeom->sectsize, argv[optind + 1]); } else if (agno) { offset = cvt_agbno_to_b(xfd, agno, 0); length = cvt_off_fsb_to_b(xfd, fsgeom->agblocks); } else { offset = 0; length = cvt_off_fsb_to_b(xfd, fsgeom->datablocks); } trim.start = offset; trim.len = length; trim.minlen = minlen; ret = ioctl(file->xfd.fd, FITRIM, (unsigned long)&trim); if (ret < 0) { fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: %s\n", progname, file->name, strerror(errno)); exitcode = 1; } return 0; } static void trim_help(void) { printf(_( "\n" "Discard filesystem free space\n" "\n" " -a agno -- trim all the freespace in the given AG agno\n" " -f -- trim all the freespace in the entire filesystem\n" " offset length -- trim the freespace in the range {offset, length}\n" " -m minlen -- skip freespace extents smaller than minlen\n" "\n" "One of -a, -f, or the offset/length pair are required.\n" "\n")); } void trim_init(void) { trim_cmd.name = "trim"; trim_cmd.altname = "tr"; trim_cmd.cfunc = trim_f; trim_cmd.argmin = 1; trim_cmd.argmax = 4; trim_cmd.args = "[-m minlen] ( -a agno | -f | offset length )"; trim_cmd.flags = CMD_FLAG_ONESHOT; trim_cmd.oneline = _("Discard filesystem free space"); trim_cmd.help = trim_help; add_command(&trim_cmd); } xfsprogs-5.3.0/spaceman/xfs_info.sh0000755000175000017500000000241613570057155017220 0ustar nathansnathans#!/bin/sh -f # SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # OPTS="" USAGE="Usage: xfs_info [-V] [-t mtab] [mountpoint|device|file]" # Try to find a loop device associated with a file. We only want to return # one loopdev (multiple loop devices can attach to a single file) so we grab # the last line and return it if it's actually a block device. try_find_loop_dev_for_file() { local x="$(losetup -O NAME -j "$1" 2> /dev/null | tail -n 1)" test -b "$x" && echo "$x" } while getopts "t:V" c do case $c in t) OPTS="-t $OPTARG" ;; V) xfs_spaceman -p xfs_info -V status=$? exit $status ;; *) echo $USAGE 1>&2 exit 2 ;; esac done set -- extra "$@" shift $OPTIND case $# in 1) arg="$1" # See if we can map the arg to a loop device loopdev="$(try_find_loop_dev_for_file "${arg}")" test -n "${loopdev}" && arg="${loopdev}" # If we find a mountpoint for the device, do a live query; # otherwise try reading the fs with xfs_db. if mountpt="$(findmnt -t xfs -f -n -o TARGET "${arg}" 2> /dev/null)"; then xfs_spaceman -p xfs_info -c "info" $OPTS "${mountpt}" status=$? else xfs_db -p xfs_info -c "info" $OPTS "${arg}" status=$? fi ;; *) echo $USAGE 1>&2 exit 2 ;; esac exit $status xfsprogs-5.3.0/tools/find-api-violations.sh0000755000175000017500000000260013435336037020624 0ustar nathansnathans#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Find libxfs API violations -- calls to functions defined in libxfs/*.c that # don't use the libxfs wrappers; or failing to negate the integer return # values. # NOTE: This script doesn't look for API violations in function parameters. tool_dirs="copy db estimate fsck fsr growfs io logprint mdrestore mkfs quota repair rtcp scrub" # Calls to xfs_* functions in libxfs/*.c without the libxfs_ prefix find_possible_api_calls() { grep -rn '[-[:space:],(]xfs_[a-z_]*(' $tool_dirs | sed -e 's/^.*\(xfs_[a-z_]*\)(.*$/\1/g' | sort | uniq } check_if_api_calls() { while read f; do grep "^$f(" libxfs/*.c; done | sed -e 's/^.*:xfs_/xfs_/g' -e 's/.$//g' } find_libxfs_violations() { grep -r -n -f <(find_possible_api_calls | check_if_api_calls | sed -e 's/^/[[:space:],-(]/g' -e 's/$/(/g' ) $tool_dirs } # libxfs calls without negated error codes find_errcode_violations() { grep -r -n 'err.* = libxfs' $tool_dirs } # Find xfs_* calls that are in the libxfs definition list find_possible_libxfs_api_calls() { grep '#define[[:space:]]*xfs' libxfs/libxfs_api_defs.h | awk '{print $2}' } find_libxfs_api_violations() { grep -r -n -f <(find_possible_libxfs_api_calls | sed -e 's/^/[[:space:],-(]/g' -e 's/$/(/g') $tool_dirs } (find_libxfs_violations ; find_errcode_violations ; find_libxfs_api_violations) | sort -g -t ':' -k 2 | sort -g -t ':' -k 1 | uniq xfsprogs-5.3.0/tools/libxfs-apply0000755000175000017500000002637413435336037016767 0ustar nathansnathans#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # 2 args: # libxfs-apply usage() { echo $* echo echo "Usage:" echo " libxfs-apply [--verbose] --sob --source --commit " echo " libxfs-apply --patch " echo echo "libxfs-apply should be run in the destination git repository." exit } cleanup() { rm -f $PATCH } # output to stderr so it is not caught by file redirects fail() { >&2 echo "Fail:" >&2 echo $* cleanup exit } # filterdiff 0.3.4 is the first version that handles git diff metadata (almost) # correctly. It just doesn't work properly in prior versions, so those versions # can't be used to extract the commit message prior to the diff. Hence just # abort and tell the user to upgrade if an old version is detected. We need to # check against x.y.z version numbers here. _version=`filterdiff --version | cut -d " " -f 5` _major=`echo $_version | cut -d "." -f 1` _minor=`echo $_version | cut -d "." -f 2` _patch=`echo $_version | cut -d "." -f 3` if [ $_major -eq 0 ]; then if [ $_minor -lt 3 ]; then fail "filterdiff $_version found. 0.3.4 or greater is required." fi if [ $_minor -eq 3 -a $_patch -le 3 ]; then fail "filterdiff $_version found. 0.3.4 or greater is required." fi fi # We should see repository contents we recognise, both at the source and # destination. Kernel repositorys will have fs/xfs/libxfs, and xfsprogs # repositories will have libxcmd. SOURCE="kernel" check_repo() { if [ ! -d "fs/xfs/libxfs" -a ! -d "libxcmd" ]; then usage "$1 repository contents not recognised!" fi if [ -d "$REPO/libxcmd" ]; then SOURCE="xfsprogs" fi } REPO= PATCH= COMMIT_ID= VERBOSE= GUILT=0 STGIT=0 while [ $# -gt 0 ]; do case "$1" in --source) REPO=$2 ; shift ;; --patch) PATCH=$2; shift ;; --commit) COMMIT_ID=$2 ; shift ;; --sob) SIGNED_OFF_BY=$2 ; shift ;; --verbose) VERBOSE=true ;; *) usage ;; esac shift done if [ -n "$PATCH" ]; then if [ -n "$REPO" -o -n "$COMMIT_ID" ]; then usage "Need to specify either patch or source repo/commit" fi VERBOSE=true elif [ -z "$REPO" -o -z "$COMMIT_ID" ]; then usage "Need to specify both source repo and commit id" fi check_repo Destination # Are we using guilt? This works even if no patch is applied. guilt top &> /dev/null if [ $? -eq 0 ]; then GUILT=1 fi # Are we using stgit? This works even if no patch is applied. stg top &> /dev/null if [ $? -eq 0 ]; then STGIT=1 fi #this is pulled from the guilt code to handle commit ids sanely. # usage: munge_hash_range # # this means: # - one commit # .. - hash until head (excludes hash, includes head) # .. - until hash (includes hash) # .. - from hash to hash (inclusive) # # The output of this function is suitable to be passed to "git rev-list" munge_hash_range() { case "$1" in *..*..*|*\ *) # double .. or space is illegal return 1;; ..*) # e.g., "..v0.10" echo ${1#..};; *..) # e.g., "v0.19.." echo ${1%..}..HEAD;; *..*) # e.g., "v0.19-rc1..v0.19" echo ${1%%..*}..${1#*..};; ?*) # e.g., "v0.19" echo $1^..$1;; *) # empty return 1;; esac return 0 } # Filter the patch into the right format & files for the other tree filter_kernel_patch() { local _patch=$1 local _libxfs_files="" # The files we will try to apply to _libxfs_files=`mktemp` ls -1 fs/xfs/libxfs/*.[ch] | sed -e "s%.*/\(.*\)%*\1%" > $_libxfs_files # Create the new patch # filterdiff will have screwed up files that source/sink /dev/null. # fix that up with some sed magic. filterdiff \ --verbose \ -I $_libxfs_files \ --strip=1 \ --addoldprefix=a/fs/xfs/ \ --addnewprefix=b/fs/xfs/ \ $_patch | \ sed -e 's, [ab]\/fs\/xfs\/\(\/dev\/null\), \1,' \ -e '/^diff --git/d' rm -f $_libxfs_files } filter_xfsprogs_patch() { local _patch=$1 local _libxfs_files="" # The files we will try to apply to. We need to pull this from the # patch, as the may be libxfs files added in this patch and so we # need to capture them. _libxfs_files=`mktemp` #ls -1 libxfs/*.[ch] | sed -e "s%.*/\(.*\)%*libxfs/\1%" > $_libxfs_files lsdiff $_patch | sed -e "s%.*/\(.*\)%*libxfs/\1%" > $_libxfs_files # Create the new patch # filterdiff will have screwed up files that source/sink /dev/null. # fix that up with some sed magic. filterdiff \ --verbose \ -I $_libxfs_files \ --strip=3 \ --addoldprefix=a/ \ --addnewprefix=b/ \ $_patch | \ sed -e 's, [ab]\/\(\/dev\/null\), \1,' \ -e '/^diff --git/d' rm -f $_libxfs_files } fixup_header_format() { local _source=$1 local _patch=$2 local _hdr=`mktemp` local _diff=`mktemp` local _new_hdr=$_hdr.new # there's a bug in filterdiff that leaves a line at the end of the # header in the filtered git show output like: # # difflibxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c # # split the header on that (convenient!) sed -e /^difflib/q $_patch > $_hdr cat $_patch | awk ' BEGIN { difflib_seen = 0; index_seen = 0 } /^difflib/ { difflib_seen++; next } /^index/ { if (++index_seen == 1) { next } } // { if (difflib_seen) { print $0 } }' > $_diff # the header now has the format: # commit 0d5a75e9e23ee39cd0d8a167393dcedb4f0f47b2 # Author: Eric Sandeen # Date: Wed Jun 1 17:38:15 2016 +1000 # # xfs: make several functions static #.... # Signed-off-by: Dave Chinner # #difflibxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c # # We want to format it like a normal patch with a line to say what repo # and commit it was sourced from: # # xfs: make several functions static # # From: Eric Sandeen # # Source kernel commit: 0d5a75e9e23ee39cd0d8a167393dcedb4f0f47b2 # # # # To do this, use sed to first strip whitespace, then pass it into awk # to rearrange the headers. sed -e 's/^ *//' $_hdr | awk -v src=$_source ' BEGIN { date_seen=0 subject_seen=0 } /^commit/ { commit=$2 next; } /^Author:/ { split($0, a, ":") from=a[2] next; } /^Date:/ { date_seen=1; next } /^difflib/ { next } // { if (date_seen == 0) next; if (subject_seen == 0) { if (length($0) != 0) { subject_seen=1 subject=$0; } next; } if (subject_seen == 1) { print subject print print "From:" from print print "Source " src " commit: " commit subject_seen=2 } print $0 }' > $_hdr.new # Remove the last line if it contains only whitespace sed -i '${/^[[:space:]]*$/d;}' $_hdr.new # Add Signed-off-by: header if specified if [ ! -z ${SIGNED_OFF_BY+x} ]; then echo "Signed-off-by: $SIGNED_OFF_BY" >> $_hdr.new else # get it from git config if present SOB_NAME=`git config --get user.name` SOB_EMAIL=`git config --get user.email` if [ ! -z ${SOB_NAME+x} ]; then echo "Signed-off-by: $SOB_NAME <$SOB_EMAIL>" >> $_hdr.new fi fi # now output the new patch cat $_hdr.new $_diff rm -f $_hdr* $_diff } apply_patch() { local _patch=$1 local _patch_name=$2 local _current_commit=$3 local _new_patch=`mktemp` local _source="kernel" local _target="xfsprogs" # filter just the libxfs parts of the patch if [ $SOURCE == "xfsprogs" ]; then [ -n "$VERBOSE" ] || lsdiff $_patch | grep -q "[ab]/libxfs/" if [ $? -ne 0 ]; then echo "Doesn't look like an xfsprogs patch with libxfs changes" echo "Skipping commit $_current_commit" return fi filter_kernel_patch $_patch > $_new_patch _source="xfsprogs" _target="kernel" elif [ $SOURCE == "kernel" ]; then [ -n "$VERBOSE" ] || lsdiff $_patch | grep -q "[ab]/fs/xfs/libxfs/" if [ $? -ne 0 ]; then echo "Doesn't look like a kernel patch with libxfs changes" echo "Skipping commit $_current_commit" return fi filter_xfsprogs_patch $_patch > $_new_patch else fail "Unknown source repo type: $SOURCE" fi grep -q "Source $_target commit: " $_patch if [ "$?" -eq "0" ]; then echo "$_patch_name already synced up" echo "$_skipping commit $_current_commit" return fi # now munge the header to be in the correct format. fixup_header_format $_source $_new_patch > $_new_patch.2 if [ -n "$VERBOSE" ]; then echo "Filtered patch from $REPO contains:" lsdiff $_new_patch.2 fi # Ok, now apply with guilt or patch; either may fail and require a force # and/or a manual reject fixup if [ $GUILT -eq 1 ]; then [ -n "$VERBOSE" ] || echo "$REPO looks like a guilt directory." PATCHES=`guilt applied | wc -l` if [ -n "$VERBOSE" -a $PATCHES -gt 0 ]; then echo -n "Top patch is: " guilt top fi guilt import -P $_patch_name $_new_patch.2 guilt push if [ $? -eq 0 ]; then guilt refresh else echo "Guilt push of $_current_commit $_patch_name failed!" read -r -p "Skip or Fail [s|F]? " response if [ -z "$response" -o "$response" != "s" ]; then echo "Force push patch, fix and refresh." echo "Restart from commit $_current_commit" fail "Manual cleanup required!" else echo "Skipping." guilt delete -f $_patch_name fi fi elif [ $STGIT -eq 1 ]; then [ -n "$VERBOSE" ] || echo "$REPO looks like a stgit directory." PATCHES=`stg series | wc -l` if [ -n "$VERBOSE" -a $PATCHES -gt 0 ]; then echo -n "Top patch is: " stg top fi stg import -n $_patch_name $_new_patch.2 if [ $? -ne 0 ]; then echo "stgit push failed!" read -r -p "Skip or Fail [s|F]? " response if [ -z "$response" -o "$response" != "s" ]; then echo "Force push patch, fix and refresh." echo "Restart from commit $_current_commit" fail "Manual cleanup required!" else echo "Skipping. Manual series file cleanup needed!" fi fi else echo "Applying with patch utility:" patch -p1 < $_new_patch.2 echo "Patch was applied in $REPO; check for rejects, etc" fi rm -f $_new_patch* } # name a guilt patch. Code is lifted from guilt import-commit. name_patch() { s=`git log --no-decorate --pretty=oneline -1 $1 | cut -c 42-` # Try to convert the first line of the commit message to a # valid patch name. fname=`printf %s "$s" | \ sed -e "s/&/and/g" -e "s/[ :]/_/g" -e "s,[/\\],-,g" \ -e "s/['\\[{}]//g" -e 's/]//g' -e 's/\*/-/g' \ -e 's/\?/-/g' -e 's/\.\.\.*/./g' -e 's/^\.//' \ -e 's/\.patch$//' -e 's/\.$//' | tr A-Z a-z` # Try harder to make it a legal commit name by # removing all but a few safe characters. fname=`echo $fname|tr -d -c _a-zA-Z0-9---/\\n` echo $fname } # single patch is easy. if [ -z "$COMMIT_ID" ]; then apply_patch $PATCH cleanup exit 0 fi # switch to source repo and get individual commit IDs # # git rev-list gives us a list in reverse chronological order, so we need to # reverse that to give us the order we require. pushd $REPO > /dev/null check_repo Source hashr=`munge_hash_range $COMMIT_ID` if [ $SOURCE == "kernel" ]; then hashr="$hashr -- fs/xfs/libxfs" else hashr="$hashr -- libxfs" fi # grab and echo the list of commits for confirmation echo "Commits to apply:" commit_list=`git rev-list $hashr | tac` git log --oneline $hashr |tac read -r -p "Proceed [y|N]? " response if [ -z "$response" -o "$response" != "y" ]; then fail "Aborted!" fi popd > /dev/null PATCH=`mktemp` for commit in $commit_list; do # switch to source repo and pull commit into a patch file pushd $REPO > /dev/null git show $commit > $PATCH || usage "Bad source commit ID!" patch_name=`name_patch $commit` popd > /dev/null apply_patch $PATCH $patch_name $commit done cleanup xfsprogs-5.3.0/tools/libxfs-diff0000755000175000017500000000107413435336037016540 0ustar nathansnathans#!/bin/bash # SPDX-License-Identifier: GPL-2.0 if [ -z "$1" ] || [ ! -d "$1" ] || [ "$1" = "--help" ]; then echo "Usage: $0 kernel_libxfs_dir" exit 1 fi if [ ! -d "libxfs/" ]; then echo "$0: Must be run from the top level directory." exit 2 fi dir="$1" if [ ! -e "${dir}/xfs_format.h" ]; then echo "${dir}: This doesn't seem to be a libxfs/ directory." exit 3 fi dir="$(readlink -m "${dir}/..")" for i in libxfs/xfs*.[ch]; do kfile="${dir}/$i" diff -Naurpw --label "$i" <(sed -e '/#include/d' "$i") --label "${kfile}" <(sed -e '/#include/d' "${kfile}") done xfsprogs-5.3.0/tools/xfsbuflock.py0000755000175000017500000001225113435336037017137 0ustar nathansnathans#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0+ # Copyright (C) 2016 Oracle. All Rights Reserved. # # Author: Darrick J. Wong # Read ftrace input, looking for XFS buffer deadlocks. # # Rough guide to using this script: # Collect ftrace data from a deadlock: # # # trace-cmd record -e 'xfs_buf_*lock*' & # ^Z # # killall -INT trace-cmd # # # Now analyze the captured trace data: # # # trace-cmd report | xfsbuflock.py # === fsx-14956 === # # 3732.005575: xfs_buf_trylock_fail: dev 8:16 bno 0x1 nblks 0x1 hold 4 \ # pincount 1 lock 0 flags DONE|KMEM caller 0xc009af36s # Locked buffers: # dev 8:16 bno 0x64c371 nblks 0x1 lock 1 owner fsx-14956@3732.005567 # waiting: fsx-14954 # dev 8:16 bno 0x64c380 nblks 0x8 lock 1 owner fsx-14956@3732.005571 # dev 8:16 bno 0x64c378 nblks 0x8 lock 1 owner fsx-14956@3732.005570 # === fsx-14954 === # # 3732.005592: xfs_buf_trylock_fail: dev 8:16 bno 0x64c371 nblks 0x1 hold 4 \ # pincount 1 lock 0 flags ASYNC|DONE|KMEM caller 0xc009af36s # Locked buffers: # dev 8:16 bno 0x8 nblks 0x8 lock 1 owner fsx-14954@3732.005583 # dev 8:16 bno 0x1 nblks 0x1 lock 1 owner fsx-14954@3732.005574 # waiting: fsx-14956 # waiting: fsx-14957 # waiting: fsx-14958 # dev 8:16 bno 0x10 nblks 0x8 lock 1 owner fsx-14954@3732.005585 # # As you can see, fsx-14596 is locking AGFs in violation of the locking # order rules. import sys import fileinput from collections import namedtuple NR_BACKTRACE = 50 class Process: def __init__(self, pid): self.pid = pid; self.bufs = set() self.locked_bufs = set() self.backtrace = [] def dump(self): print('=== %s ===' % self.pid) for bt in self.backtrace: print('%f: %s' % (bt.time, bt.descr)) print('Locked buffers:') for buf in self.locked_bufs: buf.dump() class Buffer: def __init__(self, dev, bno, blen): self.dev = dev self.bno = int(bno, 0) self.blen = int(blen, 0) self.locked = False self.locktime = None self.owner = None self.waiters = set() self.lockline = 0 def trylock(self, process, time): if not self.locked: self.lockdone(process, time) def init(self, process, time): # Buffers are initialized locked, but we could be allocating # a surplus buffer while trying to grab a buffer that may or # may not already exist. if not self.locked: self.lockdone(process, time) def lockdone(self, process, time): if self.locked: print('Buffer 0x%x already locked at line %d? (line %d)' % \ (self.bno, self.lockline, nr)) # process.dump() # self.dump() # assert False if process in self.waiters: self.waiters.remove(process) self.locked = True self.owner = process self.locktime = time self.lockline = nr process.locked_bufs.add(self) process.bufs.add(self) locked_buffers.add(self) def waitlock(self, process): self.waiters.add(process) def unlock(self): self.locked = False if self in locked_buffers: locked_buffers.remove(self) if self.owner is not None and \ self in self.owner.locked_bufs: self.owner.locked_bufs.remove(self) def dump(self): if self.owner is not None: pid = '%s@%f (line %d)' % \ (self.owner.pid, self.locktime, self.lockline) else: pid = '' print('dev %s bno 0x%x nblks 0x%x lock %d owner %s' % \ (self.dev, self.bno, self.blen, self.locked, \ pid)) for proc in self.waiters: print(' waiting: %s' % proc.pid) Event = namedtuple('Event', 'time descr') # Read ftrace input, looking for events and for buffer lock info processes = {} buffers = {} locked_buffers = set() def getbuf(toks): if int(toks[7], 0) == 18446744073709551615: return None bufkey = ' '.join(toks[4:10]) if bufkey in buffers: return buffers[bufkey] buf = Buffer(toks[5], toks[7], toks[9]) buffers[bufkey] = buf return buf nr = 0 for line in fileinput.input(): nr += 1 toks = line.split() if len(toks) < 4: continue pid = toks[0] try: time = float(toks[2][:-1]) except: continue fn = toks[3][:-1] if pid in processes: proc = processes[pid] else: proc = Process(pid) processes[pid] = proc if fn == 'xfs_buf_unlock' or fn == 'xfs_buf_item_unlock_stale': buf = getbuf(toks) if buf is not None: buf.unlock() elif fn == 'xfs_buf_lock_done': buf = getbuf(toks) if buf is not None: buf.lockdone(proc, time) elif fn == 'xfs_buf_lock': buf = getbuf(toks) if buf is not None: buf.waitlock(proc) elif fn == 'xfs_buf_trylock': buf = getbuf(toks) if buf is not None: buf.trylock(proc, time) elif fn == 'xfs_buf_init': buf = getbuf(toks) if buf is not None: buf.init(proc, time) elif fn == 'xfs_buf_item_unlock': pass else: e = Event(time, ' '.join(toks[3:])) proc.backtrace.append(e) if len(proc.backtrace) > NR_BACKTRACE: proc.backtrace.pop(0) deadlocked = set() for buf in locked_buffers: deadlocked.add(buf.owner) for proc in deadlocked: proc.dump() sys.exit(0) for key in buffers: buf = buffers[key] if buf.locked: print('dev %s bno 0x%x len 0x%x owner %s' % (buf.dev, buf.bno, buf.blen, buf.owner.pid)) else: print('dev %s bno 0x%x len 0x%x' % (buf.dev, buf.bno, buf.blen)) sys.exit(0) for pid in processes: proc = processes[pid] xfsprogs-5.3.0/m4/libtool.m40000644000175000017500000112676613570057245015525 0ustar nathansnathans# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 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. # GNU Libtool 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool 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 . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS xfsprogs-5.3.0/m4/lt~obsolete.m40000644000175000017500000001377413570057245016424 0ustar nathansnathans# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) xfsprogs-5.3.0/m4/ltoptions.m40000644000175000017500000003426213570057245016100 0ustar nathansnathans# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) xfsprogs-5.3.0/m4/ltsugar.m40000644000175000017500000001044013570057245015516 0ustar nathansnathans# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) xfsprogs-5.3.0/m4/ltversion.m40000644000175000017500000000127313570057245016066 0ustar nathansnathans# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) xfsprogs-5.3.0/po/xfsprogs.pot0000644000175000017500000123761313570057260016303 0ustar nathansnathans# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-11-29 10:56+1100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: .././copy/xfs_copy.c:101 #, c-format msgid "Check logfile \"%s\" for more details\n" msgstr "" #: .././copy/xfs_copy.c:107 #, c-format msgid "%s: could not write to logfile \"%s\".\n" msgstr "" #: .././copy/xfs_copy.c:110 #, c-format msgid "Aborting XFS copy -- logfile error -- reason: %s\n" msgstr "" #: .././copy/xfs_copy.c:125 .././copy/xfs_copy.c:278 .././copy/xfs_copy.c:604 #: .././copy/xfs_copy.c:611 msgid "Aborting XFS copy - reason" msgstr "" #: .././copy/xfs_copy.c:145 msgid "THE FOLLOWING COPIES FAILED TO COMPLETE\n" msgstr "" #: .././copy/xfs_copy.c:149 msgid "write error" msgstr "" #: .././copy/xfs_copy.c:151 msgid "lseek error" msgstr "" #: .././copy/xfs_copy.c:152 #, c-format msgid " at offset %lld\n" msgstr "" #: .././copy/xfs_copy.c:156 #, c-format msgid "All copies completed.\n" msgstr "" #: .././copy/xfs_copy.c:159 #, c-format msgid "See \"%s\" for more details.\n" msgstr "" #: .././copy/xfs_copy.c:247 #, c-format msgid "%s: write error on target %d \"%s\" at offset %lld\n" msgstr "" #: .././copy/xfs_copy.c:252 #, c-format msgid "%s: lseek error on target %d \"%s\" at offset %lld\n" msgstr "" #: .././copy/xfs_copy.c:258 #, c-format msgid "Aborting target %d - reason" msgstr "" #: .././copy/xfs_copy.c:262 msgid "Aborting XFS copy - no more targets.\n" msgstr "" #: .././copy/xfs_copy.c:273 #, c-format msgid "%s: thread %d died unexpectedly, target \"%s\" incomplete\n" msgstr "" #: .././copy/xfs_copy.c:275 #, c-format msgid "%s: offset was probably %lld\n" msgstr "" #: .././copy/xfs_copy.c:286 #, c-format msgid "%s: Unknown child died (should never happen!)\n" msgstr "" #: .././copy/xfs_copy.c:296 #, c-format msgid "Usage: %s [-bdV] [-L logfile] source target [target ...]\n" msgstr "" #: .././copy/xfs_copy.c:379 #, c-format msgid "%s: lseek failure at offset %lld\n" msgstr "" #: .././copy/xfs_copy.c:394 #, c-format msgid "assert error: buf->length = %d, buf->size = %d\n" msgstr "" #: .././copy/xfs_copy.c:400 #, c-format msgid "%s: read failure at offset %lld\n" msgstr "" #: .././copy/xfs_copy.c:430 msgid "ag header buffer invalid!\n" msgstr "" #: .././copy/xfs_copy.c:584 .././db/init.c:85 .././estimate/xfs_estimate.c:131 #: .././fsr/xfs_fsr.c:190 .././growfs/xfs_growfs.c:121 .././io/init.c:211 #: .././logprint/logprint.c:194 .././mkfs/xfs_mkfs.c:3644 .././quota/init.c:170 #: .././repair/xfs_repair.c:318 .././rtcp/xfs_rtcp.c:44 #: .././scrub/xfs_scrub.c:667 .././spaceman/init.c:83 #, c-format msgid "%s version %s\n" msgstr "" #: .././copy/xfs_copy.c:602 #, c-format msgid "%s: couldn't open log file \"%s\"\n" msgstr "" #: .././copy/xfs_copy.c:609 #, c-format msgid "%s: couldn't set up logfile stream\n" msgstr "" #: .././copy/xfs_copy.c:621 msgid "Couldn't allocate target array\n" msgstr "" #: .././copy/xfs_copy.c:638 #, c-format msgid "%s: couldn't open source \"%s\"\n" msgstr "" #: .././copy/xfs_copy.c:644 #, c-format msgid "%s: couldn't stat source \"%s\"\n" msgstr "" #: .././copy/xfs_copy.c:654 #, c-format msgid "%s: Cannot set direct I/O flag on \"%s\".\n" msgstr "" #: .././copy/xfs_copy.c:659 #, c-format msgid "%s: xfsctl on file \"%s\" failed.\n" msgstr "" #: .././copy/xfs_copy.c:682 #, c-format msgid "%s: Warning -- a filesystem is mounted on the source device.\n" msgstr "" #: .././copy/xfs_copy.c:685 msgid "\t\tGenerated copies may be corrupt unless the source is\n" msgstr "" #: .././copy/xfs_copy.c:687 msgid "\t\tunmounted or mounted read-only. Copy proceeding...\n" msgstr "" #: .././copy/xfs_copy.c:704 #, c-format msgid "" "%s: couldn't initialize XFS library\n" "%s: Aborting.\n" msgstr "" #: .././copy/xfs_copy.c:728 #, c-format msgid "" "%s: %s filesystem failed to initialize\n" "%s: Aborting.\n" msgstr "" #: .././copy/xfs_copy.c:732 #, c-format msgid "" "%s %s filesystem failed to initialize\n" "%s: Aborting.\n" msgstr "" #: .././copy/xfs_copy.c:736 #, c-format msgid "" "%s: %s has an external log.\n" "%s: Aborting.\n" msgstr "" #: .././copy/xfs_copy.c:740 #, c-format msgid "" "%s: %s has a real-time section.\n" "%s: Aborting.\n" msgstr "" #: .././copy/xfs_copy.c:759 msgid "" "Error: source filesystem log is dirty. Mount the filesystem to replay the\n" "log, unmount and retry xfs_copy.\n" msgstr "" #: .././copy/xfs_copy.c:764 msgid "" "Error: could not determine the log head or tail of the source filesystem.\n" "Mount the filesystem to replay the log or run xfs_repair.\n" msgstr "" #: .././copy/xfs_copy.c:780 msgid "" "Error: filesystem block size is smaller than the disk sectorsize.\n" "Aborting XFS copy now.\n" msgstr "" #: .././copy/xfs_copy.c:797 #, c-format msgid "Creating file %s\n" msgstr "" #: .././copy/xfs_copy.c:815 #, c-format msgid "" "%s: a filesystem is mounted on target device \"%s\".\n" "%s cannot copy to mounted filesystems. Aborting\n" msgstr "" #: .././copy/xfs_copy.c:826 #, c-format msgid "%s: couldn't open target \"%s\"\n" msgstr "" #: .././copy/xfs_copy.c:836 #, c-format msgid "%s: cannot grow data section.\n" msgstr "" #: .././copy/xfs_copy.c:844 #, c-format msgid "%s: xfsctl on \"%s\" failed.\n" msgstr "" #: .././copy/xfs_copy.c:863 #, c-format msgid "%s: failed to write last block\n" msgstr "" #: .././copy/xfs_copy.c:865 #, c-format msgid "\tIs target \"%s\" too small?\n" msgstr "" #: .././copy/xfs_copy.c:875 msgid "Couldn't initialize global thread mask\n" msgstr "" #: .././copy/xfs_copy.c:882 msgid "Error initializing wbuf 0\n" msgstr "" #: .././copy/xfs_copy.c:890 msgid "Error initializing btree buf 1\n" msgstr "" #: .././copy/xfs_copy.c:895 msgid "Error creating first semaphore.\n" msgstr "" #: .././copy/xfs_copy.c:910 msgid "Couldn't malloc space for thread args\n" msgstr "" #: .././copy/xfs_copy.c:922 #, c-format msgid "Error creating thread mutex %d\n" msgstr "" #: .././copy/xfs_copy.c:939 #, c-format msgid "Error creating thread for target %d\n" msgstr "" #: .././copy/xfs_copy.c:993 #, c-format msgid "Error: current level %d >= btree levels %d\n" msgstr "" #: .././copy/xfs_copy.c:1012 #, c-format msgid "Bad btree magic 0x%x\n" msgstr "" #: .././copy/xfs_copy.c:1039 msgid "WARNING: source filesystem inconsistent.\n" msgstr "" #: .././copy/xfs_copy.c:1041 msgid " A leaf btree rec isn't a leaf. Aborting now.\n" msgstr "" #: .././db/addr.c:23 msgid "[field-expression]" msgstr "" #: .././db/addr.c:24 msgid "set current address" msgstr "" #: .././db/addr.c:30 msgid "" "\n" " 'addr' uses the given field to set the filesystem address and type\n" "\n" " Examples:\n" "\n" " sb\n" " a rootino - set the type to inode and set position to the root inode\n" " a u.bmx[0].startblock (for inode with blockmap)\n" "\n" msgstr "" #: .././db/addr.c:60 .././db/attrset.c:74 .././db/attrset.c:178 #: .././db/crc.c:66 .././db/type.c:197 .././db/print.c:62 .././db/write.c:98 #: .././db/btdump.c:455 .././db/fuzz.c:87 msgid "no current type\n" msgstr "" #: .././db/addr.c:70 #, c-format msgid "no fields for type %s\n" msgstr "" #: .././db/addr.c:82 msgid "array not allowed for addr command\n" msgstr "" #: .././db/addr.c:91 #, c-format msgid "no next type for field %s\n" msgstr "" #: .././db/addr.c:98 #, c-format msgid "no addr function for field %s (type %s)\n" msgstr "" #: .././db/agf.c:23 .././db/agfl.c:24 .././db/agi.c:23 .././db/sb.c:32 msgid "[agno]" msgstr "" #: .././db/agf.c:24 msgid "set address to agf header" msgstr "" #: .././db/agf.c:88 msgid "" "\n" " set allocation group free block list\n" "\n" " Example:\n" "\n" " agf 2 - move location to AGF in 2nd filesystem allocation group\n" "\n" " Located in the second sector of each allocation group, the AGF\n" " contains the root of two different freespace btrees:\n" " The 'cnt' btree keeps track freespace indexed on section size.\n" " The 'bno' btree tracks sections of freespace indexed on block number.\n" msgstr "" #: .././db/agf.c:113 .././db/agfl.c:94 .././db/agi.c:83 .././db/sb.c:155 #, c-format msgid "bad allocation group number %s\n" msgstr "" #: .././db/agfl.c:25 msgid "set address to agfl block" msgstr "" #: .././db/agfl.c:67 msgid "" "\n" " set allocation group freelist\n" "\n" " Example:\n" "\n" " agfl 5\n" " Located in the fourth sector of each allocation group,\n" " the agfl freelist for internal btree space allocation is maintained\n" " for each allocation group. This acts as a reserved pool of space\n" " separate from the general filesystem freespace (not used for user data).\n" "\n" msgstr "" #: .././db/agi.c:24 msgid "set address to agi header" msgstr "" #: .././db/agi.c:58 msgid "" "\n" " set allocation group inode btree\n" "\n" " Example:\n" "\n" " agi 3 (set location to 3rd allocation group inode btree and type to 'agi')\n" "\n" " Located in the 3rd 512 byte block of each allocation group,\n" " the agi inode btree tracks all used/free inodes in the allocation group.\n" " Inodes are allocated in 16k 'chunks', each btree entry tracks a 'chunk'.\n" "\n" msgstr "" #: .././db/attrset.c:26 msgid "[-r|-s|-p|-u] [-n] [-R|-C] [-v n] name" msgstr "" #: .././db/attrset.c:27 msgid "set the named attribute on the current inode" msgstr "" #: .././db/attrset.c:30 msgid "[-r|-s|-p|-u] [-n] name" msgstr "" #: .././db/attrset.c:31 msgid "remove the named attribute from the current inode" msgstr "" #: .././db/attrset.c:37 msgid "" "\n" " The 'attr_set' and 'attr_remove' commands provide interfaces for debugging\n" " the extended attribute allocation and removal code.\n" " Both commands require an attribute name to be specified, and the attr_set\n" " command allows an optional value length (-v) to be provided as well.\n" " There are 4 namespace flags:\n" " -r -- 'root'\n" " -u -- 'user'\t\t(default)\n" " -s -- 'secure'\n" "\n" " For attr_set, these options further define the type of set operation:\n" " -C -- 'create' - create attribute, fail if it already exists\n" " -R -- 'replace' - replace attribute, fail if it does not exist\n" " The backward compatibility mode 'noattr2' can be emulated (-n) also.\n" "\n" msgstr "" #: .././db/attrset.c:78 .././db/attrset.c:182 msgid "current type is not inode\n" msgstr "" #: .././db/attrset.c:113 #, c-format msgid "bad attr_set valuelen %s\n" msgstr "" #: .././db/attrset.c:119 msgid "bad option for attr_set command\n" msgstr "" #: .././db/attrset.c:125 msgid "too few options for attr_set (no name given)\n" msgstr "" #: .././db/attrset.c:134 #, c-format msgid "cannot allocate buffer (%d)\n" msgstr "" #: .././db/attrset.c:144 .././db/attrset.c:220 #, c-format msgid "failed to iget inode %llu\n" msgstr "" #: .././db/attrset.c:151 #, c-format msgid "failed to set attr %s on inode %llu\n" msgstr "" #: .././db/attrset.c:206 msgid "bad option for attr_remove command\n" msgstr "" #: .././db/attrset.c:212 msgid "too few options for attr_remove (no name given)\n" msgstr "" #: .././db/attrset.c:226 #, c-format msgid "failed to remove attr %s from inode %llu\n" msgstr "" #: .././db/bmap.c:27 msgid "[-ad] [block [len]]" msgstr "" #: .././db/bmap.c:28 msgid "show block map for current file" msgstr "" #: .././db/bmap.c:140 .././db/inode.c:414 .././db/block.c:77 msgid "no current inode\n" msgstr "" #: .././db/bmap.c:153 msgid "bad option for bmap command\n" msgstr "" #: .././db/bmap.c:170 #, c-format msgid "bad block number for bmap %s\n" msgstr "" #: .././db/bmap.c:178 #, c-format msgid "bad len for bmap %s\n" msgstr "" #: .././db/bmap.c:201 #, c-format msgid "%s offset %lld startblock %llu (%u/%u) count %llu flag %u\n" msgstr "" #: .././db/bmap.c:203 .././db/check.c:2223 .././db/check.c:2235 #: .././db/check.c:2262 .././io/fsmap.c:92 .././repair/dinode.c:40 msgid "data" msgstr "" #: .././db/bmap.c:203 .././db/check.c:2223 .././db/check.c:2235 #: .././db/check.c:2262 .././io/fsmap.c:92 .././repair/dinode.c:41 msgid "attr" msgstr "" #: .././db/btblock.c:152 #, c-format msgid "Bad btree magic 0x%x; coercing to %s.\n" msgstr "" #: .././db/sb.c:33 msgid "set current address to sb header" msgstr "" #: .././db/sb.c:35 msgid "[uuid]" msgstr "" #: .././db/sb.c:36 msgid "write/print FS uuid" msgstr "" #: .././db/sb.c:38 msgid "[label]" msgstr "" #: .././db/sb.c:39 msgid "write/print FS label" msgstr "" #: .././db/sb.c:41 msgid "[feature | [vnum fnum]]" msgstr "" #: .././db/sb.c:42 msgid "set feature bit(s) in the sb version field" msgstr "" #: .././db/sb.c:128 msgid "" "\n" " set allocation group superblock\n" "\n" " Example:\n" "\n" " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" "\n" " Located in the first sector of each allocation group, the superblock\n" " contains the base information for the filesystem.\n" " The superblock in allocation group 0 is the primary. The copies in the\n" " remaining allocation groups only serve as backup for filesystem recovery.\n" " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" "\n" msgstr "" #: .././db/sb.c:187 #, c-format msgid "can't read superblock for AG %u\n" msgstr "" #: .././db/sb.c:195 #, c-format msgid "bad sb magic # %#x in AG %u\n" msgstr "" #: .././db/sb.c:200 #, c-format msgid "bad sb version # %#x in AG %u\n" msgstr "" #: .././db/sb.c:205 .././db/check.c:3874 msgid "mkfs not completed successfully\n" msgstr "" #: .././db/sb.c:224 msgid "aborting - external log specified for FS with an internal log\n" msgstr "" #: .././db/sb.c:230 msgid "aborting - no external log specified for FS with an external log\n" msgstr "" #: .././db/sb.c:240 msgid "ERROR: cannot find log head/tail, run xfs_repair\n" msgstr "" #: .././db/sb.c:244 #, c-format msgid "" "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running %s. If you are unable to mount the filesystem, then use\n" "the xfs_repair -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n" msgstr "" #: .././db/sb.c:272 msgid "Clearing log and setting UUID\n" msgstr "" #: .././db/sb.c:281 msgid "ERROR: cannot clear the log\n" msgstr "" #: .././db/sb.c:293 msgid "" "\n" " write/print FS uuid\n" "\n" " Example:\n" "\n" " 'uuid' - print UUID\n" " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" " 'uuid generate' - generate and write\n" " 'uuid rewrite' - copy UUID from SB 0\n" "\n" "The print function checks the UUID in each SB and will warn if the UUIDs\n" "differ between AGs (the log is not checked). The write commands will\n" "set the uuid in all AGs to either a specified value, a newly generated\n" "value or the value found in the first superblock (SB 0) respectively.\n" "As a side effect of writing the UUID, the log is cleared (which is fine\n" "on a CLEANLY unmounted FS).\n" "\n" msgstr "" #: .././db/sb.c:371 .././db/sb.c:534 msgid "invalid parameters\n" msgstr "" #: .././db/sb.c:378 .././db/sb.c:541 .././db/sb.c:711 #, c-format msgid "%s: not in expert mode, writing disabled\n" msgstr "" #: .././db/sb.c:390 msgid "failed to read UUID from AG 0\n" msgstr "" #: .././db/sb.c:395 #, c-format msgid "old UUID = %s\n" msgstr "" #: .././db/sb.c:409 msgid "invalid UUID\n" msgstr "" #: .././db/sb.c:418 .././db/sb.c:546 .././db/sb.c:798 msgid "writing all SBs\n" msgstr "" #: .././db/sb.c:421 #, c-format msgid "failed to set UUID in AG %d\n" msgstr "" #: .././db/sb.c:426 #, c-format msgid "new UUID = %s\n" msgstr "" #: .././db/sb.c:434 #, c-format msgid "failed to read UUID from AG %d\n" msgstr "" #: .././db/sb.c:440 #, c-format msgid "warning: UUID in AG %d differs to the primary SB\n" msgstr "" #: .././db/sb.c:451 msgid "warning - external log specified for FS with an internal log\n" msgstr "" #: .././db/sb.c:454 msgid "warning - no external log specified for FS with an external log\n" msgstr "" #: .././db/sb.c:459 #, c-format msgid "UUID = %s\n" msgstr "" #: .././db/sb.c:470 msgid "" "\n" " write/print FS label\n" "\n" " Example:\n" "\n" " 'label' - print label\n" " 'label 123456789012' - write label\n" " 'label --' - write an empty label\n" "\n" "The print function checks the label in each SB and will warn if the labels\n" "differ between AGs. The write commands will set the label in all AGs to the\n" "specified value. The maximum length of a label is 12 characters - use of a\n" "longer label will result in truncation and a warning will be issued.\n" "\n" msgstr "" #: .././db/sb.c:507 #, c-format msgid "%s: truncating label length from %d to %d\n" msgstr "" #: .././db/sb.c:549 #, c-format msgid "failed to set label in AG %d\n" msgstr "" #: .././db/sb.c:552 #, c-format msgid "new label = \"%s\"\n" msgstr "" #: .././db/sb.c:559 #, c-format msgid "failed to read label in AG %d\n" msgstr "" #: .././db/sb.c:565 #, c-format msgid "warning: AG %d label differs\n" msgstr "" #: .././db/sb.c:567 #, c-format msgid "label = \"%s\"\n" msgstr "" #: .././db/sb.c:577 msgid "" "\n" " set/print feature bits in sb version\n" "\n" " Example:\n" "\n" " 'version' - print current feature bits\n" " 'version extflg' - enable unwritten extents\n" " 'version attr1' - enable v1 inline extended attributes\n" " 'version attr2' - enable v2 inline extended attributes\n" " 'version log2' - enable v2 log format\n" "\n" "The version function prints currently enabled features for a filesystem\n" "according to the version field of its primary superblock.\n" "It can also be used to enable selected features, such as support for\n" "unwritten extents. The updated version is written into all AGs.\n" "\n" msgstr "" #: .././db/sb.c:605 msgid "Superblock has mismatched features2 fields, skipping modification\n" msgstr "" #: .././db/sb.c:732 msgid "unwritten extents flag is already enabled\n" msgstr "" #: .././db/sb.c:739 msgid "unwritten extents always enabled for v5 superblocks.\n" msgstr "" #: .././db/sb.c:756 msgid "version 2 log format is already in use\n" msgstr "" #: .././db/sb.c:763 msgid "Version 2 logs always enabled for v5 superblocks.\n" msgstr "" #: .././db/sb.c:768 #, c-format msgid "%s: Cannot change %s on v5 superblocks.\n" msgstr "" #: .././db/sb.c:792 #, c-format msgid "%s: invalid version change command \"%s\"\n" msgstr "" #: .././db/sb.c:801 #, c-format msgid "failed to set versionnum in AG %d\n" msgstr "" #: .././db/sb.c:819 #, c-format msgid "versionnum [0x%x+0x%x] = %s\n" msgstr "" #: .././db/crc.c:27 msgid "manipulate crc values for V5 filesystem structures" msgstr "" #: .././db/crc.c:40 msgid "" "\n" " 'crc' validates, invalidates, or recalculates the crc value for\n" " the current on-disk metadata structures in Version 5 filesystems.\n" "\n" " Usage: \"crc [-i|-r|-v]\"\n" "\n" msgstr "" #: .././db/crc.c:71 #, c-format msgid "current type (%s) is not a structure\n" msgstr "" #: .././db/crc.c:88 msgid "bad option for crc command\n" msgstr "" #: .././db/crc.c:95 msgid "crc command accepts only one option\n" msgstr "" #: .././db/crc.c:101 #, c-format msgid "%s not in expert mode, writing disabled\n" msgstr "" #: .././db/crc.c:118 #, c-format msgid "No CRC field found for type %s\n" msgstr "" #: .././db/crc.c:125 .././db/write.c:688 .././db/fuzz.c:408 msgid "parsing error\n" msgstr "" #: .././db/crc.c:161 msgid "Invalidating CRC:\n" msgstr "" #: .././db/crc.c:163 msgid "Recalculating CRC:\n" msgstr "" #: .././db/crc.c:171 msgid "Verifying CRC:\n" msgstr "" #: .././db/debug.c:15 msgid "[flagbits]" msgstr "" #: .././db/debug.c:16 msgid "set debug option bits" msgstr "" #: .././db/debug.c:30 #, c-format msgid "bad value for debug %s\n" msgstr "" #: .././db/frag.c:161 #, c-format msgid "actual %llu, ideal %llu, fragmentation factor %.2f%%\n" msgstr "" #: .././db/frag.c:163 msgid "Note, this number is largely meaningless.\n" msgstr "" #: .././db/frag.c:165 #, c-format msgid "Files on this filesystem average %.2f extents per file\n" msgstr "" #: .././db/frag.c:206 msgid "bad option for frag command\n" msgstr "" #: .././db/frag.c:342 #, c-format msgid "inode %lld actual %lld ideal %lld\n" msgstr "" #: .././db/frag.c:358 .././db/check.c:3886 #, c-format msgid "can't read agf block for ag %u\n" msgstr "" #: .././db/frag.c:367 .././db/check.c:3914 #, c-format msgid "can't read agi block for ag %u\n" msgstr "" #: .././db/frag.c:390 .././db/frag.c:413 .././db/freesp.c:274 #: .././db/check.c:4111 .././db/check.c:4139 #, c-format msgid "can't read btree block %u/%u\n" msgstr "" #: .././db/frag.c:436 .././db/frag.c:446 #, c-format msgid "invalid numrecs (%u) in %s block\n" msgstr "" #: .././db/frag.c:504 .././db/check.c:4467 #, c-format msgid "can't read inode block %u/%u\n" msgstr "" #: .././db/info.c:16 msgid "" "\n" " Pretty-prints the filesystem geometry as derived from the superblock.\n" " The output has the same format as mkfs.xfs, xfs_info, and other utilities.\n" "\n" msgstr "" #: .././db/info.c:44 msgid "pretty-print superblock info" msgstr "" #: .././db/inode.c:409 #, c-format msgid "bad value for inode number %s\n" msgstr "" #: .././db/inode.c:416 #, c-format msgid "current inode number is %lld\n" msgstr "" #: .././db/inode.c:651 #, c-format msgid "bad inode number %lld\n" msgstr "" #: .././db/inode.c:696 #, c-format msgid "Metadata CRC error detected for ino %lld\n" msgstr "" #: .././db/echo.c:15 msgid "[args]..." msgstr "" #: .././db/echo.c:16 msgid "echo arguments" msgstr "" #: .././db/faddr.c:28 .././db/faddr.c:51 msgid "no current allocation group, cannot set new addr\n" msgstr "" #: .././db/faddr.c:33 .././db/faddr.c:105 .././db/faddr.c:136 #: .././db/faddr.c:168 .././db/faddr.c:190 .././db/faddr.c:220 #: .././db/faddr.c:250 .././db/faddr.c:304 .././db/faddr.c:323 msgid "null block number, cannot set new addr\n" msgstr "" #: .././db/faddr.c:56 .././db/faddr.c:341 .././db/faddr.c:358 #: .././db/faddr.c:375 msgid "null inode number, cannot set new addr\n" msgstr "" #: .././db/faddr.c:76 msgid "null attribute block number, cannot set new addr\n" msgstr "" #: .././db/faddr.c:82 msgid "attribute block is unmapped\n" msgstr "" #: .././db/faddr.c:111 .././db/faddr.c:143 .././db/faddr.c:196 #: .././db/faddr.c:227 msgid "file block is unmapped\n" msgstr "" #: .././db/faddr.c:273 msgid "null directory block number, cannot set new addr\n" msgstr "" #: .././db/faddr.c:280 msgid "directory block is unmapped\n" msgstr "" #: .././db/type.c:38 msgid "[newtype]" msgstr "" #: .././db/type.c:39 msgid "set/show current data type" msgstr "" #: .././db/type.c:199 #, c-format msgid "current type is \"%s\"\n" msgstr "" #: .././db/type.c:201 msgid "" "\n" " supported types are:\n" " " msgstr "" #: .././db/type.c:218 #, c-format msgid "no such type %s\n" msgstr "" #: .././db/type.c:221 msgid "no current object\n" msgstr "" #: .././db/type.c:274 msgid "string fuzzing not supported.\n" msgstr "" #: .././db/type.c:294 msgid "use 'blocktrash' or 'write' to fuzz a block.\n" msgstr "" #: .././db/type.c:310 msgid "text writing/fuzzing not supported.\n" msgstr "" #: .././db/btheight.c:46 msgid "" "\n" " For a given number of btree records and a btree type, report the number of\n" " records and blocks for each level of the btree, and the total btree size.\n" " The btree type must be given after the options. A raw btree geometry can\n" " be provided in the format \"record_bytes:key_bytes:ptr_bytes:header_type\"\n" " where header_type is one of \"short\", \"long\", \"shortcrc\", or \"longcrc" "\".\n" "\n" " Options:\n" " -b -- Override the btree block size.\n" " -n -- Number of records we want to store.\n" " -w max -- Show only the best case scenario.\n" " -w min -- Show only the worst case scenario.\n" "\n" " Supported btree types:\n" " " msgstr "" #: .././db/btheight.c:90 #, c-format msgid "level %u: %llu record%s, %llu block%s\n" msgstr "" #: .././db/btheight.c:104 #, c-format msgid "%u level%s, %llu block%s total\n" msgstr "" #: .././db/btheight.c:133 #, c-format msgid "%s: record size not found.\n" msgstr "" #: .././db/btheight.c:142 #, c-format msgid "%s: record size cannot be zero.\n" msgstr "" #: .././db/btheight.c:148 #, c-format msgid "%s: key size not found.\n" msgstr "" #: .././db/btheight.c:157 #, c-format msgid "%s: key size cannot be zero.\n" msgstr "" #: .././db/btheight.c:163 #, c-format msgid "%s: pointer size not found.\n" msgstr "" #: .././db/btheight.c:172 #, c-format msgid "%s: pointer size cannot be zero.\n" msgstr "" #: .././db/btheight.c:178 #, c-format msgid "%s: header type not found.\n" msgstr "" #: .././db/btheight.c:190 #, c-format msgid "%s: unrecognized btree header type." msgstr "" #: .././db/btheight.c:197 #, c-format msgid "%s: record size must be less than selected block size (%u bytes).\n" msgstr "" #: .././db/btheight.c:204 #, c-format msgid "%s: key size must be less than selected block size (%u bytes).\n" msgstr "" #: .././db/btheight.c:211 #, c-format msgid "%s: pointer size must be less than selected block size (%u bytes).\n" msgstr "" #: .././db/btheight.c:219 #, c-format msgid "%s: unrecognized raw btree geometry." msgstr "" #: .././db/btheight.c:253 #, c-format msgid "" "%s: cannot calculate best case scenario due to leaf geometry underflow.\n" msgstr "" #: .././db/btheight.c:260 #, c-format msgid "" "%s: cannot calculate best case scenario due to node geometry underflow.\n" msgstr "" #: .././db/btheight.c:266 #, c-format msgid "" "%s: best case per %u-byte block: %u records (leaf) / %u keyptrs (node)\n" msgstr "" #: .././db/btheight.c:279 #, c-format msgid "" "%s: cannot calculate worst case scenario due to leaf geometry underflow.\n" msgstr "" #: .././db/btheight.c:286 #, c-format msgid "" "%s: cannot calculate worst case scenario due to node geometry underflow.\n" msgstr "" #: .././db/btheight.c:292 #, c-format msgid "" "%s: worst case per %u-byte block: %u records (leaf) / %u keyptrs (node)\n" msgstr "" #: .././db/btheight.c:347 #, c-format msgid "Number of records must be greater than zero.\n" msgstr "" #: .././db/btheight.c:353 #, c-format msgid "The largest block size this command will consider is %u bytes.\n" msgstr "" #: .././db/btheight.c:360 #, c-format msgid "The smallest block size this command will consider is 128 bytes.\n" msgstr "" #: .././db/btheight.c:378 msgid "compute btree heights" msgstr "" #: .././db/freesp.c:99 .././spaceman/freesp.c:352 #, c-format msgid "total free extents %lld\n" msgstr "" #: .././db/freesp.c:100 .././spaceman/freesp.c:353 #, c-format msgid "total free blocks %lld\n" msgstr "" #: .././db/freesp.c:101 .././spaceman/freesp.c:354 #, c-format msgid "average free extent size %g\n" msgstr "" #: .././db/freesp.c:195 msgid "" "freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... [-m binmult]\n" msgstr "" #: .././db/freesp.c:247 .././db/check.c:4069 .././repair/scan.c:2147 #, c-format msgid "agf %d freelist blocks bad, skipping freelist scan\n" msgstr "" #: .././db/freesp.c:415 .././spaceman/freesp.c:120 msgid "from" msgstr "" #: .././db/freesp.c:415 .././spaceman/freesp.c:120 msgid "to" msgstr "" #: .././db/freesp.c:415 .././repair/progress.c:27 .././spaceman/freesp.c:120 msgid "extents" msgstr "" #: .././db/freesp.c:415 .././repair/progress.c:19 .././spaceman/freesp.c:120 msgid "blocks" msgstr "" #: .././db/freesp.c:415 .././spaceman/freesp.c:120 msgid "pct" msgstr "" #: .././db/fsmap.c:25 #, c-format msgid "" "%llu: %u/%u len %u owner %lld offset %llu bmbt %d attrfork %d extflag %d\n" msgstr "" #: .././db/fsmap.c:72 #, c-format msgid "Error %d while reading AGF.\n" msgstr "" #: .././db/fsmap.c:79 msgid "Not enough memory.\n" msgstr "" #: .././db/fsmap.c:89 #, c-format msgid "Error %d while querying fsmap btree.\n" msgstr "" #: .././db/fsmap.c:113 msgid "Filesystem does not support reverse mapping btree.\n" msgstr "" #: .././db/fsmap.c:120 msgid "Bad option for fsmap command.\n" msgstr "" #: .././db/fsmap.c:128 #, c-format msgid "Bad fsmap start_fsb %s.\n" msgstr "" #: .././db/fsmap.c:136 #, c-format msgid "Bad fsmap end_fsb %s.\n" msgstr "" #: .././db/fsmap.c:148 msgid "[start_fsb] [end_fsb]" msgstr "" #: .././db/fsmap.c:149 msgid "display reverse mapping(s)" msgstr "" #: .././db/hash.c:19 msgid "string" msgstr "" #: .././db/hash.c:20 msgid "calculate hash value" msgstr "" #: .././db/hash.c:26 msgid "" "\n" " 'hash' prints out the calculated hash value for a string using the\n" "directory/attribute code hash function.\n" "\n" " Usage: \"hash \"\n" "\n" msgstr "" #: .././db/help.c:18 .././db/io.c:39 .././libxcmd/help.c:81 msgid "[command]" msgstr "" #: .././db/help.c:19 .././libxcmd/help.c:82 msgid "help for one or all commands" msgstr "" #: .././db/help.c:28 .././libxcmd/help.c:22 #, c-format msgid "" "\n" "Use 'help commandname' for extended help.\n" msgstr "" #: .././db/help.c:44 .././db/command.c:73 .././libxcmd/help.c:38 #, c-format msgid "command %s not found\n" msgstr "" #: .././db/help.c:77 #, c-format msgid "(or %s) " msgstr "" #: .././db/input.c:31 msgid "source-file" msgstr "" #: .././db/input.c:32 msgid "get commands from source-file" msgstr "" #: .././db/input.c:319 #, c-format msgid "can't open %s\n" msgstr "" #: .././db/io.c:37 msgid "pop location from the stack" msgstr "" #: .././db/io.c:40 msgid "push location to the stack" msgstr "" #: .././db/io.c:43 msgid "view the location stack" msgstr "" #: .././db/io.c:46 msgid "move forward to next entry in the position ring" msgstr "" #: .././db/io.c:49 msgid "move to the previous location in the position ring" msgstr "" #: .././db/io.c:52 msgid "show position ring or move to a specific entry" msgstr "" #: .././db/io.c:82 #, c-format msgid "can't set block offset to %d\n" msgstr "" #: .././db/io.c:95 msgid "can't pop anything from I/O stack\n" msgstr "" #: .././db/io.c:129 msgid "" "\n" " Changes the address and data type to the first entry on the stack.\n" "\n" msgstr "" #: .././db/io.c:143 #, c-format msgid "\tbyte offset %lld, length %d\n" msgstr "" #: .././db/io.c:144 #, c-format msgid "\tbuffer block %lld (fsbno %lld), %d bb%s\n" msgstr "" #: .././db/io.c:148 .././db/io.c:535 #, c-format msgid "\tblock map" msgstr "" #: .././db/io.c:154 #, c-format msgid "\tinode %lld, dir inode %lld, type %s\n" msgstr "" #: .././db/io.c:155 .././logprint/log_misc.c:95 .././mkfs/xfs_mkfs.c:2674 #: .././libfrog/fsgeom.c:67 #, c-format msgid "none" msgstr "" #: .././db/io.c:165 msgid "no entries in location ring.\n" msgstr "" #: .././db/io.c:169 msgid " type bblock bblen fsbno inode\n" msgstr "" #: .././db/io.c:236 #, c-format msgid "no such command %s\n" msgstr "" #: .././db/io.c:240 #, c-format msgid "no push form allowed for %s\n" msgstr "" #: .././db/io.c:257 msgid "" "\n" " Allows you to push the current address and data type on the stack for\n" " later return. 'push' also accepts an additional command to execute after\n" " storing the current address (ex: 'push a rootino' from the superblock).\n" "\n" msgstr "" #: .././db/io.c:273 .././db/io.c:313 msgid "ring is empty\n" msgstr "" #: .././db/io.c:277 msgid "no further entries\n" msgstr "" #: .././db/io.c:296 msgid "" "\n" " The 'forward' ('f') command moves to the next location in the position\n" " ring, updating the current position and data type. If the current " "location\n" " is the top entry in the ring, then the 'forward' command will have\n" " no effect.\n" "\n" msgstr "" #: .././db/io.c:317 msgid "no previous entries\n" msgstr "" #: .././db/io.c:336 msgid "" "\n" " The 'back' ('b') command moves to the previous location in the position\n" " ring, updating the current position and data type. If the current " "location\n" " is the last entry in the ring, then the 'back' command will have no " "effect.\n" "\n" msgstr "" #: .././db/io.c:359 #, c-format msgid "invalid entry: %d\n" msgstr "" #: .././db/io.c:378 #, c-format msgid "" "\n" " The position ring automatically keeps track of each disk location and\n" " structure type for each change of position you make during your xfs_db\n" " session. The last %d most recent entries are kept in the ring.\n" "\n" " To display the current list of ring entries type 'ring' by itself on\n" " the command line. The entry highlighted by an asterisk ('*') is the\n" " current entry.\n" "\n" " To move to another entry in the ring type 'ring ' where is\n" " your desired entry from the ring position list.\n" "\n" " You may also use the 'forward' ('f') or 'back' ('b') commands to move\n" " to the previous or next entry in the ring, respectively.\n" "\n" " Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n" " location implicitly. Use the 'push' and 'pop' commands if you wish to\n" " store a specific location explicitly for later return.\n" "\n" msgstr "" #: .././db/io.c:431 .././db/io.c:447 #, c-format msgid "write error: %s\n" msgstr "" #: .././db/io.c:437 .././db/io.c:453 #, c-format msgid "read error: %s\n" msgstr "" #: .././db/io.c:476 msgid "nothing to write\n" msgstr "" #: .././db/io.c:521 msgid "set_cur no stack element to set\n" msgstr "" #: .././db/io.c:534 #, c-format msgid "xfs_db got a bbmap for %lld\n" msgstr "" #: .././db/io.c:634 msgid "" "\n" " The stack is used to explicitly store your location and data type\n" " for later return. The 'push' operation stores the current address\n" " and type on the stack, the 'pop' operation returns you to the\n" " position and datatype of the top entry on the stack.\n" "\n" " The 'stack' allows explicit location saves, see 'ring' for implicit\n" " position tracking.\n" "\n" msgstr "" #: .././db/logformat.c:78 msgid "The log is dirty. Please mount to replay the log.\n" msgstr "" #: .././db/logformat.c:110 msgid "" "\n" " The 'logformat' command reformats (clears) the log to the specified log\n" " cycle and log stripe unit. If the log cycle is not specified, the log is\n" " reformatted to the current cycle. If the log stripe unit is not specified,\n" " the stripe unit from the filesystem superblock is used.\n" "\n" msgstr "" #: .././db/logformat.c:126 msgid "[-c cycle] [-s sunit]" msgstr "" #: .././db/logformat.c:127 msgid "reformat the log" msgstr "" #: .././db/logformat.c:145 #, c-format msgid "type %d logres %u logcount %d flags 0x%x\n" msgstr "" #: .././db/logformat.c:173 msgid "" "\n" " The 'logres' command prints information about all log reservation types.\n" " This includes the reservation space, the intended transaction roll count,\n" " and the reservation flags, if any.\n" "\n" msgstr "" #: .././db/logformat.c:189 msgid "dump log reservations" msgstr "" #: .././db/malloc.c:15 #, c-format msgid "%s: out of memory\n" msgstr "" #: .././db/output.c:18 msgid "[stop|start ]" msgstr "" #: .././db/output.c:19 msgid "start or stop logging to a file" msgstr "" #: .././db/output.c:56 #, c-format msgid "logging to %s\n" msgstr "" #: .././db/output.c:58 .././db/output.c:65 msgid "no log file\n" msgstr "" #: .././db/output.c:68 #, c-format msgid "already logging to %s\n" msgstr "" #: .././db/output.c:72 #, c-format msgid "can't open %s for writing\n" msgstr "" #: .././db/output.c:78 msgid "bad log command, ignored\n" msgstr "" #: .././db/print.c:29 msgid "[value]..." msgstr "" #: .././db/print.c:30 msgid "print field values" msgstr "" #: .././db/print.c:67 #, c-format msgid "no print function for type %s\n" msgstr "" #: .././db/print.c:152 msgid "(empty)\n" msgstr "" #: .././db/print.c:154 msgid "Unrecognized metadata or type mismatch\n" msgstr "" #: .././db/print.c:216 msgid "(empty)" msgstr "" #: .././db/print.c:276 msgid "no arguments allowed\n" msgstr "" #: .././db/quit.c:15 msgid "exit xfs_db" msgstr "" #: .././db/write.c:29 msgid "[-c|-d] [field or value]..." msgstr "" #: .././db/write.c:30 msgid "write value to disk" msgstr "" #: .././db/write.c:46 msgid "" "\n" " The 'write' command takes on different personalities depending on the\n" " type of object being worked with.\n" "\n" " Write has 3 modes:\n" " 'struct mode' - is active anytime you're looking at a filesystem object\n" " which contains individual fields (ex: an inode).\n" " 'data mode' - is active anytime you set a disk address directly or set\n" " the type to 'data'.\n" " 'string mode' - only used for writing symlink blocks.\n" "\n" " Examples:\n" " Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n" " 'write fname \"hello\\000\"' - write superblock fname.\n" " (note: in struct mode strings are not null terminated)\n" " 'write fname #6669736800' - write superblock fname with " "hex.\n" " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n" " - write superblock uuid.\n" " Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n" " 'write lshift 3' - shift the block 3 bytes to the left\n" " 'write sequence 1 5' - write a cycle of number [1-5] through\n" " the entire block.\n" " String mode: 'write \"This_is_a_filename\" - write null terminated " "string.\n" "\n" " In data mode type 'write' by itself for a list of specific commands.\n" "\n" " Specifying the -c option will allow writes of invalid (corrupt) data with\n" " an invalid CRC. Specifying the -d option will allow writes of invalid " "data,\n" " but still recalculate the CRC so we are forced to check and detect the\n" " invalid data appropriately.\n" "\n" msgstr "" #: .././db/write.c:92 #, c-format msgid "%s started in read only mode, writing disabled\n" msgstr "" #: .././db/write.c:104 #, c-format msgid "no handler function for type %s, write unsupported.\n" msgstr "" #: .././db/write.c:118 msgid "bad option for write command\n" msgstr "" #: .././db/write.c:124 .././db/fuzz.c:113 msgid "Cannot specify both -c and -d options\n" msgstr "" #: .././db/write.c:131 .././db/fuzz.c:120 msgid "Cannot recalculate CRCs on this type of object\n" msgstr "" #: .././db/write.c:158 msgid "Allowing write of corrupted data and bad CRC\n" msgstr "" #: .././db/write.c:161 .././db/write.c:164 msgid "Allowing write of corrupted data with good CRC\n" msgstr "" #: .././db/write.c:220 .././db/write.c:249 .././db/write.c:279 #: .././db/write.c:312 .././db/write.c:348 .././db/write.c:397 #: .././db/write.c:426 #, c-format msgid "length (%d) too large for data block size (%d)" msgstr "" #: .././db/write.c:668 msgid "usage: write fieldname value\n" msgstr "" #: .././db/write.c:674 .././db/fuzz.c:386 #, c-format msgid "unable to parse '%s'.\n" msgstr "" #: .././db/write.c:723 #, c-format msgid "unable to convert value '%s'.\n" msgstr "" #: .././db/write.c:747 msgid "usage (in string mode): write \"string...\"\n" msgstr "" #: .././db/write.c:789 msgid "write: invalid subcommand\n" msgstr "" #: .././db/write.c:794 #, c-format msgid "write %s: invalid number of arguments\n" msgstr "" #: .././db/write.c:818 msgid "usage: write (in data mode)\n" msgstr "" #: .././db/metadump.c:40 msgid "[-a] [-e] [-g] [-m max_extent] [-w] [-o] filename" msgstr "" #: .././db/metadump.c:41 msgid "dump metadata to a file" msgstr "" #: .././db/metadump.c:73 #, c-format msgid "" "\n" " The 'metadump' command dumps the known metadata to a compact file suitable\n" " for compressing and sending to an XFS maintainer for corruption analysis \n" " or xfs_repair failures.\n" "\n" " Options:\n" " -a -- Copy full metadata blocks without zeroing unused space\n" " -e -- Ignore read errors and keep going\n" " -g -- Display dump progress\n" " -m -- Specify max extent size in blocks to copy (default = %d blocks)\n" " -o -- Don't obfuscate names and extended attributes\n" " -w -- Show warnings of bad metadata information\n" "\n" msgstr "" #: .././db/metadump.c:2901 msgid "" "Warning: log recovery of an obfuscated metadata image can leak unobfuscated " "metadata and/or cause image corruption. If possible, please mount the " "filesystem to clean the log, or disable obfuscation." msgstr "" #: .././db/metadump.c:2909 msgid "Could not discern log; image will contain unobfuscated metadata in log." msgstr "" #: .././db/attr.c:624 .././db/attr.c:659 msgid "Unknown attribute buffer type!\n" msgstr "" #: .././db/attr.c:671 msgid "Writing unknown attribute buffer type!\n" msgstr "" #: .././db/block.c:31 .././db/block.c:37 msgid "filoff" msgstr "" #: .././db/block.c:32 msgid "set address to file offset (attr fork)" msgstr "" #: .././db/block.c:34 msgid "[d]" msgstr "" #: .././db/block.c:35 msgid "set address to daddr value" msgstr "" #: .././db/block.c:38 msgid "set address to file offset (data fork)" msgstr "" #: .././db/block.c:40 msgid "[fsb]" msgstr "" #: .././db/block.c:41 msgid "set address to fsblock value" msgstr "" #: .././db/block.c:47 msgid "" "\n" " Example:\n" "\n" " 'ablock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's attribute fork. The filesystem block size is specified in\n" " the superblock.\n" "\n" msgstr "" #: .././db/block.c:70 .././db/block.c:170 #, c-format msgid "bad block number %s\n" msgstr "" #: .././db/block.c:83 msgid "no attribute data for file\n" msgstr "" #: .././db/block.c:89 msgid "file attr block is unmapped\n" msgstr "" #: .././db/block.c:112 msgid "" "\n" " Example:\n" "\n" " 'daddr 102' - sets position to the 102nd absolute disk block\n" " (512 byte block).\n" msgstr "" #: .././db/block.c:128 #, c-format msgid "current daddr is %lld\n" msgstr "" #: .././db/block.c:134 #, c-format msgid "bad daddr %s\n" msgstr "" #: .././db/block.c:146 msgid "" "\n" " Example:\n" "\n" " 'dblock 23' - sets the file position to the 23rd filesystem block in\n" " the inode's data fork. The filesystem block size is specified in the\n" " superblock.\n" "\n" msgstr "" #: .././db/block.c:178 msgid "no type for file data\n" msgstr "" #: .././db/block.c:185 msgid "file data block is unmapped\n" msgstr "" #: .././db/block.c:203 msgid "" "\n" " Example:\n" "\n" " 'fsblock 1023' - sets the file position to the 1023rd filesystem block.\n" " The filesystem block size is specified in the superblock and set during\n" " mkfs time. Offset is absolute (not AG relative).\n" "\n" msgstr "" #: .././db/block.c:222 #, c-format msgid "current fsblock is %lld\n" msgstr "" #: .././db/block.c:228 .././db/block.c:234 #, c-format msgid "bad fsblock %s\n" msgstr "" #: .././db/btdump.c:18 msgid "" "\n" " If the cursor points to a btree block, 'btdump' dumps the btree\n" " downward from that block. If the cursor points to an inode,\n" " the data fork btree root is selected by default. If the cursor\n" " points to a directory or extended attribute btree node, the tree\n" " will be printed downward from that block.\n" "\n" " Options:\n" " -a -- Display an inode's extended attribute fork btree.\n" " -i -- Print internal btree nodes.\n" "\n" msgstr "" #: .././db/btdump.c:78 .././db/btdump.c:381 #, c-format msgid "%s level %u block %u daddr %llu\n" msgstr "" #: .././db/btdump.c:171 msgid "attr fork not in btree format\n" msgstr "" #: .././db/btdump.c:177 msgid "data fork not in btree format\n" msgstr "" #: .././db/btdump.c:416 #, c-format msgid "Current location is not part of a dir/attr btree.\n" msgstr "" #: .././db/btdump.c:467 msgid "bad option for btdump command\n" msgstr "" #: .././db/btdump.c:473 msgid "bad options for btdump command\n" msgstr "" #: .././db/btdump.c:477 msgid "attrfork flag doesn't apply here\n" msgstr "" #: .././db/btdump.c:499 #, c-format msgid "type \"%s\" is not a btree type or inode\n" msgstr "" #: .././db/btdump.c:507 msgid "dump btree" msgstr "" #: .././db/command.c:77 #, c-format msgid "bad argument count %d to %s, expected " msgstr "" #: .././db/command.c:79 #, c-format msgid "at least %d" msgstr "" #: .././db/command.c:83 #, c-format msgid "between %d and %d" msgstr "" #: .././db/command.c:84 msgid " arguments\n" msgstr "" #: .././db/convert.c:158 #, c-format msgid "bad argument count %d to convert, expected 3,5,7,9 arguments\n" msgstr "" #: .././db/convert.c:163 .././db/convert.c:170 #, c-format msgid "unknown conversion type %s\n" msgstr "" #: .././db/convert.c:174 msgid "result type same as argument\n" msgstr "" #: .././db/convert.c:178 #, c-format msgid "conflicting conversion type %s\n" msgstr "" #: .././db/convert.c:256 #, c-format msgid "%s is not a number\n" msgstr "" #: .././db/dir2.c:1007 #, c-format msgid "Unknown directory buffer type! %x %x\n" msgstr "" #: .././db/dir2.c:1051 msgid "Unknown directory buffer type!\n" msgstr "" #: .././db/dir2.c:1063 msgid "Writing unknown directory buffer type!\n" msgstr "" #: .././db/dquot.c:25 msgid "[-g|-p|-u] id" msgstr "" #: .././db/dquot.c:26 msgid "" "set current address to a group, project or user quota block for given ID" msgstr "" #: .././db/dquot.c:117 msgid "bad option for dquot command\n" msgstr "" #: .././db/dquot.c:121 msgid "project" msgstr "" #: .././db/dquot.c:121 msgid "group" msgstr "" #: .././db/dquot.c:121 msgid "user" msgstr "" #: .././db/dquot.c:123 #, c-format msgid "dquot command requires one %s id argument\n" msgstr "" #: .././db/dquot.c:133 #, c-format msgid "no %s quota inode present\n" msgstr "" #: .././db/dquot.c:138 #, c-format msgid "bad %s id for dquot %s\n" msgstr "" #: .././db/dquot.c:150 #, c-format msgid "no %s quota data for id %d\n" msgstr "" #: .././db/flist.c:137 #, c-format msgid "field %s not found\n" msgstr "" #: .././db/flist.c:147 #, c-format msgid "no elements in %s\n" msgstr "" #: .././db/flist.c:153 #, c-format msgid "indices %d-%d for field %s out of range %d-%d\n" msgstr "" #: .././db/flist.c:161 #, c-format msgid "index %d for field %s out of range %d-%d\n" msgstr "" #: .././db/flist.c:175 #, c-format msgid "field %s is not an array\n" msgstr "" #: .././db/flist.c:188 #, c-format msgid "field %s has no subfields\n" msgstr "" #: .././db/flist.c:208 #, c-format msgid "fl@%p:\n" msgstr "" #: .././db/flist.c:209 #, c-format msgid "\tname=%s, fld=%p, child=%p, sibling=%p\n" msgstr "" #: .././db/flist.c:211 #, c-format msgid "\tlow=%d, high=%d, flags=%d (%s%s), offset=%d\n" msgstr "" #: .././db/flist.c:213 msgid "oklow " msgstr "" #: .././db/flist.c:214 msgid "okhigh" msgstr "" #: .././db/flist.c:215 #, c-format msgid "\tfld->name=%s, fld->ftyp=%d (%s)\n" msgstr "" #: .././db/flist.c:218 #, c-format msgid "\tfld->flags=%d (%s%s%s%s%s)\n" msgstr "" #: .././db/flist.c:310 #, c-format msgid "bad syntax in field name %s\n" msgstr "" #: .././db/flist.c:366 #, c-format msgid "missing closing quote %s\n" msgstr "" #: .././db/flist.c:383 #, c-format msgid "bad character in field %s\n" msgstr "" #: .././db/fprint.c:87 msgid "null" msgstr "" #: .././db/fuzz.c:30 msgid "[-c] [-d] field fuzzcmd..." msgstr "" #: .././db/fuzz.c:31 msgid "fuzz values on disk" msgstr "" #: .././db/fuzz.c:47 msgid "" "\n" " The 'fuzz' command fuzzes fields in any on-disk data structure. For\n" " block fuzzing, see the 'blocktrash' or 'write' commands.\n" " Examples:\n" " Struct mode: 'fuzz core.uid zeroes' - set an inode uid field to 0.\n" " 'fuzz crc ones' - set a crc filed to all ones.\n" " 'fuzz bno[11] firstbit' - set the high bit of a block " "array.\n" " 'fuzz keys[5].startblock add' - increase a btree key " "value.\n" " 'fuzz uuid random' - randomize the superblock uuid.\n" "\n" " Type 'fuzz' by itself for a list of specific commands.\n" "\n" " Specifying the -c option will allow writes of invalid (corrupt) data with\n" " an invalid CRC. Specifying the -d option will allow writes of invalid " "data,\n" " but still recalculate the CRC so we are forced to check and detect the\n" " invalid data appropriately.\n" "\n" msgstr "" #: .././db/fuzz.c:81 #, c-format msgid "%s started in read only mode, fuzzing disabled\n" msgstr "" #: .././db/fuzz.c:93 #, c-format msgid "no handler function for type %s, fuzz unsupported.\n" msgstr "" #: .././db/fuzz.c:107 msgid "bad option for fuzz command\n" msgstr "" #: .././db/fuzz.c:147 msgid "Allowing fuzz of corrupted data and bad CRC\n" msgstr "" #: .././db/fuzz.c:150 .././db/fuzz.c:153 msgid "Allowing fuzz of corrupted data with good CRC\n" msgstr "" #: .././db/fuzz.c:376 msgid "Usage: fuzz fieldname fuzzcmd\n" msgstr "" #: .././db/fuzz.c:395 #, c-format msgid "Unknown fuzz command '%s'.\n" msgstr "" #: .././db/fuzz.c:441 #, c-format msgid "unable to fuzz field '%s'\n" msgstr "" #: .././db/init.c:37 #, c-format msgid "Usage: %s [-ifFrxV] [-p prog] [-l logdev] [-c cmd]... device\n" msgstr "" #: .././db/init.c:105 msgid "" "\n" "fatal error -- couldn't initialize XFS library\n" msgstr "" #: .././db/init.c:120 #, c-format msgid "%s: %s is invalid (cannot read first 512 bytes)\n" msgstr "" #: .././db/init.c:132 #, c-format msgid "" "%s: %s is not a valid XFS filesystem (unexpected SB magic number 0x%08x)\n" msgstr "" #: .././db/init.c:135 #, c-format msgid "Use -F to force a read attempt.\n" msgstr "" #: .././db/init.c:145 #, c-format msgid "%s: device %s unusable (not an XFS filesystem?)\n" msgstr "" #: .././db/init.c:164 #, c-format msgid "%s: cannot init perag data (%d). Continuing anyway.\n" msgstr "" #: .././db/check.c:377 msgid "free block usage information" msgstr "" #: .././db/check.c:380 msgid "[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..." msgstr "" #: .././db/check.c:381 msgid "get block usage and check consistency" msgstr "" #: .././db/check.c:384 msgid "[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..." msgstr "" #: .././db/check.c:385 msgid "trash randomly selected block(s)" msgstr "" #: .././db/check.c:388 msgid "[-n] [-c blockcount]" msgstr "" #: .././db/check.c:389 msgid "print usage for current block(s)" msgstr "" #: .././db/check.c:392 msgid "[-s] [-i ino] ..." msgstr "" #: .././db/check.c:393 msgid "print inode-name pairs" msgstr "" #: .././db/check.c:413 #, c-format msgid "-i %lld bad inode number\n" msgstr "" #: .././db/check.c:425 #, c-format msgid "inode %lld add link, now %u\n" msgstr "" #: .././db/check.c:452 #, c-format msgid "inode %lld parent %lld\n" msgstr "" #: .././db/check.c:765 msgid "block usage information not allocated\n" msgstr "" #: .././db/check.c:803 msgid "already have block usage information\n" msgstr "" #: .././db/check.c:820 .././db/check.c:921 msgid "WARNING: this may be a newer XFS filesystem.\n" msgstr "" #: .././db/check.c:856 #, c-format msgid "sb_icount %lld, counted %lld\n" msgstr "" #: .././db/check.c:862 #, c-format msgid "sb_ifree %lld, counted %lld\n" msgstr "" #: .././db/check.c:868 #, c-format msgid "sb_fdblocks %lld, counted %lld\n" msgstr "" #: .././db/check.c:874 #, c-format msgid "sb_fdblocks %lld, aggregate AGF count %lld\n" msgstr "" #: .././db/check.c:880 #, c-format msgid "sb_frextents %lld, counted %lld\n" msgstr "" #: .././db/check.c:887 #, c-format msgid "sb_features2 (0x%x) not same as sb_bad_features2 (0x%x)\n" msgstr "" #: .././db/check.c:896 #, c-format msgid "sb versionnum missing attr bit %x\n" msgstr "" #: .././db/check.c:903 #, c-format msgid "sb versionnum missing quota bit %x\n" msgstr "" #: .././db/check.c:910 #, c-format msgid "sb versionnum extra align bit %x\n" msgstr "" #: .././db/check.c:949 msgid "zeroed" msgstr "" #: .././db/check.c:949 msgid "set" msgstr "" #: .././db/check.c:949 msgid "flipped" msgstr "" #: .././db/check.c:949 msgid "randomized" msgstr "" #: .././db/check.c:957 #, c-format msgid "zero-length block %u/%u buffer to trash??\n" msgstr "" #: .././db/check.c:976 #, c-format msgid "can't read block %u/%u for trashing\n" msgstr "" #: .././db/check.c:1005 #, c-format msgid "blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n" msgstr "" #: .././db/check.c:1084 #, c-format msgid "bad blocktrash count %s\n" msgstr "" #: .././db/check.c:1096 #, c-format msgid "bad blocktrash offset %s\n" msgstr "" #: .././db/check.c:1113 #, c-format msgid "bad blocktrash type %s\n" msgstr "" #: .././db/check.c:1122 #, c-format msgid "bad blocktrash min %s\n" msgstr "" #: .././db/check.c:1130 #, c-format msgid "bad blocktrash max %s\n" msgstr "" #: .././db/check.c:1138 msgid "bad option for blocktrash command\n" msgstr "" #: .././db/check.c:1143 .././db/check.c:1234 msgid "must run blockget first\n" msgstr "" #: .././db/check.c:1147 msgid "nothing on stack\n" msgstr "" #: .././db/check.c:1151 msgid "bad min/max for blocktrash command\n" msgstr "" #: .././db/check.c:1169 #, c-format msgid "blocktrash: seed %u\n" msgstr "" #: .././db/check.c:1185 msgid "blocktrash: no matching blocks\n" msgstr "" #: .././db/check.c:1249 #, c-format msgid "bad blockuse count %s\n" msgstr "" #: .././db/check.c:1255 .././db/check.c:1979 msgid "must run blockget -n first\n" msgstr "" #: .././db/check.c:1261 msgid "bad option for blockuse command\n" msgstr "" #: .././db/check.c:1268 #, c-format msgid "block %llu (%u/%u) type %s" msgstr "" #: .././db/check.c:1272 #, c-format msgid " inode %lld" msgstr "" #: .././db/check.c:1316 #, c-format msgid "block %u/%u expected type %s got %s\n" msgstr "" #: .././db/check.c:1349 #, c-format msgid "blocks %u/%u..%u claimed by inode %lld\n" msgstr "" #: .././db/check.c:1357 #, c-format msgid "block %u/%u claimed by inode %lld, previous inum %lld\n" msgstr "" #: .././db/check.c:1386 #, c-format msgid "link count mismatch for inode %lld (name %s), nlink %d, counted %d\n" msgstr "" #: .././db/check.c:1394 #, c-format msgid "disconnected inode %lld, nlink %d\n" msgstr "" #: .././db/check.c:1398 #, c-format msgid "allocated inode %lld has 0 link count\n" msgstr "" #: .././db/check.c:1408 #, c-format msgid "inode %lld name %s\n" msgstr "" #: .././db/check.c:1442 .././db/check.c:1457 #, c-format msgid "block %u/%u out of range\n" msgstr "" #: .././db/check.c:1445 .././db/check.c:1460 #, c-format msgid "blocks %u/%u..%u out of range\n" msgstr "" #: .././db/check.c:1483 #, c-format msgid "rtblock %llu expected type %s got %s\n" msgstr "" #: .././db/check.c:1503 #, c-format msgid "rtblocks %llu..%llu claimed by inode %lld\n" msgstr "" #: .././db/check.c:1512 #, c-format msgid "rtblock %llu claimed by inode %lld, previous inum %lld\n" msgstr "" #: .././db/check.c:1530 #, c-format msgid "root inode %lld is missing\n" msgstr "" #: .././db/check.c:1535 #, c-format msgid "root inode %lld is not a directory\n" msgstr "" #: .././db/check.c:1551 #, c-format msgid "rtblock %llu out of range\n" msgstr "" #: .././db/check.c:1595 #, c-format msgid "blocks %u/%u..%u claimed by block %u/%u\n" msgstr "" #: .././db/check.c:1609 #, c-format msgid "setting block %u/%u to %s\n" msgstr "" #: .././db/check.c:1632 #, c-format msgid "setting rtblock %llu to %s\n" msgstr "" #: .././db/check.c:1653 .././repair/rt.c:139 #, c-format msgid "rt summary mismatch, size %d block %llu, file: %d, computed: %d\n" msgstr "" #: .././db/check.c:1678 #, c-format msgid "block %u/%u type %s not expected\n" msgstr "" #: .././db/check.c:1699 #, c-format msgid "rtblock %llu type %s not expected\n" msgstr "" #: .././db/check.c:1736 #, c-format msgid "dir ino %lld missing leaf entry for %x/%x\n" msgstr "" #: .././db/check.c:1855 #, c-format msgid "bad superblock magic number %x, giving up\n" msgstr "" #: .././db/check.c:1909 msgid "bad option for blockget command\n" msgstr "" #: .././db/check.c:1996 #, c-format msgid "bad option -%c for ncheck command\n" msgstr "" #: .././db/check.c:2070 #, c-format msgid "block 0 for directory inode %lld is missing\n" msgstr "" #: .././db/check.c:2090 #, c-format msgid "can't read block 0 for directory inode %lld\n" msgstr "" #: .././db/check.c:2136 #, c-format msgid "inode %lld extent [%lld,%lld,%lld,%d]\n" msgstr "" #: .././db/check.c:2139 #, c-format msgid "bmap rec out of order, inode %lld entry %d\n" msgstr "" #: .././db/check.c:2145 #, c-format msgid "inode %lld bad rt block number %lld, offset %lld\n" msgstr "" #: .././db/check.c:2155 .././db/check.c:2161 #, c-format msgid "inode %lld bad block number %lld [%d,%d], offset %lld\n" msgstr "" #: .././db/check.c:2179 .././db/check.c:2193 #, c-format msgid "inode %lld block %lld at offset %lld\n" msgstr "" #: .././db/check.c:2220 #, c-format msgid "level for ino %lld %s fork bmap root too large (%u)\n" msgstr "" #: .././db/check.c:2232 #, c-format msgid "numrecs for ino %lld %s fork bmap root too large (%u)\n" msgstr "" #: .././db/check.c:2259 #, c-format msgid "extent count for ino %lld %s fork too low (%d) for file format\n" msgstr "" #: .././db/check.c:2311 .././db/check.c:3334 #, c-format msgid "bad directory data magic # %#x for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:2329 #, c-format msgid "bad block directory tail for dir ino %lld\n" msgstr "" #: .././db/check.c:2374 #, c-format msgid "dir %lld block %d bad free entry at %d\n" msgstr "" #: .././db/check.c:2398 #, c-format msgid "dir %lld block %d zero length entry at %d\n" msgstr "" #: .././db/check.c:2407 #, c-format msgid "dir %lld block %d bad entry at %d\n" msgstr "" #: .././db/check.c:2425 #, c-format msgid "dir %lld block %d entry %*.*s %lld\n" msgstr "" #: .././db/check.c:2432 #, c-format msgid "dir %lld block %d entry %*.*s bad inode number %lld\n" msgstr "" #: .././db/check.c:2442 #, c-format msgid "multiple .. entries in dir %lld (%lld, %lld)\n" msgstr "" #: .././db/check.c:2459 #, c-format msgid "dir %lld entry . inode number mismatch (%lld)\n" msgstr "" #: .././db/check.c:2473 #, c-format msgid "dir %lld block %d bad count %u\n" msgstr "" #: .././db/check.c:2484 .././db/check.c:3348 #, c-format msgid "dir %lld block %d extra leaf entry %x %x\n" msgstr "" #: .././db/check.c:2496 #, c-format msgid "dir %lld block %d bad bestfree data\n" msgstr "" #: .././db/check.c:2504 #, c-format msgid "dir %lld block %d bad block tail count %d (stale %d)\n" msgstr "" #: .././db/check.c:2514 #, c-format msgid "dir %lld block %d bad stale tail count %d\n" msgstr "" #: .././db/check.c:2520 #, c-format msgid "dir %lld block %d consecutive free entries\n" msgstr "" #: .././db/check.c:2526 #, c-format msgid "dir %lld block %d entry/unused tag mismatch\n" msgstr "" #: .././db/check.c:2575 #, c-format msgid "no . entry for directory %lld\n" msgstr "" #: .././db/check.c:2580 #, c-format msgid "no .. entry for directory %lld\n" msgstr "" #: .././db/check.c:2584 #, c-format msgid ". and .. same for non-root directory %lld\n" msgstr "" #: .././db/check.c:2589 #, c-format msgid "root directory %lld has .. %lld\n" msgstr "" #: .././db/check.c:2622 #, c-format msgid "bad size (%lld) or format (%d) for directory inode %lld\n" msgstr "" #: .././db/check.c:2650 #, c-format msgid "bad number of extents %d for inode %lld\n" msgstr "" #: .././db/check.c:2722 #, c-format msgid "bad magic number %#x for inode %lld\n" msgstr "" #: .././db/check.c:2729 #, c-format msgid "bad version number %#x for inode %lld\n" msgstr "" #: .././db/check.c:2737 #, c-format msgid "bad nblocks %lld for free inode %lld\n" msgstr "" #: .././db/check.c:2744 #, c-format msgid "bad nlink %d for free inode %lld\n" msgstr "" #: .././db/check.c:2750 #, c-format msgid "bad mode %#o for free inode %lld\n" msgstr "" #: .././db/check.c:2759 #, c-format msgid "bad next unlinked %#x for inode %lld\n" msgstr "" #: .././db/check.c:2770 #, c-format msgid "bad format %d for inode %lld type %#o\n" msgstr "" #: .././db/check.c:2778 #, c-format msgid "bad fork offset %d for inode %lld\n" msgstr "" #: .././db/check.c:2785 #, c-format msgid "bad attribute format %d for inode %lld\n" msgstr "" #: .././db/check.c:2791 #, c-format msgid "" "inode %lld mode %#o fmt %s afmt %s nex %d anex %d nblk %lld sz %lld%s%s%s%s%s" "%s%s\n" msgstr "" #: .././db/check.c:2910 #, c-format msgid "bad nblocks %lld for inode %lld, counted %lld\n" msgstr "" #: .././db/check.c:2917 #, c-format msgid "bad nextents %d for inode %lld, counted %d\n" msgstr "" #: .././db/check.c:2923 #, c-format msgid "bad anextents %d for inode %lld, counted %d\n" msgstr "" #: .././db/check.c:2975 #, c-format msgid "local inode %lld data is too large (size %lld)\n" msgstr "" #: .././db/check.c:2984 #, c-format msgid "local inode %lld attr is too large (size %d)\n" msgstr "" #: .././db/check.c:3032 #, c-format msgid "dir inode %lld block %u=%llu\n" msgstr "" #: .././db/check.c:3044 #, c-format msgid "can't read block %u for directory inode %lld\n" msgstr "" #: .././db/check.c:3058 #, c-format msgid "multiple .. entries in dir %lld\n" msgstr "" #: .././db/check.c:3080 #, c-format msgid "missing free index for data block %d in dir ino %lld\n" msgstr "" #: .././db/check.c:3108 .././db/check.c:3186 #, c-format msgid "bad free block firstdb %d for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3119 .././db/check.c:3197 #, c-format msgid "bad free block nvalid/nused %d/%d for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3133 .././db/check.c:3211 #, c-format msgid "bad free block ent %d is %d should be %d for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3147 .././db/check.c:3225 #, c-format msgid "bad free block nused %d should be %d for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3172 #, c-format msgid "bad free block magic # %#x for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3279 #, c-format msgid "bad leaf block forw/back pointers %d/%d for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3288 #, c-format msgid "single leaf block for dir ino %lld block %d should be at block %d\n" msgstr "" #: .././db/check.c:3300 #, c-format msgid "bestfree %d for dir ino %lld block %d doesn't match table value %d\n" msgstr "" #: .././db/check.c:3325 #, c-format msgid "bad node block level %d for dir ino %lld block %d\n" msgstr "" #: .././db/check.c:3357 #, c-format msgid "dir3 %lld block %d stale mismatch %d/%d\n" msgstr "" #: .././db/check.c:3364 #, c-format msgid "dir %lld block %d stale mismatch %d/%d\n" msgstr "" #: .././db/check.c:3420 #, c-format msgid "can't read block %lld for %s quota inode (fsblock %lld)\n" msgstr "" #: .././db/check.c:3430 #, c-format msgid "%s dqblk %lld entry %d id %u bc %lld ic %lld rc %lld\n" msgstr "" #: .././db/check.c:3438 #, c-format msgid "bad magic number %#x for %s dqblk %lld entry %d id %u\n" msgstr "" #: .././db/check.c:3447 #, c-format msgid "bad version number %#x for %s dqblk %lld entry %d id %u\n" msgstr "" #: .././db/check.c:3457 #, c-format msgid "bad flags %#x for %s dqblk %lld entry %d id %u\n" msgstr "" #: .././db/check.c:3466 #, c-format msgid "bad id %u for %s dqblk %lld entry %d id %u\n" msgstr "" #: .././db/check.c:3512 #, c-format msgid "block %lld for rtbitmap inode is missing\n" msgstr "" #: .././db/check.c:3523 #, c-format msgid "can't read block %lld for rtbitmap inode\n" msgstr "" #: .././db/check.c:3579 #, c-format msgid "block %lld for rtsummary inode is missing\n" msgstr "" #: .././db/check.c:3590 #, c-format msgid "can't read block %lld for rtsummary inode\n" msgstr "" #: .././db/check.c:3623 #, c-format msgid "dir %lld entry . %lld\n" msgstr "" #: .././db/check.c:3631 #, c-format msgid "dir %llu bad size in entry at %d\n" msgstr "" #: .././db/check.c:3643 #, c-format msgid "dir %lld entry %*.*s bad inode number %lld\n" msgstr "" #: .././db/check.c:3655 #, c-format msgid "dir %lld entry %*.*s offset %d %lld\n" msgstr "" #: .././db/check.c:3660 #, c-format msgid "dir %lld entry %*.*s bad offset %d\n" msgstr "" #: .././db/check.c:3673 #, c-format msgid "dir %llu size is %lld, should be %u\n" msgstr "" #: .././db/check.c:3681 #, c-format msgid "dir %llu offsets too high\n" msgstr "" #: .././db/check.c:3692 #, c-format msgid "dir %lld entry .. bad inode number %lld\n" msgstr "" #: .././db/check.c:3697 #, c-format msgid "dir %lld entry .. %lld\n" msgstr "" #: .././db/check.c:3700 #, c-format msgid "dir %lld i8count mismatch is %d should be %d\n" msgstr "" #: .././db/check.c:3782 #, c-format msgid "%s quota id %u, have/exp" msgstr "" #: .././db/check.c:3785 #, c-format msgid " bc %lld/%lld" msgstr "" #: .././db/check.c:3789 #, c-format msgid " ic %lld/%lld" msgstr "" #: .././db/check.c:3793 #, c-format msgid " rc %lld/%lld" msgstr "" #: .././db/check.c:3849 #, c-format msgid "can't read superblock for ag %u\n" msgstr "" #: .././db/check.c:3858 #, c-format msgid "bad sb magic # %#x in ag %u\n" msgstr "" #: .././db/check.c:3864 #, c-format msgid "bad sb version # %#x in ag %u\n" msgstr "" #: .././db/check.c:3892 #, c-format msgid "bad agf magic # %#x in ag %u\n" msgstr "" #: .././db/check.c:3898 #, c-format msgid "bad agf version # %#x in ag %u\n" msgstr "" #: .././db/check.c:3920 #, c-format msgid "bad agi magic # %#x in ag %u\n" msgstr "" #: .././db/check.c:3926 #, c-format msgid "bad agi version # %#x in ag %u\n" msgstr "" #: .././db/check.c:3969 .././repair/scan.c:2247 #, c-format msgid "agf_freeblks %u, counted %u in ag %u\n" msgstr "" #: .././db/check.c:3976 .././repair/scan.c:2252 #, c-format msgid "agf_longest %u, counted %u in ag %u\n" msgstr "" #: .././db/check.c:3984 #, c-format msgid "agf_btreeblks %u, counted %u in ag %u\n" msgstr "" #: .././db/check.c:3992 .././repair/scan.c:2301 #, c-format msgid "agi_count %u, counted %u in ag %u\n" msgstr "" #: .././db/check.c:3999 .././repair/scan.c:2306 #, c-format msgid "agi_freecount %u, counted %u in ag %u\n" msgstr "" #: .././db/check.c:4008 #, c-format msgid "agi unlinked bucket %d is %u in ag %u (inode=%lld)\n" msgstr "" #: .././db/check.c:4060 #, c-format msgid "can't read agfl block for ag %u\n" msgstr "" #: .././db/check.c:4081 #, c-format msgid "freeblk count %u != flcount %u in ag %u\n" msgstr "" #: .././db/check.c:4173 #, c-format msgid "bad magic # %#x in inode %lld bmbt block %u/%u\n" msgstr "" #: .././db/check.c:4180 #, c-format msgid "expected level %d got %d in inode %lld bmbt block %u/%u\n" msgstr "" #: .././db/check.c:4192 .././db/check.c:4209 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in inode %lld bmap block %lld\n" msgstr "" #: .././db/check.c:4238 #, c-format msgid "bad magic # %#x in btbno block %u/%u\n" msgstr "" #: .././db/check.c:4247 #, c-format msgid "expected level %d got %d in btbno block %u/%u\n" msgstr "" #: .././db/check.c:4256 .././db/check.c:4284 .././db/check.c:4330 #: .././db/check.c:4361 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in btbno block %u/%u\n" msgstr "" #: .././db/check.c:4271 .././repair/scan.c:662 #, c-format msgid "out-of-order bno btree record %d (%u %u) block %u/%u\n" msgstr "" #: .././db/check.c:4312 #, c-format msgid "bad magic # %#x in btcnt block %u/%u\n" msgstr "" #: .././db/check.c:4321 #, c-format msgid "expected level %d got %d in btcnt block %u/%u\n" msgstr "" #: .././db/check.c:4349 .././repair/scan.c:674 #, c-format msgid "out-of-order cnt btree record %d (%u %u) block %u/%u\n" msgstr "" #: .././db/check.c:4408 #, c-format msgid "bad magic # %#x in inobt block %u/%u\n" msgstr "" #: .././db/check.c:4415 #, c-format msgid "expected level %d got %d in inobt block %u/%u\n" msgstr "" #: .././db/check.c:4424 .././db/check.c:4510 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in inobt block %u/%u\n" msgstr "" #: .././db/check.c:4498 #, c-format msgid "ir_freecount/free mismatch, inode chunk %u/%u, freecount %d nfree %d\n" msgstr "" #: .././db/check.c:4552 #, c-format msgid "bad magic # %#x in finobt block %u/%u\n" msgstr "" #: .././db/check.c:4559 #, c-format msgid "expected level %d got %d in finobt block %u/%u\n" msgstr "" #: .././db/check.c:4568 .././db/check.c:4611 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in finobt block %u/%u\n" msgstr "" #: .././db/check.c:4638 #, c-format msgid "bad magic # %#x in rmapbt block %u/%u\n" msgstr "" #: .././db/check.c:4645 #, c-format msgid "expected level %d got %d in rmapbt block %u/%u\n" msgstr "" #: .././db/check.c:4658 .././db/check.c:4682 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in rmapbt block %u/%u\n" msgstr "" #: .././db/check.c:4670 #, c-format msgid "out-of-order rmap btree record %d (%u %u) block %u/%u\n" msgstr "" #: .././db/check.c:4710 #, c-format msgid "bad magic # %#x in refcntbt block %u/%u\n" msgstr "" #: .././db/check.c:4717 #, c-format msgid "expected level %d got %d in refcntbt block %u/%u\n" msgstr "" #: .././db/check.c:4726 .././db/check.c:4778 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in refcntbt block %u/%u\n" msgstr "" #: .././db/check.c:4744 .././repair/scan.c:1337 #, c-format msgid "leftover CoW extent (%u/%u) len %u\n" msgstr "" #: .././db/check.c:4747 #, c-format msgid "leftover CoW extent at unexpected address (%u/%u) len %u\n" msgstr "" #: .././db/check.c:4765 #, c-format msgid "out-of-order refcnt btree record %d (%u %u) block %u/%u\n" msgstr "" #: .././db/check.c:4821 #, c-format msgid "setting inode to %lld for block %u/%u\n" msgstr "" #: .././db/check.c:4853 #, c-format msgid "setting inode to %lld for rtblock %llu\n" msgstr "" #: .././db/check.c:4869 #, c-format msgid "inode %lld nlink %u %s dir\n" msgstr "" #: .././estimate/xfs_estimate.c:65 #, c-format msgid "" "Usage: %s [opts] directory [directory ...]\n" "\t-b blocksize (fundamental filesystem blocksize)\n" "\t-i logsize (internal log size)\n" "\t-e logsize (external log size)\n" "\t-v prints more verbose messages\n" "\t-V prints version and exits\n" "\t-h prints this usage message\n" "\n" "Note:\tblocksize may have 'k' appended to indicate x1024\n" "\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n" msgstr "" #: .././estimate/xfs_estimate.c:96 #, c-format msgid "blocksize %llu too small\n" msgstr "" #: .././estimate/xfs_estimate.c:101 #, c-format msgid "blocksize %llu too large\n" msgstr "" #: .././estimate/xfs_estimate.c:108 #, c-format msgid "already have external log noted, can't have both\n" msgstr "" #: .././estimate/xfs_estimate.c:117 #, c-format msgid "already have internal log noted, can't have both\n" msgstr "" #: .././estimate/xfs_estimate.c:147 #, c-format msgid "" "directory bsize blocks megabytes " "logsize\n" msgstr "" #: .././estimate/xfs_estimate.c:161 #, c-format msgid "dirsize=%llu\n" msgstr "" #: .././estimate/xfs_estimate.c:162 #, c-format msgid "fullblocks=%llu\n" msgstr "" #: .././estimate/xfs_estimate.c:163 #, c-format msgid "isize=%llu\n" msgstr "" #: .././estimate/xfs_estimate.c:165 #, c-format msgid "%llu regular files\n" msgstr "" #: .././estimate/xfs_estimate.c:166 #, c-format msgid "%llu symbolic links\n" msgstr "" #: .././estimate/xfs_estimate.c:167 #, c-format msgid "%llu directories\n" msgstr "" #: .././estimate/xfs_estimate.c:168 #, c-format msgid "%llu special files\n" msgstr "" #: .././estimate/xfs_estimate.c:181 #, c-format msgid "%s will take about %.1f megabytes\n" msgstr "" #: .././estimate/xfs_estimate.c:188 #, c-format msgid "%-39s %5llu %8llu %10.1fMB %10llu\n" msgstr "" #: .././estimate/xfs_estimate.c:194 #, c-format msgid "\twith the external log using %llu blocks " msgstr "" #: .././estimate/xfs_estimate.c:196 #, c-format msgid "or about %.1f megabytes\n" msgstr "" #: .././fsr/xfs_fsr.c:163 #, c-format msgid "%s: Stats not yet supported for XFS\n" msgstr "" #: .././fsr/xfs_fsr.c:227 .././scrub/xfs_scrub.c:716 #, c-format msgid "%s: could not stat: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:248 #, c-format msgid "%s: char special not supported: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:254 #, c-format msgid "%s: cannot defragment: %s: Not XFS\n" msgstr "" #: .././fsr/xfs_fsr.c:264 #, c-format msgid "%s: not fsys dev, dir, or reg file, ignoring\n" msgstr "" #: .././fsr/xfs_fsr.c:279 #, c-format msgid "" "Usage: %s [-d] [-v] [-g] [-t time] [-p passes] [-f leftf] [-m mtab]\n" " %s [-d] [-v] [-g] xfsdev | dir | file ...\n" " %s -V\n" "\n" "Options:\n" " -g Print to syslog (default if stdout not a tty).\n" " -t time How long to run in seconds.\n" " -p passes Number of passes before terminating global re-org.\n" " -f leftoff Use this instead of %s.\n" " -m mtab Use something other than /etc/mtab.\n" " -d Debug, print even more.\n" " -v Verbose, more -v's more verbose.\n" " -V Print version number and exit.\n" msgstr "" #: .././fsr/xfs_fsr.c:309 .././fsr/xfs_fsr.c:347 #, c-format msgid "out of memory: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:338 #, c-format msgid "Skipping %s: not mounted rw\n" msgstr "" #: .././fsr/xfs_fsr.c:352 #, c-format msgid "out of memory on realloc: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:363 .././fsr/xfs_fsr.c:367 #, c-format msgid "strdup(%s) failed\n" msgstr "" #: .././fsr/xfs_fsr.c:378 #, c-format msgid "no rw xfs file systems in mtab: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:382 #, c-format msgid "Found %d mounted, writable, XFS filesystems\n" msgstr "" #: .././fsr/xfs_fsr.c:412 #, c-format msgid "%s: open failed\n" msgstr "" #: .././fsr/xfs_fsr.c:427 #, c-format msgid "Can't use %s: mode=0%o own=%d nlink=%d\n" msgstr "" #: .././fsr/xfs_fsr.c:447 #, c-format msgid "could not read %s, starting with %s\n" msgstr "" #: .././fsr/xfs_fsr.c:497 #, c-format msgid "START: pass=%d ino=%llu %s %s\n" msgstr "" #: .././fsr/xfs_fsr.c:519 msgid "couldn't fork sub process:" msgstr "" #: .././fsr/xfs_fsr.c:540 #, c-format msgid "Completed all %d passes\n" msgstr "" #: .././fsr/xfs_fsr.c:560 #, c-format msgid "%s startpass %d, endpass %d, time %d seconds\n" msgstr "" #: .././fsr/xfs_fsr.c:567 #, c-format msgid "open(%s) failed: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:573 #, c-format msgid "write(%s) failed: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:595 #, c-format msgid "%s start inode=%llu\n" msgstr "" #: .././fsr/xfs_fsr.c:600 #, c-format msgid "unable to get handle: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:607 #, c-format msgid "unable to open XFS file: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:618 #, c-format msgid "Skipping %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:647 #, c-format msgid "bstat conversion error: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:659 #, c-format msgid "could not open: inode %llu\n" msgstr "" #: .././fsr/xfs_fsr.c:690 #, c-format msgid "%s: bulkstat: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:718 #, c-format msgid "%s: Directory defragmentation not supported\n" msgstr "" #: .././fsr/xfs_fsr.c:741 #, c-format msgid "unable to construct sys handle for %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:752 #, c-format msgid "unable to open sys handle for XFS file %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:759 #, c-format msgid "unable to get bstat on %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:765 #, c-format msgid "bstat conversion error on %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:772 #, c-format msgid "unable to open handle %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:826 #, c-format msgid "sync failed: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:832 #, c-format msgid "%s: zero size, ignoring\n" msgstr "" #: .././fsr/xfs_fsr.c:851 #, c-format msgid "locking check failed: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:858 #, c-format msgid "mandatory lock: %s: ignoring\n" msgstr "" #: .././fsr/xfs_fsr.c:871 #, c-format msgid "unable to get fs stat on %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:878 #, c-format msgid "insufficient freespace for: %s: size=%lld: ignoring\n" msgstr "" #: .././fsr/xfs_fsr.c:885 #, c-format msgid "failed to get inode attrs: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:890 #, c-format msgid "%s: immutable/append, ignoring\n" msgstr "" #: .././fsr/xfs_fsr.c:895 #, c-format msgid "%s: marked as don't defrag, ignoring\n" msgstr "" #: .././fsr/xfs_fsr.c:901 #, c-format msgid "cannot get realtime geometry for: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:906 #, c-format msgid "low on realtime free space: %s: ignoring file\n" msgstr "" #: .././fsr/xfs_fsr.c:913 #, c-format msgid "cannot open: %s: Permission denied\n" msgstr "" #: .././fsr/xfs_fsr.c:973 .././fsr/xfs_fsr.c:1024 .././fsr/xfs_fsr.c:1104 msgid "could not set ATTR\n" msgstr "" #: .././fsr/xfs_fsr.c:982 #, c-format msgid "unable to stat temp file: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1001 #, c-format msgid "unable to get bstat on temp file: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1006 #, c-format msgid "orig forkoff %d, temp forkoff %d\n" msgstr "" #: .././fsr/xfs_fsr.c:1059 msgid "big ATTR set failed\n" msgstr "" #: .././fsr/xfs_fsr.c:1080 #, c-format msgid "forkoff diff %d too large!\n" msgstr "" #: .././fsr/xfs_fsr.c:1097 #, c-format msgid "data fork growth unimplemented\n" msgstr "" #: .././fsr/xfs_fsr.c:1112 msgid "set temp attr\n" msgstr "" #: .././fsr/xfs_fsr.c:1115 msgid "failed to match fork offset\n" msgstr "" #: .././fsr/xfs_fsr.c:1162 #, c-format msgid "%s already fully defragmented.\n" msgstr "" #: .././fsr/xfs_fsr.c:1168 #, c-format msgid "%s extents=%d can_save=%d tmp=%s\n" msgstr "" #: .././fsr/xfs_fsr.c:1174 #, c-format msgid "could not open tmp file: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1182 #, c-format msgid "failed to set ATTR fork on tmp: %s:\n" msgstr "" #: .././fsr/xfs_fsr.c:1189 #, c-format msgid "could not set inode attrs on tmp: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1196 #, c-format msgid "could not get DirectIO info on tmp: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1211 #, c-format msgid "DEBUG: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n" msgstr "" #: .././fsr/xfs_fsr.c:1218 #, c-format msgid "could not allocate buf: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1228 #, c-format msgid "could not open fragfile: %s : %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1243 #, c-format msgid "could not trunc tmp %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1247 .././fsr/xfs_fsr.c:1267 .././fsr/xfs_fsr.c:1295 #, c-format msgid "could not lseek in tmpfile: %s : %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1262 #, c-format msgid "could not pre-allocate tmp space: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1275 msgid "Couldn't rewind on temporary file\n" msgstr "" #: .././fsr/xfs_fsr.c:1282 #, c-format msgid "Temporary file has %d extents (%d in original)\n" msgstr "" #: .././fsr/xfs_fsr.c:1285 #, c-format msgid "No improvement will be made (skipping): %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1300 #, c-format msgid "could not lseek in file: %s : %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1336 #, c-format msgid "bad read of %d bytes from %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1340 .././fsr/xfs_fsr.c:1372 #, c-format msgid "bad write of %d bytes to %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1357 #, c-format msgid "bad write2 of %d bytes to %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1362 #, c-format msgid "bad copy to %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1380 #, c-format msgid "could not truncate tmpfile: %s : %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1385 #, c-format msgid "could not fsync tmpfile: %s : %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1400 #, c-format msgid "failed to fchown tmpfile %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1410 #, c-format msgid "%s: file type not supported\n" msgstr "" #: .././fsr/xfs_fsr.c:1414 #, c-format msgid "%s: file modified defrag aborted\n" msgstr "" #: .././fsr/xfs_fsr.c:1419 #, c-format msgid "%s: file busy\n" msgstr "" #: .././fsr/xfs_fsr.c:1421 #, c-format msgid "XFS_IOC_SWAPEXT failed: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1429 #, c-format msgid "extents before:%d after:%d %s %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1463 #, c-format msgid "tmp file name too long: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1513 #, c-format msgid "realloc failed: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1526 #, c-format msgid "malloc failed: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1556 #, c-format msgid "failed reading extents: inode %llu" msgstr "" #: .././fsr/xfs_fsr.c:1606 msgid "failed reading extents" msgstr "" #: .././fsr/xfs_fsr.c:1682 .././fsr/xfs_fsr.c:1696 #, c-format msgid "tmpdir already exists: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1685 #, c-format msgid "could not create tmpdir: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1698 #, c-format msgid "cannot create tmpdir: %s: %s\n" msgstr "" #: .././fsr/xfs_fsr.c:1736 .././fsr/xfs_fsr.c:1744 #, c-format msgid "could not remove tmpdir: %s: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:15 #, c-format msgid "" "Usage: %s [options] mountpoint\n" "\n" "Options:\n" "\t-d grow data/metadata section\n" "\t-l grow log section\n" "\t-r grow realtime section\n" "\t-n don't change anything, just show geometry\n" "\t-i convert log from external to internal format\n" "\t-t alternate location for mount table (/etc/mtab)\n" "\t-x convert log from internal to external format\n" "\t-D size grow data/metadata section to size blks\n" "\t-L size grow/shrink log section to size blks\n" "\t-R size grow realtime section to size blks\n" "\t-e size set realtime extent size to size blks\n" "\t-m imaxpct set inode max percent to imaxpct\n" "\t-V print version information\n" msgstr "" #: .././growfs/xfs_growfs.c:138 #, c-format msgid "%s: path resolution failed for %s: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:148 #, c-format msgid "%s: %s is not a mounted XFS filesystem\n" msgstr "" #: .././growfs/xfs_growfs.c:165 #, c-format msgid "%s: specified file [\"%s\"] is not on an XFS filesystem\n" msgstr "" #: .././growfs/xfs_growfs.c:175 #, c-format msgid "%s: cannot determine geometry of filesystem mounted at %s: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:197 #, c-format msgid "%s: failed to access data device for %s\n" msgstr "" #: .././growfs/xfs_growfs.c:202 #, c-format msgid "%s: failed to access external log for %s\n" msgstr "" #: .././growfs/xfs_growfs.c:208 #, c-format msgid "%s: failed to access realtime device for %s\n" msgstr "" #: .././growfs/xfs_growfs.c:244 #, c-format msgid "data size %lld too large, maximum is %lld\n" msgstr "" #: .././growfs/xfs_growfs.c:251 #, c-format msgid "data size %lld too small, old size is %lld\n" msgstr "" #: .././growfs/xfs_growfs.c:259 #, c-format msgid "data size unchanged, skipping\n" msgstr "" #: .././growfs/xfs_growfs.c:262 #, c-format msgid "inode max pct unchanged, skipping\n" msgstr "" #: .././growfs/xfs_growfs.c:269 .././growfs/xfs_growfs.c:308 #: .././growfs/xfs_growfs.c:343 #, c-format msgid "%s: growfs operation in progress already\n" msgstr "" #: .././growfs/xfs_growfs.c:273 #, c-format msgid "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:289 #, c-format msgid "realtime size %lld too large, maximum is %lld\n" msgstr "" #: .././growfs/xfs_growfs.c:295 #, c-format msgid "realtime size %lld too small, old size is %lld\n" msgstr "" #: .././growfs/xfs_growfs.c:301 #, c-format msgid "realtime size unchanged, skipping\n" msgstr "" #: .././growfs/xfs_growfs.c:312 #, c-format msgid "%s: realtime growth not implemented\n" msgstr "" #: .././growfs/xfs_growfs.c:316 #, c-format msgid "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:337 #, c-format msgid "log size unchanged, skipping\n" msgstr "" #: .././growfs/xfs_growfs.c:347 #, c-format msgid "%s: log growth not supported yet\n" msgstr "" #: .././growfs/xfs_growfs.c:351 #, c-format msgid "%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:360 #, c-format msgid "%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n" msgstr "" #: .././growfs/xfs_growfs.c:365 #, c-format msgid "data blocks changed from %lld to %lld\n" msgstr "" #: .././growfs/xfs_growfs.c:368 #, c-format msgid "inode max percent changed from %d to %d\n" msgstr "" #: .././growfs/xfs_growfs.c:371 #, c-format msgid "log blocks changed from %d to %d\n" msgstr "" #: .././growfs/xfs_growfs.c:374 #, c-format msgid "log changed from %s to %s\n" msgstr "" #: .././growfs/xfs_growfs.c:375 .././growfs/xfs_growfs.c:376 msgid "internal" msgstr "" #: .././growfs/xfs_growfs.c:375 .././growfs/xfs_growfs.c:376 #: .././libfrog/fsgeom.c:64 .././libfrog/fsgeom.c:67 msgid "external" msgstr "" #: .././growfs/xfs_growfs.c:378 #, c-format msgid "realtime blocks changed from %lld to %lld\n" msgstr "" #: .././growfs/xfs_growfs.c:381 #, c-format msgid "realtime extent size changed from %d to %d\n" msgstr "" #: .././io/fsync.c:47 msgid "calls fsync(2) to flush all in-core file state to disk" msgstr "" #: .././io/fsync.c:54 msgid "calls fdatasync(2) to flush the files in-core data to disk" msgstr "" #: .././io/getrusage.c:107 msgid "report process resource usage" msgstr "" #: .././io/madvise.c:19 #, c-format msgid "" "\n" " advise the page cache about access patterns expected for a mapping\n" "\n" " Modifies page cache behavior when operating on the current mapping.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_MADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_MADV_DONTNEED) [*]\n" " -r -- expect random page references (POSIX_MADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_MADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_MADV_WILLNEED) [*]\n" " Notes:\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED forces the maximum readahead.\n" "\n" msgstr "" #: .././io/madvise.c:74 .././io/mincore.c:35 .././io/mmap.c:219 #: .././io/mmap.c:327 .././io/mmap.c:413 .././io/mmap.c:572 .././io/mmap.c:654 #: .././io/pwrite.c:390 .././io/sendfile.c:112 .././io/sync_file_range.c:62 #: .././io/prealloc.c:61 .././io/fadvise.c:79 #, c-format msgid "non-numeric offset argument -- %s\n" msgstr "" #: .././io/madvise.c:81 .././io/mincore.c:41 .././io/mmap.c:225 #: .././io/mmap.c:334 .././io/mmap.c:420 .././io/mmap.c:579 .././io/pread.c:443 #: .././io/pread.c:451 .././io/pwrite.c:396 .././io/sendfile.c:119 #: .././io/sync_file_range.c:69 .././io/prealloc.c:66 .././io/fadvise.c:86 #, c-format msgid "non-numeric length argument -- %s\n" msgstr "" #: .././io/madvise.c:85 .././io/mincore.c:45 #, c-format msgid "length argument too large -- %lld\n" msgstr "" #: .././io/madvise.c:114 msgid "[-drsw] [off len]" msgstr "" #: .././io/madvise.c:115 msgid "give advice about use of memory" msgstr "" #: .././io/mincore.c:79 .././io/mincore.c:89 #, c-format msgid "0x%lx %lu pages (%llu : %lu)\n" msgstr "" #: .././io/mincore.c:109 msgid "[off len]" msgstr "" #: .././io/mincore.c:110 msgid "find mapping pages that are memory resident" msgstr "" #: .././io/mmap.c:70 #, c-format msgid "offset (%lld) is before start of mapping (%lld)\n" msgstr "" #: .././io/mmap.c:76 #, c-format msgid "offset (%lld) is beyond end of mapping (%lld)\n" msgstr "" #: .././io/mmap.c:81 #, c-format msgid "range (%lld:%lld) is beyond mapping (%lld:%ld)\n" msgstr "" #: .././io/mmap.c:87 #, c-format msgid "offset address (%p) is not page aligned\n" msgstr "" #: .././io/mmap.c:127 #, c-format msgid "" "\n" " maps a range within the current file into memory\n" "\n" " Example:\n" " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n" "\n" " Memory maps a range of a file for subsequent use by other xfs_io commands.\n" " With no arguments, mmap shows the current mappings. The current mapping\n" " can be set by using the single argument form (mapping number or address).\n" " If two arguments are specified (a range), a new mapping is created and the\n" " following options are available:\n" " -r -- map with PROT_READ protection\n" " -w -- map with PROT_WRITE protection\n" " -x -- map with PROT_EXEC protection\n" " -S -- map with MAP_SYNC and MAP_SHARED_VALIDATE flags\n" " -s -- first do mmap(size)/munmap(size), try to reserve some free " "space\n" " If no protection mode is specified, all are used by default.\n" "\n" msgstr "" #: .././io/mmap.c:163 .././io/mmap.c:170 .././io/init.c:116 #, c-format msgid "no mapped regions, try 'help mmap'\n" msgstr "" #: .././io/mmap.c:164 .././io/mmap.c:171 .././io/mmap.c:174 .././io/open.c:246 #: .././io/init.c:112 #, c-format msgid "no files are open, try 'help open'\n" msgstr "" #: .././io/mmap.c:280 #, c-format msgid "" "\n" " flushes a range of bytes in the current memory mapping\n" "\n" " Writes all modified copies of pages over the specified range (or entire\n" " mapping if no range specified) to their backing storage locations. Also,\n" " optionally invalidates so that subsequent references to the pages will be\n" " obtained from their backing storage locations (instead of cached copies).\n" " -a -- perform asynchronous writes (MS_ASYNC)\n" " -i -- invalidate mapped pages (MS_INVALIDATE)\n" " -s -- perform synchronous writes (MS_SYNC)\n" "\n" msgstr "" #: .././io/mmap.c:356 #, c-format msgid "" "\n" " reads a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n" "\n" " Accesses a range of the current memory mapping, optionally dumping it to\n" " the standard output stream (with -v option) for subsequent inspection.\n" " -f -- verbose mode, dump bytes with offsets relative to start of file.\n" " -r -- reverse order; start accessing from the end of range, moving " "backward\n" " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n" " The accesses are performed sequentially from the start offset by default.\n" " Notes:\n" " References to whole pages following the end of the backing file results\n" " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n" " on various filesystem conditions, including quota exceeded errors, and\n" " for physical device errors (such as unreadable disk blocks). No attempt\n" " has been made to catch signals at this stage...\n" "\n" msgstr "" #: .././io/mmap.c:520 #, c-format msgid "" "\n" " dirties a range of bytes in the current memory mapping\n" "\n" " Example:\n" " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n" "\n" " Stores a byte into memory for a range within a mapping.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -S -- use an alternate seed character\n" " -r -- reverse order; start storing from the end of range, moving backward\n" " The stores are performed sequentially from the start offset by default.\n" "\n" msgstr "" #: .././io/mmap.c:556 .././io/pread.c:428 .././io/pwrite.c:342 #: .././io/pwrite.c:371 #, c-format msgid "non-numeric seed -- %s\n" msgstr "" #: .././io/mmap.c:608 #, c-format msgid "" "\n" " resizes the current memory mapping\n" "\n" " Examples:\n" " 'mremap 8192' - resizes the current mapping to 8192 bytes.\n" "\n" " Resizes the mapping, growing or shrinking from the current size.\n" " The default stored value is 'X', repeated to fill the range specified.\n" " -f -- use MREMAP_FIXED flag to mremap on new_address\n" " -m -- use the MREMAP_MAYMOVE flag\n" "\n" msgstr "" #: .././io/mmap.c:686 msgid "[N] | [-rwxS] [-s size] [off len]" msgstr "" #: .././io/mmap.c:688 msgid "mmap a range in the current file, show mappings" msgstr "" #: .././io/mmap.c:697 msgid "[-r] [off len]" msgstr "" #: .././io/mmap.c:699 msgid "reads data from a region in the current memory mapping" msgstr "" #: .././io/mmap.c:708 msgid "[-ais] [off len]" msgstr "" #: .././io/mmap.c:709 msgid "flush a region in the current memory mapping" msgstr "" #: .././io/mmap.c:718 msgid "unmaps the current memory mapping" msgstr "" #: .././io/mmap.c:726 msgid "[-r] [-S seed] [off len]" msgstr "" #: .././io/mmap.c:728 msgid "writes data into a region in the current memory mapping" msgstr "" #: .././io/mmap.c:738 msgid "[-m|-f ] newsize" msgstr "" #: .././io/mmap.c:740 msgid "alters the size of the current memory mapping" msgstr "" #: .././io/truncate.c:25 #, c-format msgid "non-numeric truncate argument -- %s\n" msgstr "" #: .././io/truncate.c:45 msgid "off" msgstr "" #: .././io/truncate.c:47 msgid "truncates the current file at the given offset" msgstr "" #: .././io/label.c:27 #, c-format msgid "" "\n" " Manipulate or query the filesystem label while mounted.\n" "\n" " With no arguments, displays the current filesystem label.\n" " -s newlabel -- set the filesystem label to newlabel\n" " -c -- clear the filesystem label (sets to NULL string)\n" "\n" msgstr "" #: .././io/label.c:93 msgid "[-s label|-c]" msgstr "" #: .././io/label.c:96 msgid "query, set, or clear the filesystem label while mounted" msgstr "" #: .././io/swapext.c:21 #, c-format msgid "" "\n" " Swaps extents between the open file descriptor and the supplied filename.\n" "\n" msgstr "" #: .././io/swapext.c:85 msgid "" msgstr "" #: .././io/swapext.c:86 msgid "Swap extents between files." msgstr "" #: .././io/scrub.c:27 #, c-format msgid "" "\n" " Scrubs a piece of XFS filesystem metadata. The first argument is the type\n" " of metadata to examine. Allocation group metadata types take one AG " "number\n" " as the second parameter. Inode metadata types act on the currently open " "file\n" " or (optionally) take an inode number and generation number to act upon as\n" " the second and third parameters.\n" "\n" " Example:\n" " 'scrub inobt 3' - scrub the inode btree in AG 3.\n" " 'scrub bmapbtd 128 13525' - scrubs the extent map of inode 128 gen 13525.\n" "\n" " Known metadata scrub types are:" msgstr "" #: .././io/scrub.c:78 #, c-format msgid "Corruption detected.\n" msgstr "" #: .././io/scrub.c:80 .././io/scrub.c:265 #, c-format msgid "Optimization possible.\n" msgstr "" #: .././io/scrub.c:82 .././io/scrub.c:267 #, c-format msgid "Cross-referencing failed.\n" msgstr "" #: .././io/scrub.c:84 #, c-format msgid "Corruption detected during cross-referencing.\n" msgstr "" #: .././io/scrub.c:86 #, c-format msgid "Scan was not complete.\n" msgstr "" #: .././io/scrub.c:119 #, c-format msgid "Unknown type '%s'.\n" msgstr "" #: .././io/scrub.c:133 #, c-format msgid "Bad inode number '%s'.\n" msgstr "" #: .././io/scrub.c:140 #, c-format msgid "Bad generation number '%s'.\n" msgstr "" #: .././io/scrub.c:146 #, c-format msgid "Must specify inode number and generation.\n" msgstr "" #: .././io/scrub.c:154 #, c-format msgid "Must specify one AG number.\n" msgstr "" #: .././io/scrub.c:160 #, c-format msgid "Bad AG number '%s'.\n" msgstr "" #: .././io/scrub.c:168 #, c-format msgid "No parameters allowed.\n" msgstr "" #: .././io/scrub.c:198 .././io/scrub.c:295 msgid "type [agno|ino gen]" msgstr "" #: .././io/scrub.c:199 msgid "scrubs filesystem metadata" msgstr "" #: .././io/scrub.c:212 #, c-format msgid "" "\n" " Repairs a piece of XFS filesystem metadata. The first argument is the " "type\n" " of metadata to examine. Allocation group metadata types take one AG " "number\n" " as the second parameter. Inode metadata types act on the currently open " "file\n" " or (optionally) take an inode number and generation number to act upon as\n" " the second and third parameters.\n" "\n" " Example:\n" " 'repair inobt 3' - repairs the inode btree in AG 3.\n" " 'repair bmapbtd 128 13525' - repairs the extent map of inode 128 gen " "13525.\n" "\n" " Known metadata repairs types are:" msgstr "" #: .././io/scrub.c:263 #, c-format msgid "Corruption remains.\n" msgstr "" #: .././io/scrub.c:269 #, c-format msgid "Corruption still detected during cross-referencing.\n" msgstr "" #: .././io/scrub.c:271 #, c-format msgid "Repair was not complete.\n" msgstr "" #: .././io/scrub.c:273 #, c-format msgid "Metadata did not need repair or optimization.\n" msgstr "" #: .././io/scrub.c:296 msgid "repairs filesystem metadata" msgstr "" #: .././io/stat.c:41 msgid "socket" msgstr "" #: .././io/stat.c:43 .././repair/da_util.c:73 .././scrub/unicrash.c:689 #: .././scrub/phase5.c:112 msgid "directory" msgstr "" #: .././io/stat.c:45 msgid "char device" msgstr "" #: .././io/stat.c:47 msgid "block device" msgstr "" #: .././io/stat.c:49 msgid "regular file" msgstr "" #: .././io/stat.c:51 msgid "symbolic link" msgstr "" #: .././io/stat.c:53 msgid "fifo" msgstr "" #: .././io/stat.c:85 .././io/stat.c:185 #, c-format msgid "fd.path = \"%s\"\n" msgstr "" #: .././io/stat.c:86 #, c-format msgid "fd.flags = %s,%s,%s%s%s%s%s\n" msgstr "" #: .././io/stat.c:87 .././io/file.c:29 msgid "sync" msgstr "" #: .././io/stat.c:87 .././io/file.c:29 msgid "non-sync" msgstr "" #: .././io/stat.c:88 .././io/file.c:30 msgid "direct" msgstr "" #: .././io/stat.c:88 .././io/file.c:30 msgid "non-direct" msgstr "" #: .././io/stat.c:89 .././io/file.c:31 msgid "read-only" msgstr "" #: .././io/stat.c:89 .././io/file.c:31 msgid "read-write" msgstr "" #: .././io/stat.c:90 .././io/file.c:32 msgid ",real-time" msgstr "" #: .././io/stat.c:91 .././io/file.c:33 msgid ",append-only" msgstr "" #: .././io/stat.c:92 .././io/file.c:34 msgid ",non-block" msgstr "" #: .././io/stat.c:93 .././io/file.c:35 msgid ",tmpfile" msgstr "" #: .././io/stat.c:106 #, c-format msgid "fsxattr.xflags = 0x%x " msgstr "" #: .././io/stat.c:108 #, c-format msgid "fsxattr.projid = %u\n" msgstr "" #: .././io/stat.c:109 #, c-format msgid "fsxattr.extsize = %u\n" msgstr "" #: .././io/stat.c:110 #, c-format msgid "fsxattr.cowextsize = %u\n" msgstr "" #: .././io/stat.c:111 #, c-format msgid "fsxattr.nextents = %u\n" msgstr "" #: .././io/stat.c:112 #, c-format msgid "fsxattr.naextents = %u\n" msgstr "" #: .././io/stat.c:117 #, c-format msgid "dioattr.mem = 0x%x\n" msgstr "" #: .././io/stat.c:118 #, c-format msgid "dioattr.miniosz = %u\n" msgstr "" #: .././io/stat.c:119 #, c-format msgid "dioattr.maxiosz = %u\n" msgstr "" #: .././io/stat.c:157 .././io/stat.c:361 #, c-format msgid "stat.ino = %lld\n" msgstr "" #: .././io/stat.c:158 .././io/stat.c:362 #, c-format msgid "stat.type = %s\n" msgstr "" #: .././io/stat.c:159 .././io/stat.c:363 #, c-format msgid "stat.size = %lld\n" msgstr "" #: .././io/stat.c:160 .././io/stat.c:364 #, c-format msgid "stat.blocks = %lld\n" msgstr "" #: .././io/stat.c:162 .././io/stat.c:366 #, c-format msgid "stat.atime = %s" msgstr "" #: .././io/stat.c:163 .././io/stat.c:367 #, c-format msgid "stat.mtime = %s" msgstr "" #: .././io/stat.c:164 .././io/stat.c:368 #, c-format msgid "stat.ctime = %s" msgstr "" #: .././io/stat.c:189 #, c-format msgid "statfs.f_bsize = %lld\n" msgstr "" #: .././io/stat.c:190 #, c-format msgid "statfs.f_blocks = %lld\n" msgstr "" #: .././io/stat.c:191 #, c-format msgid "statfs.f_bavail = %lld\n" msgstr "" #: .././io/stat.c:192 #, c-format msgid "statfs.f_files = %lld\n" msgstr "" #: .././io/stat.c:193 #, c-format msgid "statfs.f_ffree = %lld\n" msgstr "" #: .././io/stat.c:195 #, c-format msgid "statfs.f_flags = 0x%llx\n" msgstr "" #: .././io/stat.c:204 #, c-format msgid "geom.bsize = %u\n" msgstr "" #: .././io/stat.c:205 #, c-format msgid "geom.agcount = %u\n" msgstr "" #: .././io/stat.c:206 #, c-format msgid "geom.agblocks = %u\n" msgstr "" #: .././io/stat.c:207 #, c-format msgid "geom.datablocks = %llu\n" msgstr "" #: .././io/stat.c:209 #, c-format msgid "geom.rtblocks = %llu\n" msgstr "" #: .././io/stat.c:211 #, c-format msgid "geom.rtextents = %llu\n" msgstr "" #: .././io/stat.c:213 #, c-format msgid "geom.rtextsize = %u\n" msgstr "" #: .././io/stat.c:214 #, c-format msgid "geom.sunit = %u\n" msgstr "" #: .././io/stat.c:215 #, c-format msgid "geom.swidth = %u\n" msgstr "" #: .././io/stat.c:220 #, c-format msgid "counts.freedata = %llu\n" msgstr "" #: .././io/stat.c:222 #, c-format msgid "counts.freertx = %llu\n" msgstr "" #: .././io/stat.c:224 #, c-format msgid "counts.freeino = %llu\n" msgstr "" #: .././io/stat.c:226 #, c-format msgid "counts.allocino = %llu\n" msgstr "" #: .././io/stat.c:252 #, c-format msgid "" "\n" " Display extended file status.\n" "\n" " Options:\n" " -v -- More verbose output\n" " -r -- Print raw statx structure fields\n" " -m mask -- Specify the field mask for the statx call\n" " (can also be 'basic' or 'all'; default STATX_ALL)\n" " -D -- Don't sync attributes with the server\n" " -F -- Force the attributes to be sync'd with the server\n" "\n" msgstr "" #: .././io/stat.c:323 #, c-format msgid "non-numeric mask -- %s\n" msgstr "" #: .././io/stat.c:370 #, c-format msgid "stat.btime = %s" msgstr "" #: .././io/stat.c:390 msgid "[-v|-r]" msgstr "" #: .././io/stat.c:391 msgid "statistics on the currently open file" msgstr "" #: .././io/stat.c:398 msgid "[-v|-r][-m basic | -m all | -m ][-FD]" msgstr "" #: .././io/stat.c:399 msgid "extended statistics on the currently open file" msgstr "" #: .././io/stat.c:406 msgid "statistics on the filesystem of the currently open file" msgstr "" #: .././io/inject.c:93 #, c-format msgid "" "\n" " inject errors into the filesystem of the currently open file\n" "\n" " Example:\n" " 'inject readagf' - cause errors on allocation group freespace reads\n" "\n" " Causes the kernel to generate and react to errors within XFS, provided\n" " the XFS kernel code has been built with debugging features enabled.\n" " With no arguments, displays the list of error injection tags.\n" "\n" msgstr "" #: .././io/inject.c:119 #, c-format msgid "no such tag -- %s\n" msgstr "" #: .././io/inject.c:140 msgid "[tag ...]" msgstr "" #: .././io/inject.c:141 msgid "inject errors into a filesystem" msgstr "" #: .././io/crc32cselftest.c:30 msgid "self test of crc32c implementation" msgstr "" #: .././io/imap.c:40 #, c-format msgid "ino %10 count %2d mask %016\n" msgstr "" #: .././io/imap.c:62 msgid "[nentries]" msgstr "" #: .././io/imap.c:64 msgid "inode map for filesystem of current file" msgstr "" #: .././io/open.c:205 #, c-format msgid "" "\n" " opens a new file in the requested mode\n" "\n" " Example:\n" " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n" "\n" " Opens a file for subsequent use by all of the other xfs_io commands.\n" " With no arguments, open uses the stat command to show the current file.\n" " -a -- open with the O_APPEND flag (append-only mode)\n" " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n" " -f -- open with O_CREAT (create the file if it doesn't exist)\n" " -m -- permissions to use in case a new file is created (default 0600)\n" " -n -- open with O_NONBLOCK\n" " -r -- open with O_RDONLY, the default is O_RDWR\n" " -s -- open with O_SYNC\n" " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n" " -R -- mark the file as a realtime XFS file immediately after opening it\n" " -T -- open with O_TMPFILE (create a file not visible in the namespace)\n" " -P -- open with O_PATH (create an fd that is merely a location reference)\n" " -L -- open with O_NOFOLLOW (don't follow symlink)\n" " Note1: usually read/write direct IO requests must be blocksize aligned;\n" " some kernels, however, allow sectorsize alignment for direct IO.\n" " Note2: the bmap for non-regular files can be obtained provided the file\n" " was opened correctly (in particular, must be opened read-only).\n" "\n" msgstr "" #: .././io/open.c:268 .././io/init.c:175 #, c-format msgid "non-numeric mode -- %s\n" msgstr "" #: .././io/open.c:306 #, c-format msgid "-T and -r options are incompatible\n" msgstr "" #: .././io/open.c:312 #, c-format msgid "-P and -L are incompatible with the other options\n" msgstr "" #: .././io/open.c:367 #, c-format msgid "" "\n" " displays the project identifier associated with the current path\n" "\n" " Options:\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, but only list projects on directories\n" "\n" msgstr "" #: .././io/open.c:390 .././io/open.c:462 .././io/open.c:586 .././io/open.c:608 #: .././io/attr.c:166 .././io/attr.c:242 .././io/cowextsize.c:95 #: .././io/cowextsize.c:118 .././libxfs/init.c:112 .././mkfs/proto.c:283 #: .././quota/project.c:106 .././quota/project.c:151 .././quota/project.c:198 #, c-format msgid "%s: cannot open %s: %s\n" msgstr "" #: .././io/open.c:433 #, c-format msgid "projid = %u\n" msgstr "" #: .././io/open.c:441 #, c-format msgid "" "\n" " modifies the project identifier associated with the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying projects on directories\n" "\n" msgstr "" #: .././io/open.c:500 #, c-format msgid "invalid project ID -- %s\n" msgstr "" #: .././io/open.c:516 #, c-format msgid "" "\n" " report or modify preferred extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying extsize on directories\n" "\n" msgstr "" #: .././io/open.c:559 .././io/cowextsize.c:67 #, c-format msgid "invalid target file type - file %s\n" msgstr "" #: .././io/open.c:645 #, c-format msgid "non-numeric extsize argument -- %s\n" msgstr "" #: .././io/open.c:668 #, c-format msgid "" "\n" "Query physical information about an inode\n" " Default:\t-- Return 1 if any inode number greater than 32 bits exists in\n" "\t\t the filesystem, or 0 if none exist\n" " num\t\t-- Return inode number [num] if in use, or 0 if not in use\n" " -n num\t-- Return the next used inode after [num]\n" " -v\t\t-- Verbose mode - display returned inode number's size in bits\n" "\n" msgstr "" #: .././io/open.c:755 #, c-format msgid "%s is not a numeric inode value\n" msgstr "" #: .././io/open.c:844 #, c-format msgid "" "\n" " Change the read/write permissions on the current file\n" "\n" " Options:\n" " -r -- make the file read only (0444 permissions)\n" " -w -- make the file read/write (0664 permissions)\n" "\n" msgstr "" #: .././io/open.c:892 msgid "[-acdrstxRTPL] [-m mode] [path]" msgstr "" #: .././io/open.c:893 msgid "open the file specified by path" msgstr "" #: .././io/open.c:902 msgid "close the current open file" msgstr "" #: .././io/open.c:906 msgid "[-D | -R] projid" msgstr "" #: .././io/open.c:911 msgid "change project identifier on the currently open file" msgstr "" #: .././io/open.c:916 msgid "[-D | -R]" msgstr "" #: .././io/open.c:921 msgid "list project identifier set on the currently open file" msgstr "" #: .././io/open.c:926 msgid "[-D | -R] [extsize]" msgstr "" #: .././io/open.c:931 msgid "get/set preferred extent size (in bytes) for the open file" msgstr "" #: .././io/open.c:936 msgid "[-nv] [num]" msgstr "" #: .././io/open.c:941 msgid "Query inode number usage in the filesystem" msgstr "" #: .././io/open.c:946 msgid "-r | -w" msgstr "" #: .././io/open.c:951 msgid "change the read/write permissions on the currently open file" msgstr "" #: .././io/attr.c:49 #, c-format msgid "" "\n" " displays the set of extended inode flags associated with the current file\n" "\n" " Each individual flag is displayed as a single character, in this order:\n" " r -- file data is stored in the realtime section\n" " p -- file has preallocated extents (cannot be changed using chattr)\n" " i -- immutable, file cannot be modified\n" " a -- append-only, file can only be appended to\n" " s -- all updates are synchronous\n" " A -- the access time is not updated for this inode\n" " d -- do not include this file in a dump of the filesystem\n" " t -- child created in this directory has realtime bit set by default\n" " P -- child created in this directory has parents project ID by default\n" " n -- symbolic links cannot be created in this directory\n" " e -- for non-realtime files, observe the inode extent size value\n" " E -- children created in this directory inherit the extent size value\n" " f -- do not include this file when defragmenting the filesystem\n" " S -- enable filestreams allocator for this directory\n" " x -- Use direct access (DAX) for data in this file\n" " C -- for files with shared blocks, observe the inode CoW extent size value\n" " X -- file has extended attributes (cannot be changed using chattr)\n" "\n" " Options:\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, but only list attributes on directories\n" " -a -- show all flags which can be set alongside those which are set\n" " -v -- verbose mode; show long names of flags, not single characters\n" "\n" msgstr "" #: .././io/attr.c:83 #, c-format msgid "" "\n" " modifies the set of extended inode flags associated with the current file\n" "\n" " Examples:\n" " 'chattr +a' - sets the append-only flag\n" " 'chattr -a' - clears the append-only flag\n" "\n" " -R -- recursively descend (useful when current file is a directory)\n" " -D -- recursively descend, only modifying attributes on directories\n" " +/-r -- set/clear the realtime flag\n" " +/-i -- set/clear the immutable flag\n" " +/-a -- set/clear the append-only flag\n" " +/-s -- set/clear the sync flag\n" " +/-A -- set/clear the no-atime flag\n" " +/-d -- set/clear the no-dump flag\n" " +/-t -- set/clear the realtime inheritance flag\n" " +/-P -- set/clear the project ID inheritance flag\n" " +/-n -- set/clear the no-symbolic-links flag\n" " +/-e -- set/clear the extent-size flag\n" " +/-E -- set/clear the extent-size inheritance flag\n" " +/-f -- set/clear the no-defrag flag\n" " +/-S -- set/clear the filestreams allocator flag\n" " +/-x -- set/clear the direct access (DAX) flag\n" " +/-C -- set/clear the CoW extent-size flag\n" " Note1: user must have certain capabilities to modify immutable/append-" "only.\n" " Note2: immutable/append-only files cannot be deleted; removing these files\n" " requires the immutable/append-only flag to be cleared first.\n" " Note3: the realtime flag can only be set if the filesystem has a realtime\n" " section, and the (regular) file must be empty when the flag is set.\n" "\n" msgstr "" #: .././io/attr.c:169 .././io/attr.c:216 .././io/attr.c:245 .././io/attr.c:316 #: .././quota/project.c:110 .././quota/project.c:156 .././quota/project.c:203 #, c-format msgid "%s: cannot get flags on %s: %s\n" msgstr "" #: .././io/attr.c:251 .././io/attr.c:322 #, c-format msgid "%s: cannot set flags on %s: %s\n" msgstr "" #: .././io/attr.c:286 .././io/attr.c:300 #, c-format msgid "%s: unknown flag\n" msgstr "" #: .././io/attr.c:306 #, c-format msgid "%s: bad chattr command, not +/-X\n" msgstr "" #: .././io/attr.c:333 msgid "[-R|-D] [+/-" msgstr "" #: .././io/attr.c:338 msgid "change extended inode flags on the currently open file" msgstr "" #: .././io/attr.c:343 msgid "[-R|-D|-a|-v]" msgstr "" #: .././io/attr.c:348 msgid "list extended inode flags set on the currently open file" msgstr "" #: .././io/bmap.c:20 #, c-format msgid "" "\n" " prints the block mapping for an XFS file's data or attribute forks\n" " Example:\n" " 'bmap -vp' - tabular format verbose map, including unwritten extents\n" "\n" " bmap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -c -- prints the copy-on-write fork map instead of the data fork.\n" " This works only if the kernel was compiled in debug mode.\n" " -d -- suppresses a DMAPI read event, offline portions shown as holes.\n" " -e -- print delayed allocation extents.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " -n -- query n extents.\n" " -p -- obtain all unwritten extents as well (w/ -v show which are " "unwritten.)\n" " -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n" " Note: the bmap for non-regular files can be obtained provided the file\n" " was opened appropriately (in particular, must be opened read-only).\n" "\n" msgstr "" #: .././io/bmap.c:112 .././io/fsmap.c:454 #, c-format msgid "%s: can't get geometry [\"%s\"]: %s\n" msgstr "" #: .././io/bmap.c:120 #, c-format msgid "%s: cannot read attrs on \"%s\": %s\n" msgstr "" #: .././io/bmap.c:138 .././io/fiemap.c:289 #, c-format msgid "%s: malloc of %d bytes failed.\n" msgstr "" #: .././io/bmap.c:186 #, c-format msgid "%s: xfsctl(XFS_IOC_GETBMAPX) iflags=0x%x [\"%s\"]: %s\n" msgstr "" #: .././io/bmap.c:217 #, c-format msgid "%s: cannot realloc %d bytes\n" msgstr "" #: .././io/bmap.c:226 #, c-format msgid "%s: no extents\n" msgstr "" #: .././io/bmap.c:240 .././io/bmap.c:375 .././io/fiemap.c:70 #, c-format msgid "hole" msgstr "" #: .././io/bmap.c:242 .././io/bmap.c:383 #, c-format msgid "delalloc" msgstr "" #: .././io/bmap.c:251 #, c-format msgid " %lld blocks\n" msgstr "" #: .././io/bmap.c:331 .././io/fiemap.c:105 .././io/fsmap.c:253 msgid "EXT" msgstr "" #: .././io/bmap.c:332 .././io/fiemap.c:106 .././io/fsmap.c:257 msgid "FILE-OFFSET" msgstr "" #: .././io/bmap.c:333 msgid "RT-BLOCK-RANGE" msgstr "" #: .././io/bmap.c:333 .././io/fiemap.c:107 .././io/fsmap.c:255 msgid "BLOCK-RANGE" msgstr "" #: .././io/bmap.c:334 .././io/fsmap.c:258 msgid "AG" msgstr "" #: .././io/bmap.c:335 .././io/fsmap.c:259 msgid "AG-OFFSET" msgstr "" #: .././io/bmap.c:336 .././io/fiemap.c:108 .././io/fsmap.c:260 msgid "TOTAL" msgstr "" #: .././io/bmap.c:337 .././io/fsmap.c:261 msgid " FLAGS" msgstr "" #: .././io/bmap.c:417 .././io/fsmap.c:351 #, c-format msgid " FLAG Values:\n" msgstr "" #: .././io/bmap.c:418 .././io/fsmap.c:354 #, c-format msgid " %*.*o Shared extent\n" msgstr "" #: .././io/bmap.c:420 .././io/fsmap.c:356 #, c-format msgid " %*.*o Unwritten preallocated extent\n" msgstr "" #: .././io/bmap.c:422 .././io/fsmap.c:358 #, c-format msgid " %*.*o Doesn't begin on stripe unit\n" msgstr "" #: .././io/bmap.c:424 .././io/fsmap.c:360 #, c-format msgid " %*.*o Doesn't end on stripe unit\n" msgstr "" #: .././io/bmap.c:426 .././io/fsmap.c:362 #, c-format msgid " %*.*o Doesn't begin on stripe width\n" msgstr "" #: .././io/bmap.c:428 .././io/fsmap.c:364 #, c-format msgid " %*.*o Doesn't end on stripe width\n" msgstr "" #: .././io/bmap.c:444 msgid "[-adlpv] [-n nx]" msgstr "" #: .././io/bmap.c:445 msgid "print block mapping for an XFS file" msgstr "" #: .././io/bulkstat.c:66 #, c-format msgid "" "Bulk-queries the filesystem for inode stat information and prints it.\n" "\n" " -a Only iterate this AG.\n" " -d Print debugging output.\n" " -e Stop after this inode.\n" " -n Ask for this many results at once.\n" " -s Inode to start with.\n" " -v Use this version of the ioctl (1 or 5).\n" msgstr "" #: .././io/bulkstat.c:188 #, c-format msgid "bulkstat: startino=%lld flags=0x%x agno=%u ret=%d icount=%u ocount=%u\n" msgstr "" #: .././io/bulkstat.c:217 #, c-format msgid "" "Queries the filesystem for a single inode's stat information and prints it.\n" "If a given inode is not allocated, information about the next allocated \n" "inode will be printed instead.\n" "\n" " -v (ver) Use this version of the ioctl (1 or 5).\n" " -d Print debugging information.\n" "\n" "Pass in inode numbers or a special inode name:\n" " root Root directory.\n" msgstr "" #: .././io/bulkstat.c:316 #, c-format msgid "bulkstat_single: startino=% flags=0x% ret=%d\n" msgstr "" #: .././io/bulkstat.c:339 #, c-format msgid "" "Queries the filesystem for inode group information and prints it.\n" "\n" " -a Only iterate this AG.\n" " -d Print debugging output.\n" " -e Stop after this inode.\n" " -n Ask for this many results at once.\n" " -s Inode to start with.\n" " -v Use this version of the ioctl (1 or 5).\n" msgstr "" #: .././io/bulkstat.c:444 #, c-format msgid "" "bulkstat: startino=% flags=0x% agno=% ret=%d icount=" "% ocount=%\n" msgstr "" #: .././io/bulkstat.c:500 .././io/bulkstat.c:507 msgid "[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]" msgstr "" #: .././io/bulkstat.c:501 msgid "Bulk stat of inodes in a filesystem" msgstr "" #: .././io/bulkstat.c:503 msgid "[-d] [-v version] inum..." msgstr "" #: .././io/bulkstat.c:504 msgid "Stat one inode in a filesystem" msgstr "" #: .././io/bulkstat.c:508 msgid "Query inode groups in a filesystem" msgstr "" #: .././io/cowextsize.c:26 #, c-format msgid "" "\n" " report or modify preferred CoW extent size (in bytes) for the current path\n" "\n" " -R -- recursively descend (useful when current path is a directory)\n" " -D -- recursively descend, only modifying cowextsize on directories\n" "\n" msgstr "" #: .././io/cowextsize.c:155 #, c-format msgid "non-numeric cowextsize argument -- %s\n" msgstr "" #: .././io/cowextsize.c:179 msgid "[-D | -R] [cowextsize]" msgstr "" #: .././io/cowextsize.c:184 msgid "get/set preferred CoW extent size (in bytes) for the open file" msgstr "" #: .././io/encrypt.c:160 #, c-format msgid "" "\n" " display the encryption policy of the current file\n" "\n" " -1 -- Use only the old ioctl to get the encryption policy.\n" " This only works if the file has a v1 encryption policy.\n" " -t -- Test whether v2 encryption policies are supported.\n" " Prints \"supported\", \"unsupported\", or an error message.\n" "\n" msgstr "" #: .././io/encrypt.c:176 #, c-format msgid "" "\n" " assign an encryption policy to the currently open file\n" "\n" " Examples:\n" " 'set_encpolicy' - assign v1 policy with default key descriptor\n" " (0000000000000000)\n" " 'set_encpolicy -v 2' - assign v2 policy with default key identifier\n" " (00000000000000000000000000000000)\n" " 'set_encpolicy 0000111122223333' - assign v1 policy with given key " "descriptor\n" " 'set_encpolicy 00001111222233334444555566667777' - assign v2 policy with " "given\n" " key identifier\n" "\n" " -c MODE -- contents encryption mode\n" " -n MODE -- filenames encryption mode\n" " -f FLAGS -- policy flags\n" " -v VERSION -- policy version\n" "\n" " MODE can be numeric or one of the following predefined values:\n" msgstr "" #: .././io/encrypt.c:202 #, c-format msgid "" " FLAGS and VERSION must be numeric.\n" "\n" " Note that it's only possible to set an encryption policy on an empty\n" " directory. It's then inherited by new files and subdirectories.\n" "\n" msgstr "" #: .././io/encrypt.c:213 #, c-format msgid "" "\n" " add an encryption key to the filesystem\n" "\n" " Examples:\n" " 'add_enckey' - add key for v2 policies\n" " 'add_enckey -d 0000111122223333' - add key for v1 policies w/ given " "descriptor\n" "\n" "The key in binary is read from standard input.\n" " -d DESCRIPTOR -- master_key_descriptor\n" "\n" msgstr "" #: .././io/encrypt.c:229 #, c-format msgid "" "\n" " remove an encryption key from the filesystem\n" "\n" " Examples:\n" " 'rm_enckey 0000111122223333' - remove key for v1 policies w/ given " "descriptor\n" " 'rm_enckey 00001111222233334444555566667777' - remove key for v2 policies " "w/ given identifier\n" "\n" " -a -- remove key for all users who have added it (privileged operation)\n" "\n" msgstr "" #: .././io/encrypt.c:244 #, c-format msgid "" "\n" " get the status of a filesystem encryption key\n" "\n" " Examples:\n" " 'enckey_status 0000111122223333' - get status of v1 policy key\n" " 'enckey_status 00001111222233334444555566667777' - get status of v2 policy " "key\n" "\n" msgstr "" #: .././io/encrypt.c:353 msgid "descriptor" msgstr "" #: .././io/encrypt.c:355 msgid "identifier" msgstr "" #: .././io/encrypt.c:357 .././io/encrypt.c:369 msgid "[unknown]" msgstr "" #: .././io/encrypt.c:377 #, c-format msgid "invalid key descriptor: %s\n" msgstr "" #: .././io/encrypt.c:388 #, c-format msgid "invalid key identifier: %s\n" msgstr "" #: .././io/encrypt.c:418 #, c-format msgid "invalid key specifier: %s\n" msgstr "" #: .././io/encrypt.c:443 #, c-format msgid "supported\n" msgstr "" #: .././io/encrypt.c:447 #, c-format msgid "unsupported\n" msgstr "" #: .././io/encrypt.c:451 #, c-format msgid "" "%s: unexpected error checking for FS_IOC_GET_ENCRYPTION_POLICY_EX support: " "%s\n" msgstr "" #: .././io/encrypt.c:459 .././io/encrypt.c:475 .././io/encrypt.c:543 #, c-format msgid "Encryption policy for %s:\n" msgstr "" #: .././io/encrypt.c:460 .././io/encrypt.c:476 #, c-format msgid "\tPolicy version: %u\n" msgstr "" #: .././io/encrypt.c:461 #, c-format msgid "\tMaster key descriptor: %s\n" msgstr "" #: .././io/encrypt.c:463 .././io/encrypt.c:479 #, c-format msgid "\tContents encryption mode: %u (%s)\n" msgstr "" #: .././io/encrypt.c:466 .././io/encrypt.c:482 #, c-format msgid "\tFilenames encryption mode: %u (%s)\n" msgstr "" #: .././io/encrypt.c:469 .././io/encrypt.c:485 #, c-format msgid "\tFlags: 0x%02x\n" msgstr "" #: .././io/encrypt.c:477 #, c-format msgid "\tMaster key identifier: %s\n" msgstr "" #: .././io/encrypt.c:529 #, c-format msgid "%s: failed to get encryption policy: %s\n" msgstr "" #: .././io/encrypt.c:544 #, c-format msgid "\tPolicy version: %u (unknown)\n" msgstr "" #: .././io/encrypt.c:571 #, c-format msgid "invalid contents encryption mode: %s\n" msgstr "" #: .././io/encrypt.c:579 #, c-format msgid "invalid filenames encryption mode: %s\n" msgstr "" #: .././io/encrypt.c:586 #, c-format msgid "invalid flags: %s\n" msgstr "" #: .././io/encrypt.c:596 #, c-format msgid "invalid policy version: %s\n" msgstr "" #: .././io/encrypt.c:649 #, c-format msgid "%s: failed to set encryption policy: %s\n" msgstr "" #: .././io/encrypt.c:715 #, c-format msgid "Error reading key from stdin: %s\n" msgstr "" #: .././io/encrypt.c:722 #, c-format msgid "Invalid key; got > FSCRYPT_MAX_KEY_SIZE (%d) bytes on stdin!\n" msgstr "" #: .././io/encrypt.c:729 #, c-format msgid "Error adding encryption key: %s\n" msgstr "" #: .././io/encrypt.c:734 #, c-format msgid "Added encryption key with %s %s\n" msgstr "" #: .././io/encrypt.c:770 #, c-format msgid "Error removing encryption key: %s\n" msgstr "" #: .././io/encrypt.c:777 #, c-format msgid "Removed user's claim to encryption key with %s %s\n" msgstr "" #: .././io/encrypt.c:781 #, c-format msgid "Removed encryption key with %s %s, but files still busy\n" msgstr "" #: .././io/encrypt.c:784 #, c-format msgid "Removed encryption key with %s %s\n" msgstr "" #: .././io/encrypt.c:801 #, c-format msgid "Error getting encryption key status: %s\n" msgstr "" #: .././io/encrypt.c:809 #, c-format msgid "Present" msgstr "" #: .././io/encrypt.c:825 #, c-format msgid "Absent\n" msgstr "" #: .././io/encrypt.c:828 #, c-format msgid "Incompletely removed\n" msgstr "" #: .././io/encrypt.c:831 #, c-format msgid "Unknown status (%u)\n" msgstr "" #: .././io/encrypt.c:841 msgid "[-1] [-t]" msgstr "" #: .././io/encrypt.c:846 msgid "display the encryption policy of the current file" msgstr "" #: .././io/encrypt.c:852 msgid "[-c mode] [-n mode] [-f flags] [-v version] [keyspec]" msgstr "" #: .././io/encrypt.c:857 msgid "assign an encryption policy to the current file" msgstr "" #: .././io/encrypt.c:862 msgid "[-d descriptor]" msgstr "" #: .././io/encrypt.c:866 msgid "add an encryption key to the filesystem" msgstr "" #: .././io/encrypt.c:871 msgid "[-a] keyspec" msgstr "" #: .././io/encrypt.c:876 msgid "remove an encryption key from the filesystem" msgstr "" #: .././io/encrypt.c:881 msgid "keyspec" msgstr "" #: .././io/encrypt.c:886 msgid "get the status of a filesystem encryption key" msgstr "" #: .././io/fiemap.c:23 #, c-format msgid "" "\n" " prints the block mapping for a file's data or attribute forks\n" " Example:\n" " 'fiemap -v' - tabular format verbose map\n" "\n" " fiemap prints the map of disk blocks used by the current file.\n" " The map lists each extent used by the file, as well as regions in the\n" " file that do not have any corresponding blocks (holes).\n" " By default, each line of the listing takes the following form:\n" " extent: [startoffset..endoffset]: startblock..endblock\n" " Holes are marked by replacing the startblock..endblock with 'hole'.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -a -- prints the attribute fork map instead of the data fork.\n" " -l -- also displays the length of each extent in 512-byte blocks.\n" " -n -- query n extents.\n" " -v -- Verbose information\n" " offset is the starting offset to map, and is optional. If offset is\n" " specified, mapping length may (optionally) be specified as well.\n" msgstr "" #: .././io/fiemap.c:62 .././io/fiemap.c:169 #, c-format msgid " %llu blocks\n" msgstr "" #: .././io/fiemap.c:109 msgid "FLAGS" msgstr "" #: .././io/fiemap.c:393 msgid "[-alv] [-n nx] [offset [len]]" msgstr "" #: .././io/fiemap.c:394 msgid "print block mapping for a file" msgstr "" #: .././io/file.c:26 #, c-format msgid "%c%03d%c %-14s (%s,%s,%s,%s%s%s%s%s%s%s)\n" msgstr "" #: .././io/file.c:28 msgid "foreign" msgstr "" #: .././io/file.c:28 msgid "xfs" msgstr "" #: .././io/file.c:36 msgid ",path" msgstr "" #: .././io/file.c:37 msgid ",nofollow" msgstr "" #: .././io/file.c:71 .././io/sendfile.c:89 .././quota/path.c:114 #, c-format msgid "value %d is out of range (0-%d)\n" msgstr "" #: .././io/file.c:84 .././quota/path.c:128 msgid "[N]" msgstr "" #: .././io/file.c:89 msgid "set the current file" msgstr "" #: .././io/file.c:98 msgid "list current open files and memory mappings" msgstr "" #: .././io/freeze.c:24 #, c-format msgid "%s: cannot freeze filesystem at %s: %s\n" msgstr "" #: .././io/freeze.c:41 #, c-format msgid "%s: cannot unfreeze filesystem mounted at %s: %s\n" msgstr "" #: .././io/freeze.c:57 msgid "freeze filesystem of current file" msgstr "" #: .././io/freeze.c:64 msgid "unfreeze filesystem of current file" msgstr "" #: .././io/fsmap.c:21 #, c-format msgid "" "\n" " Prints the block mapping for the filesystem hosting the current file\n" " fsmap prints the map of disk blocks used by the whole filesystem.\n" " When possible, owner and offset information will be included in the\n" " space report.\n" "\n" " By default, each line of the listing takes the following form:\n" " extent: major:minor [startblock..endblock]: owner startoffset.." "endoffset length\n" " The owner field is either an inode number or a special value.\n" " All the file offsets and disk blocks are in units of 512-byte blocks.\n" " -d -- query only the data device (default).\n" " -l -- query only the log device.\n" " -r -- query only the realtime device.\n" " -n -- query n extents at a time.\n" " -m -- output machine-readable format.\n" " -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -" "v\n" "\n" "The optional start and end arguments require one of -d, -l, or -r to be " "set.\n" "\n" msgstr "" #: .././io/fsmap.c:51 msgid "free space" msgstr "" #: .././io/fsmap.c:53 msgid "unknown" msgstr "" #: .././io/fsmap.c:55 msgid "static fs metadata" msgstr "" #: .././io/fsmap.c:57 msgid "journalling log" msgstr "" #: .././io/fsmap.c:59 msgid "per-AG metadata" msgstr "" #: .././io/fsmap.c:61 msgid "inode btree" msgstr "" #: .././io/fsmap.c:63 .././repair/progress.c:17 .././scrub/phase7.c:195 msgid "inodes" msgstr "" #: .././io/fsmap.c:65 msgid "refcount btree" msgstr "" #: .././io/fsmap.c:67 msgid "cow reservation" msgstr "" #: .././io/fsmap.c:69 msgid "defective" msgstr "" #: .././io/fsmap.c:71 #, c-format msgid "special %u:%u" msgstr "" #: .././io/fsmap.c:96 #, c-format msgid "inode %lld %s extent map" msgstr "" #: .././io/fsmap.c:99 #, c-format msgid "inode %lld %s %lld..%lld" msgstr "" #: .././io/fsmap.c:103 #, c-format msgid " %lld\n" msgstr "" #: .././io/fsmap.c:119 #, c-format msgid "EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n" msgstr "" #: .././io/fsmap.c:130 #, c-format msgid "inode_%lld_%s_bmbt,,," msgstr "" #: .././io/fsmap.c:133 #, c-format msgid "inode_%lld_%s,%lld,%lld," msgstr "" #: .././io/fsmap.c:228 msgid "extent_map" msgstr "" #: .././io/fsmap.c:254 msgid "DEV" msgstr "" #: .././io/fsmap.c:256 msgid "OWNER" msgstr "" #: .././io/fsmap.c:326 msgid "extent map" msgstr "" #: .././io/fsmap.c:352 #, c-format msgid " %*.*o Attribute fork\n" msgstr "" #: .././io/fsmap.c:432 #, c-format msgid "Bad rmap start_bblock %s.\n" msgstr "" #: .././io/fsmap.c:443 #, c-format msgid "Bad rmap end_bblock %s.\n" msgstr "" #: .././io/fsmap.c:464 #, c-format msgid "%s: malloc of %zu bytes failed.\n" msgstr "" #: .././io/fsmap.c:494 .././io/fsmap.c:533 #, c-format msgid "%s: xfsctl(XFS_IOC_GETFSMAP) iflags=0x%x [\"%s\"]: %s\n" msgstr "" #: .././io/fsmap.c:508 #, c-format msgid "%s: cannot realloc %zu bytes\n" msgstr "" #: .././io/fsmap.c:573 msgid "[-d|-l|-r] [-m|-v] [-n nx] [start] [end]" msgstr "" #: .././io/fsmap.c:574 msgid "print filesystem mapping for a range of blocks" msgstr "" #: .././io/link.c:22 #, c-format msgid "" "\n" "link the open file descriptor to the supplied filename\n" "\n" "\n" msgstr "" #: .././io/link.c:51 msgid "filename" msgstr "" #: .././io/link.c:53 msgid "link the open file descriptor to the supplied filename" msgstr "" #: .././io/log_writes.c:90 msgid "-d device -m mark" msgstr "" #: .././io/log_writes.c:92 msgid "create mark in the dm-log-writes log specified by " msgstr "" #: .././io/pread.c:22 #, c-format msgid "" "\n" " reads a range of bytes in a specified block size from the given offset\n" "\n" " Example:\n" " 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n" "\n" " Reads a segment of the currently open file, optionally dumping it to the\n" " standard output stream (with -v option) for subsequent inspection.\n" " The reads are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different pattern is requested.\n" " -B -- read backwards through the range from offset (backwards N bytes)\n" " -F -- read forwards through the range of bytes from offset (default)\n" " -v -- be verbose, dump out buffers (used when reading forwards)\n" " -R -- read at random offsets in the range of bytes\n" " -Z N -- zeed the random number generator (used when reading randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" " -V N -- use vectored IO with N iovecs of blocksize each (preadv)\n" "\n" " When in \"random\" mode, the number of read operations will equal the\n" " number required to do a complete forward/backward scan of the range.\n" " Note that the offset within the range is chosen at random each time\n" " (an offset may be read more than once when operating in this mode).\n" "\n" msgstr "" #: .././io/pread.c:389 .././io/pwrite.c:297 #, c-format msgid "non-numeric bsize -- %s\n" msgstr "" #: .././io/pread.c:419 .././io/pwrite.c:356 #, c-format msgid "non-numeric vector count == %s\n" msgstr "" #: .././io/pread.c:496 msgid "[-b bs] [-v] [-i N] [-FBR [-Z N]] off len" msgstr "" #: .././io/pread.c:497 msgid "reads a number of bytes at a specified offset" msgstr "" #: .././io/pwrite.c:19 #, c-format msgid "" "\n" " writes a range of bytes (in block size increments) from the given offset\n" "\n" " Example:\n" " 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Writes into a segment of the currently open file, using either a buffer\n" " filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n" " The writes are performed in sequential blocks starting at offset, with the\n" " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" " unless a different write pattern is requested.\n" " -S -- use an alternate seed number for filling the write buffer\n" " -i -- input file, source of data to write (used when writing forward)\n" " -d -- open the input file for direct IO\n" " -s -- skip a number of bytes at the start of the input file\n" " -w -- call fdatasync(2) at the end (included in timing results)\n" " -W -- call fsync(2) at the end (included in timing results)\n" " -B -- write backwards through the range from offset (backwards N bytes)\n" " -F -- write forwards through the range of bytes from offset (default)\n" " -O -- perform pwrite call once and return (maybe partial) bytes written\n" " -R -- write at random offsets in the specified range of bytes\n" " -Z N -- zeed the random number generator (used when writing randomly)\n" " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" " -V N -- use vectored IO with N iovecs of blocksize each (pwritev)\n" " -N -- Perform the pwritev2() with RWF_NOWAIT\n" " -D -- Perform the pwritev2() with RWF_DSYNC\n" "\n" msgstr "" #: .././io/pwrite.c:335 #, c-format msgid "non-numeric skip -- %s\n" msgstr "" #: .././io/pwrite.c:378 #, c-format msgid "%s: command -%c not supported\n" msgstr "" #: .././io/pwrite.c:465 msgid "" "[-i infile [-dDwNOW] [-s skip]] [-b bs] [-S seed] [-FBR [-Z N]] [-V N] off " "len" msgstr "" #: .././io/pwrite.c:467 msgid "writes a number of bytes at a specified offset" msgstr "" #: .././io/readdir.c:186 #, c-format msgid "read %llu bytes from offset %lld\n" msgstr "" #: .././io/readdir.c:187 #, c-format msgid "%s, %d ops, %s (%s/sec and %.4f ops/sec)\n" msgstr "" #: .././io/readdir.c:200 msgid "[-v][-o offset][-l length]" msgstr "" #: .././io/readdir.c:201 msgid "read directory entries" msgstr "" #: .././io/reflink.c:20 #, c-format msgid "" "\n" " Links a range of bytes (in block size increments) from a file into a range\n" " of bytes in the open file. The contents of both file ranges must match.\n" "\n" " Example:\n" " 'dedupe some_file 0 4096 32768' - links 32768 bytes from some_file at\n" " offset 0 to into the open file at\n" " position 4096\n" "\n" " Reflink a range of blocks from a given input file to the open file. Both\n" " files share the same range of physical disk blocks; a write to the shared\n" " range of either file should result in the write landing in a new block and\n" " that range of the file being remapped (i.e. copy-on-write). Both files\n" " must reside on the same filesystem, and the contents of both ranges must\n" " match.\n" msgstr "" #: .././io/reflink.c:75 msgid "Extents did not match." msgstr "" #: .././io/reflink.c:129 .././io/reflink.c:252 #, c-format msgid "non-numeric src offset argument -- %s\n" msgstr "" #: .././io/reflink.c:135 .././io/reflink.c:258 #, c-format msgid "non-numeric dest offset argument -- %s\n" msgstr "" #: .././io/reflink.c:141 .././io/reflink.c:264 #, c-format msgid "non-positive length argument -- %s\n" msgstr "" #: .././io/reflink.c:166 #, c-format msgid "" "\n" " Links a range of bytes (in block size increments) from a file into a range\n" " of bytes in the open file. The two extent ranges need not contain " "identical\n" " data.\n" "\n" " Example:\n" " 'reflink some_file 0 4096 32768' - links 32768 bytes from some_file at\n" " offset 0 to into the open file at\n" " position 4096\n" " 'reflink some_file' - links all bytes from some_file into the open file\n" " at position 0\n" "\n" " Reflink a range of blocks from a given input file to the open file. Both\n" " files share the same range of physical disk blocks; a write to the shared\n" " range of either file should result in the write landing in a new block and\n" " that range of the file being remapped (i.e. copy-on-write). Both files\n" " must reside on the same filesystem.\n" msgstr "" #: .././io/reflink.c:297 msgid "infile [src_off dst_off len]" msgstr "" #: .././io/reflink.c:299 msgid "reflinks an entire file, or a number of bytes at a specified offset" msgstr "" #: .././io/reflink.c:311 msgid "infile src_off dst_off len" msgstr "" #: .././io/reflink.c:313 msgid "dedupes a number of bytes at a specified offset" msgstr "" #: .././io/resblks.c:26 #, c-format msgid "non-numeric argument -- %s\n" msgstr "" #: .././io/resblks.c:38 #, c-format msgid "reserved blocks = %llu\n" msgstr "" #: .././io/resblks.c:40 #, c-format msgid "available reserved blocks = %llu\n" msgstr "" #: .././io/resblks.c:53 msgid "[blocks]" msgstr "" #: .././io/resblks.c:55 msgid "get and/or set count of reserved filesystem blocks" msgstr "" #: .././io/seek.c:20 #, c-format msgid "" "\n" " returns the next hole and/or data offset at or after the requested offset\n" "\n" " Example:\n" " 'seek -d 512'\t\t- offset of data at or following offset 512\n" " 'seek -a -r 0'\t- offsets of all data and hole in entire file\n" "\n" " Returns the offset of the next data and/or hole. There is an implied hole\n" " at the end of file. If the specified offset is past end of file, or there\n" " is no data past the specified offset, EOF is returned.\n" " -a\t-- return the next data and hole starting at the specified offset.\n" " -d\t-- return the next data starting at the specified offset.\n" " -h\t-- return the next hole starting at the specified offset.\n" " -r\t-- return all remaining type(s) starting at the specified offset.\n" " -s\t-- also print the starting offset.\n" "\n" msgstr "" #: .././io/seek.c:217 msgid "-a | -d | -h [-r] off" msgstr "" #: .././io/seek.c:218 msgid "locate the next data and/or hole" msgstr "" #: .././io/sendfile.c:19 #, c-format msgid "" "\n" " transfer a range of bytes from the given offset between files\n" "\n" " Example:\n" " 'send -f 2 512 20' - writes 20 bytes at 512 bytes into the open file\n" "\n" " Copies data between one file descriptor and another. Because this copying\n" " is done within the kernel, sendfile does not need to transfer data to and\n" " from user space.\n" " -f -- specifies an input file from which to source data to write\n" " -i -- specifies an input file name from which to source data to write.\n" " An offset and length in the source file can be optionally specified.\n" "\n" msgstr "" #: .././io/sendfile.c:159 msgid "-i infile | -f N [off len]" msgstr "" #: .././io/sendfile.c:161 msgid "Transfer data directly between file descriptors" msgstr "" #: .././io/shutdown.c:42 #, c-format msgid "" "\n" " Shuts down the filesystem and prevents any further IO from occurring.\n" "\n" " By default, shutdown will not flush completed transactions to disk\n" " before shutting the filesystem down, simulating a disk failure or crash.\n" " With -f, the log will be flushed to disk, matching XFS behavior when\n" " metadata corruption is encountered.\n" "\n" " -f -- Flush completed transactions to disk before shut down.\n" "\n" msgstr "" #: .././io/shutdown.c:62 msgid "[-f]" msgstr "" #: .././io/shutdown.c:65 msgid "shuts down the filesystem where the current file resides" msgstr "" #: .././io/sync.c:48 msgid "calls sync(2) to flush all in-core filesystem state to disk" msgstr "" #: .././io/sync.c:57 msgid "calls syncfs(2) to flush all in-core filesystem state to disk" msgstr "" #: .././io/sync_file_range.c:18 #, c-format msgid "" "\n" " Trigger specific writeback commands on a range of the current file\n" "\n" " With no options, the SYNC_FILE_RANGE_WRITE is implied.\n" " -a -- wait for IO to finish after writing (SYNC_FILE_RANGE_WAIT_AFTER).\n" " -b -- wait for IO to finish before writing (SYNC_FILE_RANGE_WAIT_BEFORE).\n" " -w -- write dirty data in range (SYNC_FILE_RANGE_WRITE).\n" "\n" msgstr "" #: .././io/sync_file_range.c:89 msgid "[-abw] off len" msgstr "" #: .././io/sync_file_range.c:90 msgid "Control writeback on a range of a file" msgstr "" #: .././io/utimes.c:18 #, c-format msgid "" "\n" " Update file atime and mtime of the current file with nansecond precision.\n" "\n" " Usage: utimes atime_sec atime_nsec mtime_sec mtime_nsec.\n" " *_sec: Seconds elapsed since 1970-01-01 00:00:00 UTC.\n" " *_nsec: Nanoseconds since the corresponding *_sec.\n" "\n" msgstr "" #: .././io/utimes.c:64 msgid "atime_sec atime_nsec mtime_sec mtime_nsec" msgstr "" #: .././io/utimes.c:65 msgid "Update file times of the current file" msgstr "" #: .././io/copy_file_range.c:19 #, c-format msgid "" "\n" " Copies a range of bytes from a file into the open file, overwriting any " "data\n" " already there.\n" "\n" " Example:\n" " 'copy_range -s 100 -d 200 -l 300 some_file' - copies 300 bytes from " "some_file\n" " at offset 100 into the open\n" "\t\t\t\t\t file at offset 200\n" " 'copy_range some_file' - copies all bytes from some_file into the open " "file\n" " at position 0\n" " 'copy_range -f 2' - copies all bytes from open file 2 into the current open " "file\n" " at position 0\n" msgstr "" #: .././io/copy_file_range.c:90 #, c-format msgid "invalid source offset -- %s\n" msgstr "" #: .././io/copy_file_range.c:97 #, c-format msgid "invalid destination offset -- %s\n" msgstr "" #: .././io/copy_file_range.c:104 #, c-format msgid "invalid length -- %s\n" msgstr "" #: .././io/copy_file_range.c:112 #, c-format msgid "file value %d is out of range (0-%d)\n" msgstr "" #: .././io/copy_file_range.c:159 msgid "[-s src_off] [-d dst_off] [-l len] src_file | -f N" msgstr "" #: .././io/copy_file_range.c:160 msgid "Copy a range of data between two files" msgstr "" #: .././io/prealloc.c:163 #, c-format msgid "" "\n" " modifies space associated with part of a file via fallocate\n" " Example:\n" " 'falloc 0 1m' - fills all holes within the first megabyte\n" "\n" " falloc uses the fallocate system call to alter space allocations in the\n" " open file. The following operations are supported:\n" " All the file offsets are in units of bytes.\n" " -c -- collapses the given range.\n" " -i -- inserts a hole into the given range of the file.\n" " -k -- do not change file size.\n" " -p -- unmap the given range from the file.\n" " -u -- unshare shared extents in the given range.\n" "\n" msgstr "" #: .././io/prealloc.c:341 .././io/prealloc.c:349 .././io/prealloc.c:357 #: .././io/prealloc.c:365 .././io/prealloc.c:375 .././io/prealloc.c:402 #: .././io/prealloc.c:412 .././io/prealloc.c:422 .././io/prealloc.c:442 msgid "off len" msgstr "" #: .././io/prealloc.c:342 msgid "allocates zeroed space for part of a file" msgstr "" #: .././io/prealloc.c:350 msgid "frees space associated with part of a file" msgstr "" #: .././io/prealloc.c:359 msgid "reserves space associated with part of a file" msgstr "" #: .././io/prealloc.c:368 msgid "frees reserved space associated with part of a file" msgstr "" #: .././io/prealloc.c:377 msgid "Converts the given range of a file to allocated zeros" msgstr "" #: .././io/prealloc.c:391 msgid "[-c] [-k] [-p] [-u] off len" msgstr "" #: .././io/prealloc.c:393 msgid "allocates space associated with part of a file via fallocate" msgstr "" #: .././io/prealloc.c:404 msgid "de-allocates space associated with part of a file via fallocate" msgstr "" #: .././io/prealloc.c:414 msgid "de-allocates space and eliminates the hole by shifting extents" msgstr "" #: .././io/prealloc.c:424 msgid "creates new space for writing within file by shifting extents" msgstr "" #: .././io/prealloc.c:432 msgid "[-k] off len" msgstr "" #: .././io/prealloc.c:434 msgid "zeroes space and eliminates holes by preallocating" msgstr "" #: .././io/prealloc.c:444 msgid "unshares shared blocks within the range" msgstr "" #: .././io/init.c:25 #, c-format msgid "Usage: %s [-adfinrRstVx] [-m mode] [-p prog] [[-c|-C] cmd]... file\n" msgstr "" #: .././io/init.c:122 #, c-format msgid "foreign file active, %s command is for XFS filesystems only\n" msgstr "" #: .././io/parent.c:36 #, c-format msgid "%s%s" msgstr "" #: .././io/parent.c:41 #, c-format msgid "inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n" msgstr "" #: .././io/parent.c:45 #, c-format msgid "path \"%s\" does not stat for inode: %llu; err = %s\n" msgstr "" #: .././io/parent.c:54 #, c-format msgid "path \"%s\" found\n" msgstr "" #: .././io/parent.c:60 #, c-format msgid "inode-path for inode: %llu is incorrect - wrong inode#\n" msgstr "" #: .././io/parent.c:64 .././io/parent.c:94 #, c-format msgid "ino mismatch for path \"%s\" %llu vs %llu\n" msgstr "" #: .././io/parent.c:72 #, c-format msgid "inode number match: %llu\n" msgstr "" #: .././io/parent.c:82 #, c-format msgid "parent path \"%s\" does not stat: %s\n" msgstr "" #: .././io/parent.c:90 #, c-format msgid "inode-path for inode: %llu is incorrect - wrong parent inode#\n" msgstr "" #: .././io/parent.c:103 #, c-format msgid "parent ino match for %llu\n" msgstr "" #: .././io/parent.c:125 #, c-format msgid "parentpaths failed for ino %llu: %s\n" msgstr "" #: .././io/parent.c:136 #, c-format msgid "inode-path for inode: %llu is missing\n" msgstr "" #: .././io/parent.c:160 #, c-format msgid "can't stat mount point \"%s\": %s\n" msgstr "" #: .././io/parent.c:181 #, c-format msgid "failed to get bulkstat information for inode %llu\n" msgstr "" #: .././io/parent.c:187 #, c-format msgid "failed to get valid bulkstat information for inode %llu\n" msgstr "" #: .././io/parent.c:199 #, c-format msgid "checking inode %llu\n" msgstr "" #: .././io/parent.c:214 #, c-format msgid "syssgi bulkstat failed: %s\n" msgstr "" #: .././io/parent.c:236 #, c-format msgid "unable to open \"%s\" for jdm: %s\n" msgstr "" #: .././io/parent.c:246 #, c-format msgid "unable to allocate buffers: %s\n" msgstr "" #: .././io/parent.c:256 #, c-format msgid "num errors: %d\n" msgstr "" #: .././io/parent.c:258 #, c-format msgid "succeeded checking %llu inodes\n" msgstr "" #: .././io/parent.c:271 #, c-format msgid "p_ino = %llu\n" msgstr "" #: .././io/parent.c:272 #, c-format msgid "p_gen = %u\n" msgstr "" #: .././io/parent.c:273 #, c-format msgid "p_reclen = %u\n" msgstr "" #: .././io/parent.c:275 #, c-format msgid "p_name = \"%s%s\"\n" msgstr "" #: .././io/parent.c:277 #, c-format msgid "p_name = \"%s\"\n" msgstr "" #: .././io/parent.c:299 #, c-format msgid "%s: failed path_to_fshandle \"%s\": %s\n" msgstr "" #: .././io/parent.c:307 #, c-format msgid "%s: path_to_handle failed for \"%s\"\n" msgstr "" #: .././io/parent.c:314 #, c-format msgid "%s: unable to allocate parent buffer: %s\n" msgstr "" #: .././io/parent.c:335 #, c-format msgid "%s: %s call failed for \"%s\": %s\n" msgstr "" #: .././io/parent.c:344 #, c-format msgid "%s: inode-path is missing\n" msgstr "" #: .././io/parent.c:376 #, c-format msgid "file argument, \"%s\", is not in a mounted XFS filesystem\n" msgstr "" #: .././io/parent.c:416 #, c-format msgid "" "\n" " list the current file's parents and their filenames\n" "\n" " -c -- check the current file's file system for parent consistency\n" " -p -- list the current file's parents and their full paths\n" " -v -- verbose mode\n" "\n" msgstr "" #: .././io/parent.c:432 msgid "[-cpv]" msgstr "" #: .././io/parent.c:434 msgid "print or check parent inodes" msgstr "" #: .././io/fadvise.c:18 #, c-format msgid "" "\n" " advise the page cache about expected I/O patterns on the current file\n" "\n" " Modifies kernel page cache behaviour when operating on the current file.\n" " The range arguments are required by some advise commands ([*] below).\n" " With no arguments, the POSIX_FADV_NORMAL advice is implied.\n" " -d -- don't need these pages (POSIX_FADV_DONTNEED) [*]\n" " -n -- data will be accessed once (POSIX_FADV_NOREUSE) [*]\n" " -r -- expect random page references (POSIX_FADV_RANDOM)\n" " -s -- expect sequential page references (POSIX_FADV_SEQUENTIAL)\n" " -w -- will need these pages (POSIX_FADV_WILLNEED) [*]\n" " Notes: these interfaces are not supported in Linux kernels before 2.6.\n" " NORMAL sets the default readahead setting on the file.\n" " RANDOM sets the readahead setting on the file to zero.\n" " SEQUENTIAL sets double the default readahead setting on the file.\n" " WILLNEED and NOREUSE are equivalent, and force the maximum readahead.\n" "\n" msgstr "" #: .././io/fadvise.c:109 msgid "[-dnrsw] [off len]" msgstr "" #: .././io/fadvise.c:110 msgid "advisory commands for sections of a file" msgstr "" #: .././libxcmd/command.c:83 #, c-format msgid "bad argument count %d to %s, expected at least %d arguments\n" msgstr "" #: .././libxcmd/command.c:87 #, c-format msgid "bad argument count %d to %s, expected %d arguments\n" msgstr "" #: .././libxcmd/command.c:91 #, c-format msgid "bad argument count %d to %s, expected between %d and %d arguments\n" msgstr "" #: .././libxcmd/command.c:190 #, c-format msgid "command \"%s\" not found\n" msgstr "" #: .././libxcmd/command.c:227 #, c-format msgid "cannot strdup command '%s': %s\n" msgstr "" #: .././libxcmd/command.c:253 #, c-format msgid "%s %lld/%lld bytes at offset %lld\n" msgstr "" #: .././libxcmd/command.c:255 #, c-format msgid "%s, %d ops; %s (%s/sec and %.4f ops/sec)\n" msgstr "" #: .././libxcmd/quit.c:31 msgid "exit the program" msgstr "" #: .././libxfs/util.c:574 #, c-format msgid "%s: cannot duplicate transaction: %s\n" msgstr "" #: .././libxfs/kmem.c:16 #, c-format msgid "%s: zone init failed (%s, %d bytes): %s\n" msgstr "" #: .././libxfs/kmem.c:47 #, c-format msgid "%s: zone alloc failed (%s, %d bytes): %s\n" msgstr "" #: .././libxfs/kmem.c:71 #, c-format msgid "%s: malloc failed (%d bytes): %s\n" msgstr "" #: .././libxfs/kmem.c:92 #, c-format msgid "%s: realloc failed (%d bytes): %s\n" msgstr "" #: .././libxfs/trans.c:763 #, c-format msgid "Transaction block reservation exceeded! %u > %u\n" msgstr "" #: .././libxfs/trans.c:826 #, c-format msgid "%s: warning - imap_to_bp failed (%d)\n" msgstr "" #: .././libxfs/trans.c:840 #, c-format msgid "%s: warning - iflush_int failed (%d)\n" msgstr "" #: .././libxfs/trans.c:888 .././libxfs/trans.c:933 #, c-format msgid "%s: unrecognised log item type\n" msgstr "" #: .././libxfs/rdwr.c:70 #, c-format msgid "%s: %s can't memalign %d bytes: %s\n" msgstr "" #: .././libxfs/rdwr.c:80 #, c-format msgid "%s: %s seek to offset %llu failed: %s\n" msgstr "" #: .././libxfs/rdwr.c:90 #, c-format msgid "%s: %s write failed: %s\n" msgstr "" #: .././libxfs/rdwr.c:94 #, c-format msgid "%s: %s not progressing?\n" msgstr "" #: .././libxfs/rdwr.c:562 #, c-format msgid "%s: %s can't memalign %u bytes: %s\n" msgstr "" #: .././libxfs/rdwr.c:602 #, c-format msgid "%s: %s can't malloc %u bytes: %s\n" msgstr "" #: .././libxfs/rdwr.c:686 #, c-format msgid "%s: %s invalid map %p or nmaps %d\n" msgstr "" #: .././libxfs/rdwr.c:693 #, c-format msgid "%s: %s map blkno 0x%llx doesn't match key 0x%llx\n" msgstr "" #: .././libxfs/rdwr.c:736 #, c-format msgid "Warning: recursive buffer locking at block % detected\n" msgstr "" #: .././libxfs/rdwr.c:911 #, c-format msgid "%s: read failed: %s\n" msgstr "" #: .././libxfs/rdwr.c:917 #, c-format msgid "%s: error - read only %d of %d bytes\n" msgstr "" #: .././libxfs/rdwr.c:1079 #, c-format msgid "%s: pwrite failed: %s\n" msgstr "" #: .././libxfs/rdwr.c:1085 #, c-format msgid "%s: error - pwrite only %d of %d bytes\n" msgstr "" #: .././libxfs/rdwr.c:1120 #, c-format msgid "%s: write verifier failed on %s bno 0x%llx/0x%x\n" msgstr "" #: .././libxfs/init.c:82 .././libxfs/init.c:181 #, c-format msgid "%s: %s: device %lld is not open\n" msgstr "" #: .././libxfs/init.c:118 #, c-format msgid "%s: cannot stat %s: %s\n" msgstr "" #: .././libxfs/init.c:143 #, c-format msgid "%s: device %lld is already open\n" msgstr "" #: .././libxfs/init.c:156 #, c-format msgid "%s: %s: too many open devices\n" msgstr "" #: .././libxfs/init.c:199 #, c-format msgid "%s: can't find a character device matching %s\n" msgstr "" #: .././libxfs/init.c:205 #, c-format msgid "%s: can't find a block device matching %s\n" msgstr "" #: .././libxfs/init.c:357 #, c-format msgid "%s: can't get size for data subvolume\n" msgstr "" #: .././libxfs/init.c:362 #, c-format msgid "%s: can't get size for log subvolume\n" msgstr "" #: .././libxfs/init.c:367 #, c-format msgid "%s: can't get size for realtime subvolume\n" msgstr "" #: .././libxfs/init.c:414 #, c-format msgid "%s: filesystem has a realtime subvolume\n" msgstr "" #: .././libxfs/init.c:436 #, c-format msgid "%s: realtime init - %llu != %llu\n" msgstr "" #: .././libxfs/init.c:444 #, c-format msgid "%s: realtime size check failed\n" msgstr "" #: .././libxfs/init.c:566 #, c-format msgid "%s: buftarg init failed\n" msgstr "" #: .././libxfs/init.c:587 #, c-format msgid "%s: bad buftarg reinit, ddev\n" msgstr "" #: .././libxfs/init.c:594 #, c-format msgid "%s: bad buftarg reinit, ldev mismatch\n" msgstr "" #: .././libxfs/init.c:601 #, c-format msgid "%s: bad buftarg reinit, logdev\n" msgstr "" #: .././libxfs/init.c:608 #, c-format msgid "%s: bad buftarg reinit, rtdev\n" msgstr "" #: .././libxfs/init.c:672 #, c-format msgid "%s: size check failed\n" msgstr "" #: .././libxfs/init.c:684 #, c-format msgid "%s: V1 inodes unsupported. Please try an older xfsprogs.\n" msgstr "" #: .././libxfs/init.c:693 #, c-format msgid "%s: V1 directories unsupported. Please try an older xfsprogs.\n" msgstr "" #: .././libxfs/init.c:701 #, c-format msgid "%s: Unsupported features detected. Please try a newer xfsprogs.\n" msgstr "" #: .././libxfs/init.c:721 #, c-format msgid "%s: data size check failed\n" msgstr "" #: .././libxfs/init.c:735 #, c-format msgid "%s: log size checks failed\n" msgstr "" #: .././libxfs/init.c:746 #, c-format msgid "%s: realtime device init failed\n" msgstr "" #: .././libxfs/init.c:763 #, c-format msgid "%s: read of AG %u failed\n" msgstr "" #: .././libxfs/init.c:767 #, c-format msgid "%s: limiting reads to AG 0\n" msgstr "" #: .././libxfs/init.c:776 #, c-format msgid "%s: perag init failed\n" msgstr "" #: .././libxlog/util.c:55 #, c-format msgid "%s: cannot find log head/tail (xlog_find_tail=%d)\n" msgstr "" #: .././libxlog/util.c:63 #, c-format msgid "%s: head block % tail block %\n" msgstr "" #: .././libxlog/util.c:85 #, c-format msgid "" "* ERROR: mismatched uuid in log\n" "* SB : %s\n" "* log: %s\n" msgstr "" #: .././libxlog/util.c:98 #, c-format msgid "" "\n" "LOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n" msgstr "" #: .././libxlog/util.c:106 #, c-format msgid "* ERROR: bad magic number in log header: 0x%x\n" msgstr "" #: .././libxlog/util.c:115 #, c-format msgid "* ERROR: log format incompatible (log=%d, ours=%d)\n" msgstr "" #: .././libxlog/util.c:125 .././libxlog/util.c:137 msgid "Bad log" msgstr "" #: .././logprint/log_copy.c:34 .././logprint/log_dump.c:33 #, c-format msgid "%s: read error (%lld): %s\n" msgstr "" #: .././logprint/log_copy.c:39 .././logprint/log_dump.c:38 #, c-format msgid "%s: physical end of log at %lld\n" msgstr "" #: .././logprint/log_copy.c:43 #, c-format msgid "%s: short read? (%lld)\n" msgstr "" #: .././logprint/log_copy.c:50 #, c-format msgid "%s: write error (%lld): %s\n" msgstr "" #: .././logprint/log_copy.c:55 #, c-format msgid "%s: short write? (%lld)\n" msgstr "" #: .././logprint/log_dump.c:46 #, c-format msgid "%6lld HEADER Cycle %d tail %d:%06d len %6d ops %d\n" msgstr "" #: .././logprint/log_dump.c:57 #, c-format msgid "[%05lld - %05lld] Cycle 0x%08x New Cycle 0x%08x\n" msgstr "" #: .././logprint/log_misc.c:75 #, c-format msgid "Oper (%d): tid: %x len: %d clientid: %s " msgstr "" #: .././logprint/log_misc.c:80 #, c-format msgid "flags: " msgstr "" #: .././logprint/log_misc.c:174 #, c-format msgid " Not enough data to decode further\n" msgstr "" #: .././logprint/log_misc.c:178 #, c-format msgid " tid: %x num_items: %d\n" msgstr "" #: .././logprint/log_misc.c:222 #, c-format msgid "" "#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d flags: 0x%x\n" msgstr "" #: .././logprint/log_misc.c:228 #, c-format msgid "#regs: %d Not printing rest of data\n" msgstr "" #: .././logprint/log_misc.c:245 #, c-format msgid "SUPER BLOCK Buffer: " msgstr "" #: .././logprint/log_misc.c:247 .././logprint/log_misc.c:337 #: .././logprint/log_misc.c:367 #, c-format msgid "Out of space\n" msgstr "" #: .././logprint/log_misc.c:257 #, c-format msgid "icount: %llu ifree: %llu " msgstr "" #: .././logprint/log_misc.c:262 #, c-format msgid "fdblks: %llu frext: %llu\n" msgstr "" #: .././logprint/log_misc.c:273 #, c-format msgid "AGI Buffer: XAGI " msgstr "" #: .././logprint/log_misc.c:284 #, c-format msgid "out of space\n" msgstr "" #: .././logprint/log_misc.c:287 #, c-format msgid "ver: %d " msgstr "" #: .././logprint/log_misc.c:289 #, c-format msgid "seq#: %d len: %d cnt: %d root: %d\n" msgstr "" #: .././logprint/log_misc.c:294 #, c-format msgid "level: %d free#: 0x%x newino: 0x%x\n" msgstr "" #: .././logprint/log_misc.c:304 #, c-format msgid "AGI unlinked data skipped " msgstr "" #: .././logprint/log_misc.c:305 #, c-format msgid "(CONTINUE set, no space)\n" msgstr "" #: .././logprint/log_misc.c:311 .././logprint/log_print_all.c:136 #, c-format msgid "bucket[%d - %d]: " msgstr "" #: .././logprint/log_misc.c:327 #, c-format msgid "AGF Buffer: XAGF " msgstr "" #: .././logprint/log_misc.c:340 #, c-format msgid "ver: %d seq#: %d len: %d \n" msgstr "" #: .././logprint/log_misc.c:344 #, c-format msgid "root BNO: %d CNT: %d\n" msgstr "" #: .././logprint/log_misc.c:347 #, c-format msgid "level BNO: %d CNT: %d\n" msgstr "" #: .././logprint/log_misc.c:350 #, c-format msgid "1st: %d last: %d cnt: %d freeblks: %d longest: %d\n" msgstr "" #: .././logprint/log_misc.c:364 #, c-format msgid "DQUOT Buffer: DQ " msgstr "" #: .././logprint/log_misc.c:371 #, c-format msgid "ver: %d flags: 0x%x id: %d \n" msgstr "" #: .././logprint/log_misc.c:374 #, c-format msgid "blk limits hard: %llu soft: %llu\n" msgstr "" #: .././logprint/log_misc.c:379 #, c-format msgid "blk count: %llu warns: %d timer: %d\n" msgstr "" #: .././logprint/log_misc.c:383 #, c-format msgid "ino limits hard: %llu soft: %llu\n" msgstr "" #: .././logprint/log_misc.c:388 #, c-format msgid "ino count: %llu warns: %d timer: %d\n" msgstr "" #: .././logprint/log_misc.c:394 #, c-format msgid "BUF DATA\n" msgstr "" #: .././logprint/log_misc.c:430 #, c-format msgid "QOFF: #regs: %d flags: 0x%x\n" msgstr "" #: .././logprint/log_misc.c:433 #, c-format msgid "QOFF: Not enough data to decode further\n" msgstr "" #: .././logprint/log_misc.c:443 #, c-format msgid "INODE CORE\n" msgstr "" #: .././logprint/log_misc.c:444 #, c-format msgid "magic 0x%hx mode 0%ho version %d format %d\n" msgstr "" #: .././logprint/log_misc.c:447 #, c-format msgid "nlink %hd uid %d gid %d\n" msgstr "" #: .././logprint/log_misc.c:449 #, c-format msgid "atime 0x%x mtime 0x%x ctime 0x%x\n" msgstr "" #: .././logprint/log_misc.c:451 #, c-format msgid "size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n" msgstr "" #: .././logprint/log_misc.c:454 #, c-format msgid "naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n" msgstr "" #: .././logprint/log_misc.c:457 #, c-format msgid "flags 0x%x gen 0x%x\n" msgstr "" #: .././logprint/log_misc.c:460 #, c-format msgid "flags2 0x%llx cowextsize 0x%x\n" msgstr "" #: .././logprint/log_misc.c:478 #, c-format msgid "SHORTFORM DIRECTORY size %d\n" msgstr "" #: .././logprint/log_misc.c:484 #, c-format msgid "SHORTFORM DIRECTORY size %d count %d\n" msgstr "" #: .././logprint/log_misc.c:487 #, c-format msgid ".. ino 0x%llx\n" msgstr "" #: .././logprint/log_misc.c:495 #, c-format msgid "%s ino 0x%llx namelen %d\n" msgstr "" #: .././logprint/log_misc.c:535 #, c-format msgid "INODE: " msgstr "" #: .././logprint/log_misc.c:536 #, c-format msgid "#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n" msgstr "" #: .././logprint/log_misc.c:539 #, c-format msgid " blkno: %lld len: %d boff: %d\n" msgstr "" #: .././logprint/log_misc.c:544 #, c-format msgid "INODE: #regs: %d Not printing rest of data\n" msgstr "" #: .././logprint/log_misc.c:571 #, c-format msgid "DEV inode: no extra region\n" msgstr "" #: .././logprint/log_misc.c:574 #, c-format msgid "UUID inode: no extra region\n" msgstr "" #: .././logprint/log_misc.c:596 #, c-format msgid "EXTENTS inode data\n" msgstr "" #: .././logprint/log_misc.c:599 #, c-format msgid "BTREE inode data\n" msgstr "" #: .././logprint/log_misc.c:602 #, c-format msgid "LOCAL inode data\n" msgstr "" #: .././logprint/log_misc.c:626 #, c-format msgid "EXTENTS attr data\n" msgstr "" #: .././logprint/log_misc.c:629 #, c-format msgid "BTREE attr data\n" msgstr "" #: .././logprint/log_misc.c:632 #, c-format msgid "LOCAL attr data\n" msgstr "" #: .././logprint/log_misc.c:673 #, c-format msgid "#regs: %d id: 0x%x" msgstr "" #: .././logprint/log_misc.c:674 #, c-format msgid " blkno: %lld len: %d boff: %d\n" msgstr "" #: .././logprint/log_misc.c:678 #, c-format msgid "DQUOT: #regs: %d Not printing rest of data\n" msgstr "" #: .././logprint/log_misc.c:697 #, c-format msgid "DQUOT: magic 0x%hx flags 0%ho\n" msgstr "" #: .././logprint/log_misc.c:723 #, c-format msgid "ICR: split header, not printing\n" msgstr "" #: .././logprint/log_misc.c:727 #, c-format msgid "" "ICR: #ag: %d agbno: 0x%x len: %d\n" " cnt: %d isize: %d gen: 0x%x\n" msgstr "" #: .././logprint/log_misc.c:753 #, c-format msgid "%s: lseek to %lld failed: %s\n" msgstr "" #: .././logprint/log_misc.c:799 #, c-format msgid "%s: xlog_print_record: malloc failed\n" msgstr "" #: .././logprint/log_misc.c:808 #, c-format msgid "%s: xlog_print_record: read error\n" msgstr "" #: .././logprint/log_misc.c:903 .././logprint/log_misc.c:1006 #, c-format msgid "Left over region from split log item\n" msgstr "" #: .././logprint/log_misc.c:991 #, c-format msgid "Unmount filesystem\n" msgstr "" #: .././logprint/log_misc.c:998 #, c-format msgid "%s: unknown log operation type (%x)\n" msgstr "" #: .././logprint/log_misc.c:1039 #, c-format msgid "Header 0x%x wanted 0x%x\n" msgstr "" #: .././logprint/log_misc.c:1053 #, c-format msgid "cycle: %d\tversion: %d\t" msgstr "" #: .././logprint/log_misc.c:1059 #, c-format msgid "length of Log Record: %d\tprev offset: %d\t\tnum ops: %d\n" msgstr "" #: .././logprint/log_misc.c:1065 .././logprint/log_misc.c:1107 #, c-format msgid "cycle num overwrites: " msgstr "" #: .././logprint/log_misc.c:1074 #, c-format msgid "uuid: %s format: " msgstr "" #: .././logprint/log_misc.c:1077 #, c-format msgid "unknown\n" msgstr "" #: .././logprint/log_misc.c:1080 #, c-format msgid "little endian linux\n" msgstr "" #: .././logprint/log_misc.c:1083 #, c-format msgid "big endian linux\n" msgstr "" #: .././logprint/log_misc.c:1086 #, c-format msgid "big endian irix\n" msgstr "" #: .././logprint/log_misc.c:1092 #, c-format msgid "h_size: %d\n" msgstr "" #: .././logprint/log_misc.c:1104 #, c-format msgid "extended-header: cycle: %d\n" msgstr "" #: .././logprint/log_misc.c:1120 #, c-format msgid "* ERROR: found data after zeroed blocks block=%-21lld *\n" msgstr "" #: .././logprint/log_misc.c:1131 #, c-format msgid "* ERROR: header cycle=%-11d block=%-21lld *\n" msgstr "" #: .././logprint/log_misc.c:1142 #, c-format msgid "* ERROR: data block=%-21lld *\n" msgstr "" #: .././logprint/log_misc.c:1153 #, c-format msgid "" "* ERROR: for header block=%lld\n" "* not enough hdrs for data length, required num = %d, hdr num = %d\n" msgstr "" #: .././logprint/log_misc.c:1159 msgid "Not enough headers for data length." msgstr "" #: .././logprint/log_misc.c:1169 #, c-format msgid "%s: xlog_print: malloc failed for ext hdrs\n" msgstr "" #: .././logprint/log_misc.c:1217 .././logprint/log_misc.c:1293 #: .././logprint/log_misc.c:1364 .././logprint/log_misc.c:1401 #, c-format msgid "%s: physical end of log\n" msgstr "" #: .././logprint/log_misc.c:1223 .././logprint/log_misc.c:1298 #: .././logprint/log_misc.c:1416 #, c-format msgid "BLKNO: %lld\n" msgstr "" #: .././logprint/log_misc.c:1281 #, c-format msgid "%s: problem finding oldest LR\n" msgstr "" #: .././logprint/log_misc.c:1307 #, c-format msgid "%s: after %d zeroed blocks\n" msgstr "" #: .././logprint/log_misc.c:1376 msgid "illegal value" msgstr "" #: .././logprint/log_misc.c:1382 #, c-format msgid "%s: skipped %d cleared blocks in range: %lld - %lld\n" msgstr "" #: .././logprint/log_misc.c:1387 #, c-format msgid "%s: totally cleared log\n" msgstr "" #: .././logprint/log_misc.c:1392 #, c-format msgid "%s: skipped %d zeroed blocks in range: %lld - %lld\n" msgstr "" #: .././logprint/log_misc.c:1397 #, c-format msgid "%s: totally zeroed log\n" msgstr "" #: .././logprint/log_misc.c:1413 msgid "xlog_find_head: bad read" msgstr "" #: .././logprint/log_misc.c:1465 #, c-format msgid "%s: logical end of log\n" msgstr "" #: .././logprint/log_print_all.c:84 #, c-format msgid "" "BUF: #regs:%d start blkno:0x%llx len:%d bmap size:%d flags:0x%x\n" msgstr "" #: .././logprint/log_print_all.c:94 #, c-format msgid "\tSUPER Block Buffer:\n" msgstr "" #: .././logprint/log_print_all.c:97 #, c-format msgid " icount:%llu ifree:%llu " msgstr "" #: .././logprint/log_print_all.c:102 #, c-format msgid "fdblks:%llu frext:%llu\n" msgstr "" #: .././logprint/log_print_all.c:107 #, c-format msgid "\t\tsunit:%u swidth:%u\n" msgstr "" #: .././logprint/log_print_all.c:113 #, c-format msgid "\tAGI Buffer: (XAGI)\n" msgstr "" #: .././logprint/log_print_all.c:116 #, c-format msgid "\t\tver:%d " msgstr "" #: .././logprint/log_print_all.c:118 #, c-format msgid "seq#:%d len:%d cnt:%d root:%d\n" msgstr "" #: .././logprint/log_print_all.c:123 #, c-format msgid "\t\tlevel:%d free#:0x%x newino:0x%x\n" msgstr "" #: .././logprint/log_print_all.c:147 #, c-format msgid "\tAGF Buffer: (XAGF)\n" msgstr "" #: .././logprint/log_print_all.c:150 #, c-format msgid "\t\tver:%d seq#:%d len:%d \n" msgstr "" #: .././logprint/log_print_all.c:154 #, c-format msgid "\t\troot BNO:%d CNT:%d\n" msgstr "" #: .././logprint/log_print_all.c:157 #, c-format msgid "\t\tlevel BNO:%d CNT:%d\n" msgstr "" #: .././logprint/log_print_all.c:160 #, c-format msgid "\t\t1st:%d last:%d cnt:%d freeblks:%d longest:%d\n" msgstr "" #: .././logprint/log_print_all.c:169 #, c-format msgid "\tDQUOT Buffer:\n" msgstr "" #: .././logprint/log_print_all.c:172 #, c-format msgid "\t\tUIDs 0x%lx-0x%lx\n" msgstr "" #: .././logprint/log_print_all.c:177 #, c-format msgid "\tBUF DATA\n" msgstr "" #: .././logprint/log_print_all.c:199 #, c-format msgid "\tQUOTAOFF: #regs:%d type:%s\n" msgstr "" #: .././logprint/log_print_all.c:214 #, c-format msgid "\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n" msgstr "" #: .././logprint/log_print_all.c:218 #, c-format msgid "\t\tmagic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n" msgstr "" #: .././logprint/log_print_all.c:223 #, c-format msgid "\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x\tino_soft 0x%x\n" msgstr "" #: .././logprint/log_print_all.c:229 #, c-format msgid "\t\tbcount 0x%x (%d) icount 0x%x (%d)\n" msgstr "" #: .././logprint/log_print_all.c:234 #, c-format msgid "\t\tbtimer 0x%x itimer 0x%x \n" msgstr "" #: .././logprint/log_print_all.c:243 #, c-format msgid "\tCORE inode:\n" msgstr "" #: .././logprint/log_print_all.c:246 #, c-format msgid "\t\tmagic:%c%c mode:0x%x ver:%d format:%d\n" msgstr "" #: .././logprint/log_print_all.c:249 #, c-format msgid "\t\tuid:%d gid:%d nlink:%d projid:0x%04x%04x\n" msgstr "" #: .././logprint/log_print_all.c:252 #, c-format msgid "\t\tatime:%d mtime:%d ctime:%d\n" msgstr "" #: .././logprint/log_print_all.c:254 #, c-format msgid "\t\tflushiter:%d\n" msgstr "" #: .././logprint/log_print_all.c:255 #, c-format msgid "\t\tsize:0x%llx nblks:0x%llx exsize:%d nextents:%d anextents:%d\n" msgstr "" #: .././logprint/log_print_all.c:259 #, c-format msgid "\t\tforkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x gen:%u\n" msgstr "" #: .././logprint/log_print_all.c:264 #, c-format msgid "\t\tflags2 0x%llx cowextsize 0x%x\n" msgstr "" #: .././logprint/log_print_all.c:283 #, c-format msgid "\tINODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n" msgstr "" #: .././logprint/log_print_all.c:299 #, c-format msgid "\t\tDATA FORK EXTENTS inode data:\n" msgstr "" #: .././logprint/log_print_all.c:306 #, c-format msgid "\t\tDATA FORK BTREE inode data:\n" msgstr "" #: .././logprint/log_print_all.c:313 #, c-format msgid "\t\tDATA FORK LOCAL inode data:\n" msgstr "" #: .././logprint/log_print_all.c:320 #, c-format msgid "\t\tDEV inode: no extra region\n" msgstr "" #: .././logprint/log_print_all.c:324 #, c-format msgid "\t\tUUID inode: no extra region\n" msgstr "" #: .././logprint/log_print_all.c:339 #, c-format msgid "\t\tATTR FORK EXTENTS inode data:\n" msgstr "" #: .././logprint/log_print_all.c:347 #, c-format msgid "\t\tATTR FORK BTREE inode data:\n" msgstr "" #: .././logprint/log_print_all.c:355 #, c-format msgid "\t\tATTR FORK LOCAL inode data:\n" msgstr "" #: .././logprint/log_print_all.c:376 #, c-format msgid "" "\tICR: #ag: %d agbno: 0x%x len: %d\n" "\t cnt: %d isize: %d gen: 0x%x\n" msgstr "" #: .././logprint/log_print_all.c:428 #, c-format msgid "xlog_recover_print_logitem: illegal type\n" msgstr "" #: .././logprint/log_print_all.c:480 #, c-format msgid "%s: illegal type" msgstr "" #: .././logprint/log_print_all.c:488 #, c-format msgid ": cnt:%d total:%d " msgstr "" #: .././logprint/log_print_all.c:490 #, c-format msgid "a:0x%lx len:%d " msgstr "" #: .././logprint/log_print_trans.c:15 #, c-format msgid "TRANS: tid:0x%x #items:%d trans:0x%x q:0x%lx\n" msgstr "" #: .././logprint/log_print_trans.c:41 #, c-format msgid "%s: failed to find head and tail, error: %d\n" msgstr "" #: .././logprint/log_print_trans.c:46 #, c-format msgid " log tail: %lld head: %lld state: %s\n" msgstr "" #: .././logprint/log_print_trans.c:52 #, c-format msgid " override tail: %d\n" msgstr "" #: .././logprint/log_print_trans.c:72 #, c-format msgid "" "Superblock has unknown incompatible log features (0x%x) enabled.\n" "Output may be incomplete or inaccurate. It is recommended that you\n" "upgrade your xfsprogs installation to match the filesystem features.\n" msgstr "" #: .././logprint/log_print_trans.c:80 #, c-format msgid "%s: failed in xfs_do_recovery_pass, error: %d\n" msgstr "" #: .././logprint/log_redo.c:59 #, c-format msgid "%s: bad size of efi format: %u; expected %u or %u; nextents = %u\n" msgstr "" #: .././logprint/log_redo.c:82 .././logprint/log_redo.c:98 #, c-format msgid "%s: xlog_print_trans_efi: malloc failed\n" msgstr "" #: .././logprint/log_redo.c:92 #, c-format msgid "EFI: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:106 #, c-format msgid "EFI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:110 #, c-format msgid "EFI free extent data skipped (CONTINUE set, no space)\n" msgstr "" #: .././logprint/log_redo.c:149 #, c-format msgid "%s: xlog_recover_print_efi: malloc failed\n" msgstr "" #: .././logprint/log_redo.c:158 #, c-format msgid "\tEFI: #regs:%d\tnum_extents:%d id:0x%llx\n" msgstr "" #: .././logprint/log_redo.c:190 #, c-format msgid "EFD: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:198 #, c-format msgid "EFD: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:216 #, c-format msgid "\tEFD: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:237 #, c-format msgid "%s: bad size of RUI format: %u; expected %u; nextents = %u\n" msgstr "" #: .././logprint/log_redo.c:264 .././logprint/log_redo.c:283 #: .././logprint/log_redo.c:412 .././logprint/log_redo.c:431 #: .././logprint/log_redo.c:555 .././logprint/log_redo.c:574 #, c-format msgid "%s: %s: malloc failed\n" msgstr "" #: .././logprint/log_redo.c:276 #, c-format msgid "RUI: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:292 #, c-format msgid "RUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:296 #, c-format msgid "RUI extent data skipped (CONTINUE set, no space)\n" msgstr "" #: .././logprint/log_redo.c:347 #, c-format msgid "RUD: #regs: %d\t id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:355 #, c-format msgid "RUD: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:389 #, c-format msgid "%s: bad size of CUI format: %u; expected %u; nextents = %u\n" msgstr "" #: .././logprint/log_redo.c:424 #, c-format msgid "CUI: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:440 #, c-format msgid "CUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:444 #, c-format msgid "CUI extent data skipped (CONTINUE set, no space)\n" msgstr "" #: .././logprint/log_redo.c:490 #, c-format msgid "CUD: #regs: %d\t id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:498 #, c-format msgid "CUD: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:532 #, c-format msgid "%s: bad size of BUI format: %u; expected %u; nextents = %u\n" msgstr "" #: .././logprint/log_redo.c:567 #, c-format msgid "BUI: Not enough data to decode further\n" msgstr "" #: .././logprint/log_redo.c:583 #, c-format msgid "BUI: #regs: %d\tnum_extents: %d id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:587 #, c-format msgid "BUI extent data skipped (CONTINUE set, no space)\n" msgstr "" #: .././logprint/log_redo.c:634 #, c-format msgid "BUD: #regs: %d\t id: 0x%llx\n" msgstr "" #: .././logprint/log_redo.c:642 #, c-format msgid "BUD: Not enough data to decode further\n" msgstr "" #: .././logprint/logprint.c:33 #, c-format msgid "" "Usage: %s [options...] \n" "\n" "Options:\n" " -c\t try to continue if error found in log\n" " -C copy the log from the filesystem to filename\n" " -d\t dump the log in log-record format\n" " -e\t exit when an error is found in the log\n" " -f\t specified device is actually a file\n" " -l filename of external log\n" " -n\t don't try and interpret log data\n" " -o\t print buffer data in hex\n" " -s block # to start printing\n" " -v print \"overwrite\" data\n" " -t\t print out transactional view\n" "\t-b in transactional view, extract buffer info\n" "\t-i in transactional view, extract inode info\n" "\t-q in transactional view, extract quota info\n" " -D print only data; no decoding\n" " -V print version information\n" msgstr "" #: .././logprint/logprint.c:67 #, c-format msgid " Can't open device %s: %s\n" msgstr "" #: .././logprint/logprint.c:73 #, c-format msgid " read of XFS superblock failed\n" msgstr "" #: .././logprint/logprint.c:93 #, c-format msgid "" " external log device not specified\n" "\n" msgstr "" #: .././logprint/logprint.c:109 #, c-format msgid "Can't open file %s: %s\n" msgstr "" #: .././logprint/logprint.c:210 #, c-format msgid "xfs_logprint:\n" msgstr "" #: .././logprint/logprint.c:219 #, c-format msgid " data device: 0x%llx\n" msgstr "" #: .././logprint/logprint.c:222 #, c-format msgid " log file: \"%s\" " msgstr "" #: .././logprint/logprint.c:224 #, c-format msgid " log device: 0x%llx " msgstr "" #: .././logprint/logprint.c:227 #, c-format msgid "" "daddr: %lld length: %lld\n" "\n" msgstr "" #: .././mkfs/proto.c:67 #, c-format msgid "%s: failed to open %s: %s\n" msgstr "" #: .././mkfs/proto.c:74 .././mkfs/proto.c:290 #, c-format msgid "%s: read failed on %s: %s\n" msgstr "" #: .././mkfs/proto.c:79 #, c-format msgid "%s: proto file %s premature EOF\n" msgstr "" #: .././mkfs/proto.c:113 msgid "cannot reserve space" msgstr "" #: .././mkfs/proto.c:166 #, c-format msgid "%s: premature EOF in prototype file\n" msgstr "" #: .././mkfs/proto.c:185 msgid "error reserving space for a file" msgstr "" #: .././mkfs/proto.c:194 msgid "allocating transaction for a file" msgstr "" #: .././mkfs/proto.c:216 msgid "committing space for a file failed" msgstr "" #: .././mkfs/proto.c:248 msgid "error allocating space for a file" msgstr "" #: .././mkfs/proto.c:252 #, c-format msgid "%s: cannot allocate space for file\n" msgstr "" #: .././mkfs/proto.c:315 msgid "directory createname error" msgstr "" #: .././mkfs/proto.c:329 msgid "directory create error" msgstr "" #: .././mkfs/proto.c:392 .././mkfs/proto.c:404 .././mkfs/proto.c:415 #: .././mkfs/proto.c:422 #, c-format msgid "%s: bad format string %s\n" msgstr "" #: .././mkfs/proto.c:442 .././mkfs/proto.c:487 .././mkfs/proto.c:502 #: .././mkfs/proto.c:514 .././mkfs/proto.c:526 .././mkfs/proto.c:537 msgid "Inode allocation failed" msgstr "" #: .././mkfs/proto.c:457 #, c-format msgid "%s: Bad value %s for proto file %s\n" msgstr "" #: .././mkfs/proto.c:466 msgid "Inode pre-allocation failed" msgstr "" #: .././mkfs/proto.c:475 msgid "Space preallocation failed." msgstr "" #: .././mkfs/proto.c:555 msgid "Directory inode allocation failed." msgstr "" #: .././mkfs/proto.c:575 msgid "Unknown format" msgstr "" #: .././mkfs/proto.c:580 msgid "Error encountered creating file from prototype file" msgstr "" #: .././mkfs/proto.c:629 msgid "Realtime bitmap inode allocation failed" msgstr "" #: .././mkfs/proto.c:646 msgid "Realtime summary inode allocation failed" msgstr "" #: .././mkfs/proto.c:654 msgid "Completion of the realtime summary inode failed" msgstr "" #: .././mkfs/proto.c:674 msgid "Allocation of the realtime bitmap failed" msgstr "" #: .././mkfs/proto.c:687 msgid "Block allocation of the realtime bitmap inode failed" msgstr "" #: .././mkfs/proto.c:706 msgid "Allocation of the realtime summary failed" msgstr "" #: .././mkfs/proto.c:718 msgid "Block allocation of the realtime summary inode failed" msgstr "" #: .././mkfs/proto.c:735 msgid "Error initializing the realtime space" msgstr "" #: .././mkfs/proto.c:740 msgid "Initialization of the realtime space failed" msgstr "" #: .././mkfs/xfs_mkfs.c:854 #, c-format msgid "" "Usage: %s\n" "/* blocksize */\t\t[-b size=num]\n" "/* metadata */\t\t[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n" "/* data subvol */\t[-d agcount=n,agsize=n,file,name=xxx,size=num,\n" "\t\t\t (sunit=value,swidth=value|su=num,sw=num|noalign),\n" "\t\t\t sectsize=num\n" "/* force overwrite */\t[-f]\n" "/* inode size */\t[-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n" "\t\t\t projid32bit=0|1,sparse=0|1]\n" "/* no discard */\t[-K]\n" "/* log subvol */\t[-l agnum=n,internal,size=num,logdev=xxx,version=n\n" "\t\t\t sunit=value|su=num,sectsize=num,lazy-count=0|1]\n" "/* label */\t\t[-L label (maximum 12 characters)]\n" "/* naming */\t\t[-n size=num,version=2|ci,ftype=0|1]\n" "/* no-op info only */\t[-N]\n" "/* prototype file */\t[-p fname]\n" "/* quiet */\t\t[-q]\n" "/* realtime subvol */\t[-r extsize=num,size=num,rtdev=xxx]\n" "/* sectorsize */\t[-s size=num]\n" "/* version */\t\t[-V]\n" "\t\t\tdevicename\n" " is required unless -d name=xxx is given.\n" " is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n" " xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n" " is xxx (512 byte blocks).\n" msgstr "" #: .././mkfs/xfs_mkfs.c:890 #, c-format msgid "Cannot specify both -%c %s and -%c %s\n" msgstr "" #: .././mkfs/xfs_mkfs.c:902 #, c-format msgid "Invalid value %s for -%s option\n" msgstr "" #: .././mkfs/xfs_mkfs.c:919 #, c-format msgid "-%c %s option requires a value\n" msgstr "" #: .././mkfs/xfs_mkfs.c:932 .././repair/xfs_repair.c:168 #, c-format msgid "option respecified\n" msgstr "" #: .././mkfs/xfs_mkfs.c:941 .././repair/xfs_repair.c:175 #, c-format msgid "unknown option -%c %s\n" msgstr "" #: .././mkfs/xfs_mkfs.c:967 #, c-format msgid "Blocksize must be provided prior to using 'b' suffix.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:976 #, c-format msgid "Sectorsize must be specified prior to using 's' suffix.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1021 #, c-format msgid "if -%s file then -%s name and -%s size are required\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1027 #, c-format msgid "No device name specified\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1039 #, c-format msgid "Error accessing specified device %s: %s\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1061 #, c-format msgid "specified \"-%s file\" on a block device %s\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1069 #, c-format msgid "specified device %s not a file or block device\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1081 #, c-format msgid "%s: Use the -f option to force overwrite.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1097 #, c-format msgid "agsize (%lld blocks) too small, need at least %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1105 #, c-format msgid "agsize (%lld blocks) too big, maximum is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1113 #, c-format msgid "agsize (%lld blocks) too big, data area is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1120 #, c-format msgid "too many allocation groups for size = %lld\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1122 #, c-format msgid "need at most %lld allocation groups\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1130 #, c-format msgid "too few allocation groups for size = %lld\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1132 #, c-format msgid "need at least %lld allocation groups\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1145 #, c-format msgid "last AG size %lld blocks too small, minimum size is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1156 #, c-format msgid "%lld allocation groups is too many, maximum is %lld\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1186 #, c-format msgid "error reading existing superblock -- failed to memalign buffer\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1201 #, c-format msgid "error reading existing superblock: %s\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1264 #, c-format msgid "Invalid value %s for -%c %s option. %s\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1284 #, c-format msgid "Developer screwed up option parsing (%d/%d)! Please report!\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1338 #, c-format msgid "" "Option -%c %s has undefined minval/maxval.Can't verify value range. This is " "a bug.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1358 msgid "Value not recognized as number." msgstr "" #: .././mkfs/xfs_mkfs.c:1361 msgid "Unit suffixes are not allowed." msgstr "" #: .././mkfs/xfs_mkfs.c:1366 msgid "Value is too small." msgstr "" #: .././mkfs/xfs_mkfs.c:1368 msgid "Value is too large." msgstr "" #: .././mkfs/xfs_mkfs.c:1370 msgid "Value must be a power of 2." msgstr "" #: .././mkfs/xfs_mkfs.c:1787 #, c-format msgid "" "specified blocksize %d is less than device physical sector size %d\n" "switching to logical sector size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1800 #, c-format msgid "illegal sector size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1806 #, c-format msgid "block size %d cannot be smaller than sector size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1812 #, c-format msgid "illegal sector size %d; hw sector is %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1838 #, c-format msgid "illegal block size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1845 #, c-format msgid "Minimum block size for CRC enabled filesystems is %d bytes.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1868 #, c-format msgid "Can't change sector size on internal log!\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1883 #, c-format msgid "illegal log sector size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1891 #, c-format msgid "Version 1 logs do not support sector size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1901 #, c-format msgid "log stripe unit specified, using v2 logs\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1928 .././mkfs/xfs_mkfs.c:2094 #, c-format msgid "Minimum inode size for CRCs is %d bytes\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1936 #, c-format msgid "Inodes always aligned for CRC enabled filesystems\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1943 #, c-format msgid "Lazy superblock counters always enabled for CRC enabled filesystems\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1950 #, c-format msgid "V2 logs always enabled for CRC enabled filesystems\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1957 #, c-format msgid "V2 attribute format always enabled on CRC enabled filesystems\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1965 #, c-format msgid "32 bit Project IDs always enabled on CRC enabled filesystems\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1972 #, c-format msgid "Directory ftype field always enabled on CRC enabled filesystems\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1988 #, c-format msgid "finobt not supported without CRC support\n" msgstr "" #: .././mkfs/xfs_mkfs.c:1995 #, c-format msgid "sparse inodes not supported without CRC support\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2002 #, c-format msgid "rmapbt not supported without CRC support\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2009 #, c-format msgid "reflink not supported without CRC support\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2018 #, c-format msgid "cowextsize not supported without reflink support\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2024 #, c-format msgid "reflink not supported with realtime devices\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2031 #, c-format msgid "rmapbt not supported with realtime devices\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2056 #, c-format msgid "illegal directory block size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2105 #, c-format msgid "illegal inode size %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2110 #, c-format msgid "allowable inode size with %d byte blocks is %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2114 #, c-format msgid "allowable inode size with %d byte blocks is between %d and %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2137 #, c-format msgid "illegal %s length %lld, not a multiple of %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2144 #, c-format msgid "warning: %s length %lld not a multiple of %d, truncated to %lld\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2167 #, c-format msgid "illegal rt extent size %lld, not a multiple of %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2226 #, c-format msgid "illegal extent size hint %lld, must be less than %u.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2248 #, c-format msgid "" "illegal extent size hint %lld, must be less than %u and a multiple of %u.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2277 #, c-format msgid "illegal CoW extent size hint %lld, must be less than %u.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2318 #, c-format msgid "both data sunit and data swidth options must be specified\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2326 #, c-format msgid "both data su and data sw options must be specified\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2332 #, c-format msgid "data su must be a multiple of the sector size (%d)\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2340 #, c-format msgid "" "data stripe width (%lld) is too large of a multiple of the data stripe unit " "(%d)\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2350 #, c-format msgid "" "data stripe width (%d) must be a multiple of the data stripe unit (%d)\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2372 #, c-format msgid "" "%s: Volume reports stripe unit of %d bytes and stripe width of 0, ignoring.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2385 #, c-format msgid "" "%s: Specified data stripe unit %d is not the same as the volume stripe unit " "%d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2390 #, c-format msgid "" "%s: Specified data stripe width %d is not the same as the volume stripe " "width %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2407 #, c-format msgid "" "%s: Stripe unit(%d) or stripe width(%d) is not a multiple of the block " "size(%d)\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2434 .././mkfs/xfs_mkfs.c:2442 #, c-format msgid "log stripe unit (%d) must be a multiple of the block size (%d)\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2464 #, c-format msgid "" "log stripe unit (%d bytes) is too large (maximum is 256KiB)\n" "log stripe unit adjusted to 32KiB\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2488 #, c-format msgid "no device name given in argument list\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2538 #, c-format msgid "can't get size of data subvolume\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2546 #, c-format msgid "" "size %s specified for data subvolume is too large, maximum is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2558 #, c-format msgid "size %lld of data subvolume is too small, minimum %d blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2565 #, c-format msgid "" "Warning: the data subvolume sector size %u is less than the sector size \n" "reported by the device (%u).\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2588 msgid "volume log" msgstr "" #: .././mkfs/xfs_mkfs.c:2597 #, c-format msgid "can't have both external and internal logs\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2613 #, c-format msgid "data and log sector sizes must be equal for internal logs\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2618 #, c-format msgid "log size %lld too large for internal log\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2622 .././libfrog/fsgeom.c:64 msgid "internal log" msgstr "" #: .././mkfs/xfs_mkfs.c:2630 #, c-format msgid "no log subvolume or external log.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2637 #, c-format msgid "unable to get size of the log subvolume.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2643 #, c-format msgid "" "size %s specified for log subvolume is too large, maximum is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2651 #, c-format msgid "" "Warning: the log subvolume sector size %u is less than the sector size\n" "reported by the device (%u).\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2670 #, c-format msgid "size specified for non-existent rt subvolume\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2681 #, c-format msgid "Invalid zero length rt subvolume found\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2687 msgid "volume rt" msgstr "" #: .././mkfs/xfs_mkfs.c:2694 #, c-format msgid "" "size %s specified for rt subvolume is too large, maxi->um is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2701 #, c-format msgid "" "Warning: the realtime subvolume sector size %u is less than the sector size\n" "reported by the device (%u).\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2728 #, c-format msgid "agsize (%s) not a multiple of fs blk size (%d)\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2810 #, c-format msgid "agsize rounded to %lld, sunit = %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:2821 #, c-format msgid "" "Warning: AG size is a multiple of stripe width. This can cause performance\n" "problems by aligning all AGs on the same disk. To avoid this, run mkfs " "with\n" "an AG size that is one stripe unit smaller or larger, for example %llu.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3011 #, c-format msgid "log size %lld is not a multiple of the log stripe unit %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3045 #, c-format msgid "" "Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" "within an allocation group.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3058 #, c-format msgid "" "Due to stripe alignment, the internal log size (%lld) is too large.\n" "Must fit within an allocation group.\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3070 #, c-format msgid "log size %lld blocks too small, minimum size is %d blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3076 #, c-format msgid "log size %lld blocks too large, maximum size is %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3082 #, c-format msgid "log size %lld bytes too large, maximum size is %lld bytes\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3121 #, c-format msgid "external log device %lld too small, must be at least %lld blocks\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3186 #, c-format msgid "internal log size %lld too large, must fit in allocation group\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3194 #, c-format msgid "log ag number %lld too large, must be less than %lld\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3360 #, c-format msgid "%s: Growing the data section failed\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3449 #, c-format msgid "AG header init failed, error %d\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3486 msgid "initializing AG free space list" msgstr "" #: .././mkfs/xfs_mkfs.c:3559 msgid "package build definitions" msgstr "" #: .././mkfs/xfs_mkfs.c:3651 #, c-format msgid "extra arguments\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3767 #, c-format msgid "%s: filesystem failed to initialize\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3784 .././mkfs/xfs_mkfs.c:3791 #, c-format msgid "%s: writing AG headers failed\n" msgstr "" #: .././mkfs/xfs_mkfs.c:3812 #, c-format msgid "%s: root inode created in AG %u, not AG 0\n" msgstr "" #: .././quota/init.c:37 #, c-format msgid "Usage: %s [-V] [-x] [-f] [-p prog] [-c cmd]... [-d project]... [path]\n" msgstr "" #: .././quota/init.c:119 #, c-format msgid "%s: command is for XFS filesystems only\n" msgstr "" #: .././quota/init.c:126 #, c-format msgid "%s: foreign filesystem. Invoke xfs_quota with -f to enable.\n" msgstr "" #: .././quota/quot.c:47 #, c-format msgid "" "\n" " display a summary of filesystem ownership\n" "\n" " -a -- summarise for all local XFS filesystem mount points\n" " -c -- display three columns giving file size in kilobytes, number of files\n" " of that size, and cumulative total of kilobytes in that size or\n" " smaller file. The last row is used as an overflow bucket and is the\n" " total of all files greater than 500 kilobytes.\n" " -v -- display three columns containing the number of kilobytes not\n" " accessed in the last 30, 60, and 90 days.\n" " -g -- display group summary\n" " -p -- display project summary\n" " -u -- display user summary\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n" msgstr "" #: .././quota/quot.c:205 #, c-format msgid "%s (%s) %s:\n" msgstr "" #: .././quota/quot.c:281 #, c-format msgid "%s (%s):\n" msgstr "" #: .././quota/quot.c:286 .././quota/quot.c:290 #, c-format msgid "%d\t%llu\t%llu\n" msgstr "" #: .././quota/quot.c:409 msgid "[-bir] [-g|-p|-u] [-acv] [-f file]" msgstr "" #: .././quota/quot.c:410 msgid "summarize filesystem ownership" msgstr "" #: .././quota/path.c:27 #, c-format msgid "%s%sFilesystem Pathname\n" msgstr "" #: .././quota/path.c:28 msgid " " msgstr "" #: .././quota/path.c:29 msgid " " msgstr "" #: .././quota/path.c:32 #, c-format msgid "%c%03d%c " msgstr "" #: .././quota/path.c:35 #, c-format msgid "%-19s %s" msgstr "" #: .././quota/path.c:38 #, c-format msgid " (project %u" msgstr "" #: .././quota/path.c:40 #, c-format msgid ", %s" msgstr "" #: .././quota/path.c:105 #, c-format msgid "No paths are available\n" msgstr "" #: .././quota/path.c:133 msgid "set current path, or show the list of paths" msgstr "" #: .././quota/path.c:141 msgid "list known mount points and projects" msgstr "" #: .././quota/quota.c:21 #, c-format msgid "" "\n" " display usage and quota information\n" "\n" " -g -- display group quota information\n" " -p -- display project quota information\n" " -u -- display user quota information\n" " -b -- display number of blocks used\n" " -i -- display number of inodes used\n" " -r -- display number of realtime blocks used\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the initial header\n" " -v -- increase verbosity in reporting (also dumps zero values)\n" " -f -- send output to a file\n" " The (optional) user/group/project can be specified either by name or by\n" " number (i.e. uid/gid/projid).\n" "\n" msgstr "" #: .././quota/quota.c:74 #, c-format msgid "" "Disk quotas for %s %s (%u)\n" "Filesystem%s" msgstr "" #: .././quota/quota.c:79 #, c-format msgid " Blocks Quota Limit Warn/Time " msgstr "" #: .././quota/quota.c:80 #, c-format msgid " Blocks Quota Limit Warn/Time " msgstr "" #: .././quota/quota.c:83 #, c-format msgid " Files Quota Limit Warn/Time " msgstr "" #: .././quota/quota.c:84 #, c-format msgid " Files Quota Limit Warn/Time " msgstr "" #: .././quota/quota.c:87 #, c-format msgid "Realtime Quota Limit Warn/Time " msgstr "" #: .././quota/quota.c:88 #, c-format msgid " Realtime Quota Limit Warn/Time " msgstr "" #: .././quota/quota.c:224 #, c-format msgid "%s: cannot find user %s\n" msgstr "" #: .././quota/quota.c:274 #, c-format msgid "%s: cannot find group %s\n" msgstr "" #: .././quota/quota.c:335 #, c-format msgid "%s: must specify a project name/ID\n" msgstr "" #: .././quota/quota.c:348 #, c-format msgid "%s: cannot find project %s\n" msgstr "" #: .././quota/quota.c:458 msgid "[-bir] [-g|-p|-u] [-hnNv] [-f file] [id|name]..." msgstr "" #: .././quota/quota.c:459 msgid "show usage and limits" msgstr "" #: .././quota/report.c:21 .././quota/report.c:756 .././quota/edit.c:709 msgid "[-g|-p|-u] [-f file]" msgstr "" #: .././quota/report.c:22 .././quota/report.c:757 msgid "dump quota information for backup utilities" msgstr "" #: .././quota/report.c:24 #, c-format msgid "" "\n" " create a backup file which contains quota limits information\n" " -g -- dump out group quota limits\n" " -p -- dump out project quota limits\n" " -u -- dump out user quota limits (default)\n" " -f -- write the dump out to the specified file\n" "\n" msgstr "" #: .././quota/report.c:36 msgid "[-bir] [-gpu] [-ahntlLNU] [-f file]" msgstr "" #: .././quota/report.c:37 .././quota/report.c:767 msgid "report filesystem quota information" msgstr "" #: .././quota/report.c:39 #, c-format msgid "" "\n" " report used space and inodes, and quota limits, for a filesystem\n" " Example:\n" " 'report -igh'\n" " (reports inode usage for all groups, in an easy-to-read format)\n" " This command is the equivalent of the traditional repquota command, which\n" " prints a summary of the disk usage and quotas for the current filesystem,\n" " or all filesystems.\n" " -a -- report for all mounted filesystems with quota enabled\n" " -h -- report in a human-readable format\n" " -n -- skip identifier-to-name translations, just report IDs\n" " -N -- suppress the header from the output\n" " -t -- terse output format, hides rows which are all zero\n" " -L -- lower ID bound to report on\n" " -U -- upper ID bound to report on\n" " -l -- look up names for IDs in lower-upper range\n" " -g -- report group usage and quota information\n" " -p -- report project usage and quota information\n" " -u -- report user usage and quota information\n" " -b -- report blocks-used information only\n" " -i -- report inodes-used information only\n" " -r -- report realtime-blocks-used information only\n" "\n" msgstr "" #: .././quota/report.c:261 #, c-format msgid "%s quota on %s (%s)\n" msgstr "" #: .././quota/report.c:286 .././quota/report.c:294 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr "" #: .././quota/report.c:287 .././quota/report.c:295 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr "" #: .././quota/report.c:290 #, c-format msgid " Used Soft Hard Warn/Grace " msgstr "" #: .././quota/report.c:291 #, c-format msgid " Used Soft Hard Warn/ Grace " msgstr "" #: .././quota/report.c:766 msgid "[-bir] [-gpu] [-ahnt] [-f file]" msgstr "" #: .././quota/state.c:21 #, c-format msgid "" "\n" " turn filesystem quota off, both accounting and enforcement\n" "\n" " Example:\n" " 'off -uv' (switch off user quota on the current filesystem)\n" " This command is the equivalent of the traditional quotaoff command,\n" " which disables quota completely on a mounted filesystem.\n" " Note that there is no 'on' command - for XFS filesystems (with the\n" " exception of the root filesystem on IRIX) quota can only be enabled\n" " at mount time, through the use of one of the quota mount options.\n" "\n" " The state command is useful for displaying the current state. Using\n" " the -v (verbose) option with the 'off' command will display the quota\n" " state for the affected filesystem once the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" #: .././quota/state.c:44 #, c-format msgid "" "\n" " query the state of quota on the current filesystem\n" "\n" " This is a verbose status command, reporting whether or not accounting\n" " and/or enforcement are enabled for a filesystem, which inodes are in\n" " use as the quota state inodes, and how many extents and blocks are\n" " presently being used to hold that information.\n" " The quota type is specified via -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" #: .././quota/state.c:60 #, c-format msgid "" "\n" " enable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and has quota accounting enabled, but not\n" " quota enforcement, enforcement can be enabled with this command.\n" " With the -v (verbose) option, the status of the filesystem will be\n" " reported after the operation is complete.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" #: .././quota/state.c:76 #, c-format msgid "" "\n" " disable quota enforcement on a filesystem\n" "\n" " If a filesystem is mounted and is currently enforcing quota, this\n" " provides a mechanism to switch off the enforcement, but continue to\n" " perform used space (and used inodes) accounting.\n" " The affected quota type is -g (groups), -p (projects) or -u (users).\n" "\n" msgstr "" #: .././quota/state.c:90 #, c-format msgid "" "\n" " remove any space being used by the quota subsystem\n" "\n" " Once quota has been switched 'off' on a filesystem, the space that\n" " was allocated to holding quota metadata can be freed via this command.\n" " The affected quota type is -g (groups), -p (projects) or -u (users)\n" " and defaults to user quota (multiple types can be specified).\n" "\n" msgstr "" #: .././quota/state.c:109 #, c-format msgid "%s quota state on %s (%s)\n" msgstr "" #: .././quota/state.c:111 #, c-format msgid " Accounting: %s\n" msgstr "" #: .././quota/state.c:111 .././quota/state.c:112 msgid "ON" msgstr "" #: .././quota/state.c:111 .././quota/state.c:112 msgid "OFF" msgstr "" #: .././quota/state.c:112 #, c-format msgid " Enforcement: %s\n" msgstr "" #: .././quota/state.c:114 #, c-format msgid " Inode: #%llu (%llu blocks, %lu extents)\n" msgstr "" #: .././quota/state.c:119 #, c-format msgid " Inode: N/A\n" msgstr "" #: .././quota/state.c:128 #, c-format msgid "%s grace time: %s\n" msgstr "" #: .././quota/state.c:200 #, c-format msgid "%s quota are not enabled on %s\n" msgstr "" #: .././quota/state.c:572 .././quota/state.c:589 .././quota/state.c:597 #: .././quota/state.c:605 msgid "[-gpu] [-v]" msgstr "" #: .././quota/state.c:573 msgid "permanently switch quota off for a path" msgstr "" #: .././quota/state.c:580 msgid "[-gpu] [-a] [-v] [-f file]" msgstr "" #: .././quota/state.c:581 msgid "get overall quota state information" msgstr "" #: .././quota/state.c:590 msgid "enable quota enforcement" msgstr "" #: .././quota/state.c:598 msgid "disable quota enforcement" msgstr "" #: .././quota/state.c:606 msgid "remove quota extents from a filesystem" msgstr "" #: .././quota/util.c:58 #, c-format msgid "[-none-]" msgstr "" #: .././quota/util.c:58 #, c-format msgid "[--none--]" msgstr "" #: .././quota/util.c:61 #, c-format msgid "[------]" msgstr "" #: .././quota/util.c:61 #, c-format msgid "[--------]" msgstr "" #: .././quota/util.c:65 .././quota/util.c:68 msgid "day" msgstr "" #: .././quota/util.c:65 .././quota/util.c:68 msgid "days" msgstr "" #: .././quota/util.c:193 msgid "Blocks" msgstr "" #: .././quota/util.c:193 msgid "Inodes" msgstr "" #: .././quota/util.c:193 msgid "Realtime Blocks" msgstr "" #: .././quota/util.c:208 msgid "User" msgstr "" #: .././quota/util.c:208 msgid "Group" msgstr "" #: .././quota/util.c:208 msgid "Project" msgstr "" #: .././quota/util.c:416 #, c-format msgid "%s: open on %s failed: %s\n" msgstr "" #: .././quota/util.c:422 #, c-format msgid "%s: fdopen on %s failed: %s\n" msgstr "" #: .././quota/edit.c:24 #, c-format msgid "" "\n" " modify quota limits for the specified user\n" "\n" " Example:\n" " 'limit bsoft=100m bhard=110m tanya\n" "\n" " Changes the soft and/or hard block limits, inode limits and/or realtime\n" " block limits that are currently being used for the specified user, group,\n" " or project. The filesystem identified by the current path is modified.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota limits\n" " -p -- modify project quota limits\n" " -u -- modify user quota limits\n" " The block limit values can be specified with a units suffix - accepted\n" " units are: k (kilobytes), m (megabytes), g (gigabytes), and t (terabytes).\n" " The user/group/project can be specified either by name or by number.\n" "\n" msgstr "" #: .././quota/edit.c:47 #, c-format msgid "" "\n" " modify quota enforcement timeout for the current filesystem\n" "\n" " Example:\n" " 'timer -i 3days'\n" " (soft inode limit timer is changed to 3 days)\n" "\n" " Changes the timeout value associated with the block limits, inode limits\n" " and/or realtime block limits for all users, groups, or projects on the\n" " current filesystem.\n" " As soon as a user consumes the amount of space or number of inodes set as\n" " the soft limit, a timer is started. If the timer expires and the user is\n" " still over the soft limit, the soft limit is enforced as the hard limit.\n" " The default timeout is 7 days.\n" " -d -- set the default values, used the first time a file is created\n" " -g -- modify group quota timer\n" " -p -- modify project quota timer\n" " -u -- modify user quota timer\n" " -b -- modify the blocks-used timer\n" " -i -- modify the inodes-used timer\n" " -r -- modify the blocks-used timer for the (optional) realtime subvolume\n" " The timeout value is specified as a number of seconds, by default.\n" " However, a suffix may be used to alternatively specify minutes (m),\n" " hours (h), days (d), or weeks (w) - either the full word or the first\n" " letter of the word can be used.\n" "\n" msgstr "" #: .././quota/edit.c:79 #, c-format msgid "" "\n" " modify the number of quota warnings sent to the specified user\n" "\n" " Example:\n" " 'warn 2 jimmy'\n" " (tell the quota system that two warnings have been sent to user jimmy)\n" "\n" " Changes the warning count associated with the block limits, inode limits\n" " and/or realtime block limits for the specified user, group, or project.\n" " When a user has been warned the maximum number of times allowed, the soft\n" " limit is enforced as the hard limit. It is intended as an alternative to\n" " the timeout system, where the system administrator updates a count of the\n" " number of warnings issued to people, and they are penalised if the " "warnings\n" " are ignored.\n" " -d -- set maximum warning count, which triggers soft limit enforcement\n" " -g -- set group quota warning count\n" " -p -- set project quota warning count\n" " -u -- set user quota warning count\n" " -b -- set the blocks-used warning count\n" " -i -- set the inodes-used warning count\n" " -r -- set the blocks-used warn count for the (optional) realtime subvolume\n" " The user/group/project can be specified either by name or by number.\n" "\n" msgstr "" #: .././quota/edit.c:133 #, c-format msgid "%s: cannot set limits: %s\n" msgstr "" #: .././quota/edit.c:154 .././quota/edit.c:575 #, c-format msgid "%s: invalid user name: %s\n" msgstr "" #: .././quota/edit.c:177 .././quota/edit.c:592 #, c-format msgid "%s: invalid group name: %s\n" msgstr "" #: .././quota/edit.c:200 .././quota/edit.c:609 #, c-format msgid "%s: invalid project name: %s\n" msgstr "" #: .././quota/edit.c:225 #, c-format msgid "%s: Error: could not parse size %s.\n" msgstr "" #: .././quota/edit.c:231 #, c-format msgid "%s: Warning: `%s' in quota blocks is 0 (unlimited).\n" msgstr "" #: .././quota/edit.c:320 #, c-format msgid "%s: unrecognised argument %s\n" msgstr "" #: .././quota/edit.c:327 #, c-format msgid "%s: cannot find any valid arguments\n" msgstr "" #: .././quota/edit.c:448 #, c-format msgid "%s: fopen on %s failed: %s\n" msgstr "" #: .././quota/edit.c:480 #, c-format msgid "%s: cannot set timer: %s\n" msgstr "" #: .././quota/edit.c:559 #, c-format msgid "%s: cannot set warnings: %s\n" msgstr "" #: .././quota/edit.c:700 msgid "[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name" msgstr "" #: .././quota/edit.c:701 msgid "modify quota limits" msgstr "" #: .././quota/edit.c:710 msgid "restore quota limits from a backup file" msgstr "" #: .././quota/edit.c:717 msgid "[-bir] [-g|-p|-u] value" msgstr "" #: .././quota/edit.c:718 msgid "set quota enforcement timeouts" msgstr "" #: .././quota/edit.c:726 msgid "[-bir] [-g|-p|-u] value -d|id|name" msgstr "" #: .././quota/edit.c:727 msgid "get/set enforcement warning counter" msgstr "" #: .././quota/free.c:20 #, c-format msgid "" "\n" " reports the number of free disk blocks and inodes\n" "\n" " This command reports the number of total, used, and available disk blocks.\n" " It can optionally report the same set of numbers for inodes and realtime\n" " disk blocks, and will report on all known XFS filesystem mount points and\n" " project quota paths by default (see 'print' command for a list).\n" " -b -- report the block count values\n" " -i -- report the inode count values\n" " -r -- report the realtime block count values\n" " -h -- report in a human-readable format\n" " -N -- suppress the header from the output\n" "\n" msgstr "" #: .././quota/free.c:161 #, c-format msgid "%s: project quota flag not set on %s\n" msgstr "" #: .././quota/free.c:170 #, c-format msgid "%s: project ID %u (%s) doesn't match ID %u (%s)\n" msgstr "" #: .././quota/free.c:237 #, c-format msgid "Filesystem " msgstr "" #: .././quota/free.c:237 #, c-format msgid "Filesystem " msgstr "" #: .././quota/free.c:240 #, c-format msgid " Size Used Avail Use%%" msgstr "" #: .././quota/free.c:241 #, c-format msgid " 1K-blocks Used Available Use%%" msgstr "" #: .././quota/free.c:244 #, c-format msgid " Inodes Used Free Use%%" msgstr "" #: .././quota/free.c:245 #, c-format msgid " Inodes IUsed IFree IUse%%" msgstr "" #: .././quota/free.c:246 #, c-format msgid " Pathname\n" msgstr "" #: .././quota/free.c:378 msgid "[-bir] [-hN] [-f file]" msgstr "" #: .././quota/free.c:379 msgid "show free and used counts for blocks and inodes" msgstr "" #: .././quota/project.c:33 #, c-format msgid "" "\n" " list projects or setup a project tree for tree quota management\n" "\n" " Example:\n" " 'project -c logfiles'\n" " (match project 'logfiles' to a directory, and setup the directory tree)\n" "\n" " Without arguments, report all projects found in the /etc/projects file.\n" " The project quota mechanism in XFS can be used to implement a form of\n" " directory tree quota, where a specified directory and all of the files\n" " and subdirectories below it (i.e. a tree) can be restricted to using a\n" " subset of the available space in the filesystem.\n" "\n" " A managed tree must be setup initially using the -s option with a project.\n" " The specified project name or identifier is matched to one or more trees\n" " defined in /etc/projects, and these trees are then recursively descended\n" " to mark the affected inodes as being part of that tree - which sets inode\n" " flags and the project identifier on every file.\n" " Once this has been done, new files created in the tree will automatically\n" " be accounted to the tree based on their project identifier. An attempt to\n" " create a hard link to a file in the tree will only succeed if the project\n" " identifier matches the project identifier for the tree. The xfs_io " "utility\n" " can be used to set the project ID for an arbitrary file, but this can only\n" " be done by a privileged user.\n" "\n" " A previously setup tree can be cleared from project quota control through\n" " use of the -C option, which will recursively descend the tree, clearing\n" " the affected inodes from project quota control.\n" "\n" " The -c option can be used to check whether a tree is setup, it reports\n" " nothing if the tree is correct, otherwise it reports the paths of inodes\n" " which do not have the project ID of the rest of the tree, or if the inode\n" " flag is not set.\n" "\n" " The -p option can be used to manually specify project path without\n" " need to create /etc/projects file. This option can be used multiple times\n" " to specify multiple paths. When using this option only one projid/name can\n" " be specified at command line. Note that /etc/projects is also used if " "exists.\n" "\n" " The -d option allows to descend at most levels of " "directories\n" " below the command line arguments. -d 0 means only apply the actions\n" " to the top level of the projects. -d -1 means no recursion limit " "(default).\n" "\n" " The /etc/projid and /etc/projects file formats are simple, and described\n" " on the xfs_quota man page.\n" "\n" msgstr "" #: .././quota/project.c:96 .././quota/project.c:141 .././quota/project.c:188 #, c-format msgid "%s: cannot stat file %s\n" msgstr "" #: .././quota/project.c:100 .././quota/project.c:145 .././quota/project.c:192 #, c-format msgid "%s: skipping special file %s\n" msgstr "" #: .././quota/project.c:114 #, c-format msgid "%s - project identifier is not set (inode=%u, tree=%u)\n" msgstr "" #: .././quota/project.c:118 #, c-format msgid "%s - project inheritance flag is not set\n" msgstr "" #: .././quota/project.c:166 #, c-format msgid "%s: cannot clear project on %s: %s\n" msgstr "" #: .././quota/project.c:213 #, c-format msgid "%s: cannot set project on %s: %s\n" msgstr "" #: .././quota/project.c:228 #, c-format msgid "Checking project %s (path %s)...\n" msgstr "" #: .././quota/project.c:232 #, c-format msgid "Setting up project %s (path %s)...\n" msgstr "" #: .././quota/project.c:236 #, c-format msgid "Clearing project %s (path %s)...\n" msgstr "" #: .././quota/project.c:259 #, c-format msgid "" "Processed %d (%s and cmdline) paths for project %s with recursion depth %s " "(%d).\n" msgstr "" #: .././quota/project.c:262 msgid "infinite" msgstr "" #: .././quota/project.c:262 msgid "limited" msgstr "" #: .././quota/project.c:307 #, c-format msgid "projects file \"%s\" doesn't exist\n" msgstr "" #: .././quota/project.c:314 #, c-format msgid "" "%s: only one projid/name can be specified when using -p , %d found.\n" msgstr "" #: .././quota/project.c:324 #, c-format msgid "%s - no such project in %s or invalid project number\n" msgstr "" #: .././quota/project.c:341 msgid "[-c|-s|-C|-d |-p ] project ..." msgstr "" #: .././quota/project.c:344 msgid "check, setup or clear project quota trees" msgstr "" #: .././repair/bmap.c:41 #, c-format msgid "" "Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n" "If this is not a corruption, then you will need a 64 bit system\n" "to repair this filesystem.\n" msgstr "" #: .././repair/bmap.c:54 #, c-format msgid "malloc failed in blkmap_alloc (%zu bytes)\n" msgstr "" #: .././repair/bmap.c:177 #, c-format msgid "blkmap_getn malloc failed (% bytes)\n" msgstr "" #: .././repair/bmap.c:284 #, c-format msgid "" "Number of extents requested in blkmap_grow (%d) overflows 32 bits.\n" "You need a 64 bit system to repair this filesystem.\n" msgstr "" #: .././repair/bmap.c:292 #, c-format msgid "" "Number of extents requested in blkmap_grow (%d) overflowed the\n" "maximum number of supported extents (%d).\n" msgstr "" #: .././repair/bmap.c:300 msgid "realloc failed in blkmap_grow\n" msgstr "" #: .././repair/incore.c:218 #, c-format msgid "couldn't allocate realtime block map, size = %\n" msgstr "" #: .././repair/incore.c:283 msgid "couldn't allocate block map btree roots\n" msgstr "" #: .././repair/incore.c:287 msgid "couldn't allocate block map locks\n" msgstr "" #: .././repair/init.c:34 #, c-format msgid "getrlimit(RLIMIT_FSIZE) failed!\n" msgstr "" #: .././repair/init.c:42 #, c-format msgid "setrlimit failed - current: %lld, max: %lld\n" msgstr "" #: .././repair/init.c:95 #, c-format msgid "" "Unmount or use the dangerous (-d) option to repair a read-only mounted " "filesystem\n" msgstr "" #: .././repair/init.c:97 msgid "couldn't initialize XFS library\n" msgstr "" #: .././repair/dir2.c:38 #, c-format msgid "malloc failed (%zu bytes) dir2_add_badlist:ino %\n" msgstr "" #: .././repair/dir2.c:81 msgid "couldn't malloc dir2 shortform copy\n" msgstr "" #: .././repair/dir2.c:217 msgid "current" msgstr "" #: .././repair/dir2.c:220 .././repair/dir2.c:683 msgid "invalid" msgstr "" #: .././repair/dir2.c:223 .././repair/dir2.c:685 msgid "realtime bitmap" msgstr "" #: .././repair/dir2.c:226 .././repair/dir2.c:687 msgid "realtime summary" msgstr "" #: .././repair/dir2.c:229 .././repair/dir2.c:689 msgid "user quota" msgstr "" #: .././repair/dir2.c:232 .././repair/dir2.c:691 msgid "group quota" msgstr "" #: .././repair/dir2.c:235 .././repair/dir2.c:693 msgid "project quota" msgstr "" #: .././repair/dir2.c:253 .././repair/dir2.c:723 msgid "free" msgstr "" #: .././repair/dir2.c:270 .././repair/dir2.c:703 msgid "non-existent" msgstr "" #: .././repair/dir2.c:275 #, c-format msgid "" "entry \"%*.*s\" in shortform directory % references %s inode " "%\n" msgstr "" #: .././repair/dir2.c:281 msgid "is zero length" msgstr "" #: .././repair/dir2.c:286 msgid "extends past end of dir" msgstr "" #: .././repair/dir2.c:292 #, c-format msgid "entry #%d %s in shortform dir %" msgstr "" #: .././repair/dir2.c:295 #, c-format msgid ", junking %d entries\n" msgstr "" #: .././repair/dir2.c:298 #, c-format msgid ", would junk %d entries\n" msgstr "" #: .././repair/dir2.c:318 #, c-format msgid "entry contains illegal character in shortform dir %\n" msgstr "" #: .././repair/dir2.c:325 #, c-format msgid "entry contains offset out of order in shortform dir %\n" msgstr "" #: .././repair/dir2.c:382 #, c-format msgid "junking entry \"%s\" in directory inode %\n" msgstr "" #: .././repair/dir2.c:386 #, c-format msgid "would have junked entry \"%s\" in directory inode %\n" msgstr "" #: .././repair/dir2.c:411 #, c-format msgid "would have corrected entry count in directory % from %d to %d\n" msgstr "" #: .././repair/dir2.c:415 #, c-format msgid "corrected entry count in directory %, was %d, now %d\n" msgstr "" #: .././repair/dir2.c:426 #, c-format msgid "would have corrected i8 count in directory % from %d to %d\n" msgstr "" #: .././repair/dir2.c:430 #, c-format msgid "corrected i8 count in directory %, was %d, now %d\n" msgstr "" #: .././repair/dir2.c:444 #, c-format msgid "" "would have corrected directory % size from % to %\n" msgstr "" #: .././repair/dir2.c:449 #, c-format msgid "corrected directory % size, was %, now %\n" msgstr "" #: .././repair/dir2.c:461 #, c-format msgid "directory % offsets too high\n" msgstr "" #: .././repair/dir2.c:467 #, c-format msgid "would have corrected entry offsets in directory %\n" msgstr "" #: .././repair/dir2.c:471 #, c-format msgid "corrected entry offsets in directory %\n" msgstr "" #: .././repair/dir2.c:492 #, c-format msgid "bogus .. inode number (%) in directory inode %, " msgstr "" #: .././repair/dir2.c:496 .././repair/dir2.c:531 msgid "clearing inode number\n" msgstr "" #: .././repair/dir2.c:502 .././repair/dir2.c:537 msgid "would clear inode number\n" msgstr "" #: .././repair/dir2.c:510 #, c-format msgid "" "corrected root directory % .. entry, was %, now %\n" msgstr "" #: .././repair/dir2.c:518 #, c-format msgid "" "would have corrected root directory % .. entry from % to " "%\n" msgstr "" #: .././repair/dir2.c:528 #, c-format msgid "bad .. entry in directory inode %, points to self, " msgstr "" #: .././repair/dir2.c:641 #, c-format msgid "corrupt block %u in directory inode %\n" msgstr "" #: .././repair/dir2.c:644 msgid "\twill junk block\n" msgstr "" #: .././repair/dir2.c:646 msgid "\twould junk block\n" msgstr "" #: .././repair/dir2.c:732 #, c-format msgid "" "entry \"%*.*s\" at block %d offset % in directory inode % " "references %s inode %\n" msgstr "" #: .././repair/dir2.c:755 #, c-format msgid "" "entry at block %u offset % in directory inode %has 0 " "namelength\n" msgstr "" #: .././repair/dir2.c:768 #, c-format msgid "\tclearing inode number in entry at offset %...\n" msgstr "" #: .././repair/dir2.c:774 #, c-format msgid "\twould clear inode number in entry at offset %...\n" msgstr "" #: .././repair/dir2.c:787 #, c-format msgid "" "entry at block %u offset % in directory inode % has illegal " "name \"%*.*s\": " msgstr "" #: .././repair/dir2.c:818 #, c-format msgid "bad .. entry in directory inode %, points to self: " msgstr "" #: .././repair/dir2.c:829 #, c-format msgid "bad .. entry in root directory inode %, was %: " msgstr "" #: .././repair/dir2.c:832 .././repair/dir2.c:851 .././repair/dir2.c:882 #: .././repair/phase2.c:209 .././repair/phase2.c:218 .././repair/phase2.c:227 msgid "correcting\n" msgstr "" #: .././repair/dir2.c:836 .././repair/dir2.c:853 .././repair/dir2.c:886 #: .././repair/dinode.c:2417 .././repair/phase2.c:211 .././repair/phase2.c:220 #: .././repair/phase2.c:229 msgid "would correct\n" msgstr "" #: .././repair/dir2.c:848 #, c-format msgid "bad .. entry in directory inode %, was %: " msgstr "" #: .././repair/dir2.c:866 #, c-format msgid "multiple .. entries in directory inode %: " msgstr "" #: .././repair/dir2.c:879 #, c-format msgid "bad . entry in directory inode %, was %: " msgstr "" #: .././repair/dir2.c:891 #, c-format msgid "multiple . entries in directory inode %: " msgstr "" #: .././repair/dir2.c:901 #, c-format msgid "entry \"%*.*s\" in directory inode % points to self: " msgstr "" #: .././repair/dir2.c:912 msgid "clearing entry\n" msgstr "" #: .././repair/dir2.c:914 msgid "would clear entry\n" msgstr "" #: .././repair/dir2.c:927 #, c-format msgid "bad bestfree table in block %u in directory inode %: " msgstr "" #: .././repair/dir2.c:930 msgid "repairing table\n" msgstr "" #: .././repair/dir2.c:935 msgid "would repair table\n" msgstr "" #: .././repair/dir2.c:975 #, c-format msgid "block %u for directory inode % is missing\n" msgstr "" #: .././repair/dir2.c:984 #, c-format msgid "can't read block %u for directory inode %\n" msgstr "" #: .././repair/dir2.c:995 #, c-format msgid "" "bad directory block magic # %#x in block %u for directory inode %\n" msgstr "" #: .././repair/dir2.c:1047 #, c-format msgid "bad entry count in block %u of directory inode %\n" msgstr "" #: .././repair/dir2.c:1055 #, c-format msgid "bad hash ordering in block %u of directory inode %\n" msgstr "" #: .././repair/dir2.c:1063 #, c-format msgid "bad stale count in block %u of directory inode %\n" msgstr "" #: .././repair/dir2.c:1112 #, c-format msgid "can't map block %u for directory inode %\n" msgstr "" #: .././repair/dir2.c:1122 #, c-format msgid "can't read file block %u for directory inode %\n" msgstr "" #: .././repair/dir2.c:1134 #, c-format msgid "bad directory leaf magic # %#x for directory inode % block %u\n" msgstr "" #: .././repair/dir2.c:1162 #, c-format msgid "bad sibling back pointer for block %u in directory inode %\n" msgstr "" #: .././repair/dir2.c:1193 #, c-format msgid "bad hash path in directory %\n" msgstr "" #: .././repair/dir2.c:1314 #, c-format msgid "block % for directory inode % is missing\n" msgstr "" #: .././repair/dir2.c:1323 #, c-format msgid "can't read block % for directory inode %\n" msgstr "" #: .././repair/dir2.c:1331 #, c-format msgid "" "bad directory block magic # %#x in block % for directory inode " "%\n" msgstr "" #: .././repair/dir2.c:1412 #, c-format msgid "bad size/format for directory %\n" msgstr "" #: .././repair/dir2.c:1419 #, c-format msgid "no . entry for directory %\n" msgstr "" #: .././repair/dir2.c:1429 #, c-format msgid "no .. entry for directory %\n" msgstr "" #: .././repair/dir2.c:1431 #, c-format msgid "no .. entry for root directory %\n" msgstr "" #: .././repair/phase7.c:39 .././repair/phase6.c:2893 .././repair/phase6.c:2897 #, c-format msgid "couldn't map inode %, err = %d\n" msgstr "" #: .././repair/phase7.c:43 #, c-format msgid "couldn't map inode %, err = %d, can't compare link counts\n" msgstr "" #: .././repair/phase7.c:55 #, c-format msgid "resetting inode % nlinks from %u to %u\n" msgstr "" #: .././repair/phase7.c:61 #, c-format msgid "would have reset inode % nlinks from %u to %u\n" msgstr "" #: .././repair/phase7.c:131 msgid "Phase 7 - verify and correct link counts...\n" msgstr "" #: .././repair/phase7.c:133 msgid "Phase 7 - verify link counts...\n" msgstr "" #: .././repair/dino_chunks.c:45 #, c-format msgid "cannot read agbno (%u/%u), disk block %\n" msgstr "" #: .././repair/dino_chunks.c:139 #, c-format msgid "uncertain inode block %d/%d already known\n" msgstr "" #: .././repair/dino_chunks.c:155 .././repair/dino_chunks.c:427 #: .././repair/dino_chunks.c:486 #, c-format msgid "inode block %d/%d multiply claimed, (state %d)\n" msgstr "" #: .././repair/dino_chunks.c:162 .././repair/dino_chunks.c:491 #, c-format msgid "inode block %d/%d bad state, (state %d)\n" msgstr "" #: .././repair/dino_chunks.c:434 #, c-format msgid "uncertain inode block overlap, agbno = %d, ino = %\n" msgstr "" #: .././repair/dino_chunks.c:473 #, c-format msgid "uncertain inode block % already known\n" msgstr "" #: .././repair/dino_chunks.c:567 #, c-format msgid "bad state in block map %d\n" msgstr "" #: .././repair/dino_chunks.c:572 #, c-format msgid "inode block % multiply claimed, state was %d\n" msgstr "" #: .././repair/dino_chunks.c:640 #, c-format msgid "failed to allocate %zd bytes of memory\n" msgstr "" #: .././repair/dino_chunks.c:666 #, c-format msgid "cannot read inode %, disk block %, cnt %d\n" msgstr "" #: .././repair/dino_chunks.c:822 #, c-format msgid "imap claims in-use inode % is free, " msgstr "" #: .././repair/dino_chunks.c:827 msgid "correcting imap\n" msgstr "" #: .././repair/dino_chunks.c:829 msgid "would correct imap\n" msgstr "" #: .././repair/dino_chunks.c:882 #, c-format msgid "cleared root inode %\n" msgstr "" #: .././repair/dino_chunks.c:886 #, c-format msgid "would clear root inode %\n" msgstr "" #: .././repair/dino_chunks.c:894 #, c-format msgid "cleared realtime bitmap inode %\n" msgstr "" #: .././repair/dino_chunks.c:898 #, c-format msgid "would clear realtime bitmap inode %\n" msgstr "" #: .././repair/dino_chunks.c:906 #, c-format msgid "cleared realtime summary inode %\n" msgstr "" #: .././repair/dino_chunks.c:910 #, c-format msgid "would clear realtime summary inode %\n" msgstr "" #: .././repair/dino_chunks.c:914 #, c-format msgid "cleared inode %\n" msgstr "" #: .././repair/dino_chunks.c:917 #, c-format msgid "would have cleared inode %\n" msgstr "" #: .././repair/dino_chunks.c:1109 .././repair/dino_chunks.c:1144 #: .././repair/dino_chunks.c:1259 msgid "found inodes not in the inode allocation tree\n" msgstr "" #: .././repair/versions.c:67 #, c-format msgid "bogus quota flags 0x%x set in superblock" msgstr "" #: .././repair/versions.c:73 msgid ", bogus flags will be cleared\n" msgstr "" #: .././repair/versions.c:75 msgid ", bogus flags would be cleared\n" msgstr "" #: .././repair/versions.c:111 msgid "Shared Version bit set. Not supported. Ever.\n" msgstr "" #: .././repair/versions.c:120 #, c-format msgid "WARNING: unknown superblock version %d\n" msgstr "" #: .././repair/versions.c:123 msgid "This filesystem contains features not understood by this program.\n" msgstr "" #: .././repair/versions.c:136 #, c-format msgid "" "Superblock has unknown compat/rocompat/incompat features (0x%x/0x%x/0x%x).\n" "Using a more recent xfs_repair is recommended.\n" msgstr "" #: .././repair/versions.c:153 msgid "" "WARNING: you have a V1 inode filesystem. It will be converted to a\n" "\tversion 2 inode filesystem. If you do not want this, run an older\n" "\tversion of xfs_repair.\n" msgstr "" #: .././repair/versions.c:158 msgid "" "WARNING: you have a V1 inode filesystem. It would be converted to a\n" "\tversion 2 inode filesystem. If you do not want this, run an older\n" "\tversion of xfs_repair.\n" msgstr "" #: .././repair/dinode.c:42 msgid "real-time" msgstr "" #: .././repair/dinode.c:43 msgid "regular" msgstr "" #: .././repair/dinode.c:66 #, c-format msgid "clearing inode % attributes\n" msgstr "" #: .././repair/dinode.c:69 #, c-format msgid "would have cleared inode % attributes\n" msgstr "" #: .././repair/dinode.c:316 #, c-format msgid "" "inode % - bad rt extent start block number %, offset " "%\n" msgstr "" #: .././repair/dinode.c:324 #, c-format msgid "" "inode % - bad rt extent last block number %, offset " "%\n" msgstr "" #: .././repair/dinode.c:332 #, c-format msgid "" "inode % - bad rt extent overflows - start %, end %, " "offset %\n" msgstr "" #: .././repair/dinode.c:354 #, c-format msgid "" "data fork in rt ino % claims dup rt extent,off - %, start - " "%, count %\n" msgstr "" #: .././repair/dinode.c:373 #, c-format msgid "bad state in rt block map %\n" msgstr "" #: .././repair/dinode.c:379 #, c-format msgid "" "data fork in rt inode % found metadata block % in rt bmap\n" msgstr "" #: .././repair/dinode.c:388 #, c-format msgid "data fork in rt inode % claims used rt block %\n" msgstr "" #: .././repair/dinode.c:394 #, c-format msgid "illegal state %d in rt block map %\n" msgstr "" #: .././repair/dinode.c:457 #, c-format msgid "" "bmap rec out of order, inode % entry %d [o s c] [% % " "%], %d [% % %]\n" msgstr "" #: .././repair/dinode.c:473 #, c-format msgid "" "zero length extent (off = %, fsbno = %) in ino %\n" msgstr "" #: .././repair/dinode.c:504 #, c-format msgid "" "inode % - bad extent starting block number %, offset " "%\n" msgstr "" #: .././repair/dinode.c:512 #, c-format msgid "" "inode % - bad extent last block number %, offset %\n" msgstr "" #: .././repair/dinode.c:520 #, c-format msgid "" "inode % - bad extent overflows - start %, end %, " "offset %\n" msgstr "" #: .././repair/dinode.c:532 #, c-format msgid "" "inode % - extent exceeds max offset - start %, count " "%, physical block %\n" msgstr "" #: .././repair/dinode.c:553 #, c-format msgid "" "Fatal error: inode % - blkmap_set_ext(): %s\n" "\t%s fork, off - %, start - %, cnt %\n" msgstr "" #: .././repair/dinode.c:586 #, c-format msgid "" "%s fork in ino % claims dup extent, off - %, start - " "%, cnt %\n" msgstr "" #: .././repair/dinode.c:605 #, c-format msgid "%s fork in ino % claims free block %\n" msgstr "" #: .././repair/dinode.c:613 #, c-format msgid "bad state in block map %\n" msgstr "" #: .././repair/dinode.c:618 msgid "rmap claims metadata use!\n" msgstr "" #: .././repair/dinode.c:625 #, c-format msgid "%s fork in inode % claims metadata block %\n" msgstr "" #: .././repair/dinode.c:635 #, c-format msgid "%s fork in %s inode % claims used block %\n" msgstr "" #: .././repair/dinode.c:641 #, c-format msgid "%s fork in %s inode % claims CoW block %\n" msgstr "" #: .././repair/dinode.c:647 #, c-format msgid "illegal state %d in block map %\n" msgstr "" #: .././repair/dinode.c:683 msgid "couldn't add reverse mapping\n" msgstr "" #: .././repair/dinode.c:695 #, c-format msgid "correcting nextents for inode %\n" msgstr "" #: .././repair/dinode.c:783 #, c-format msgid "cannot read inode (%u/%u), disk block %\n" msgstr "" #: .././repair/dinode.c:851 #, c-format msgid "bad level %d in inode % bmap btree root block\n" msgstr "" #: .././repair/dinode.c:857 #, c-format msgid "bad numrecs 0 in inode % bmap btree root block\n" msgstr "" #: .././repair/dinode.c:866 #, c-format msgid "" "indicated size of %s btree root (%d bytes) greater than space in inode " "% %s fork\n" msgstr "" #: .././repair/dinode.c:887 #, c-format msgid "bad bmap btree ptr 0x% in ino %\n" msgstr "" #: .././repair/dinode.c:907 #, c-format msgid "" "correcting key in bmbt root (was %, now %) in inode " "% %s fork\n" msgstr "" #: .././repair/dinode.c:919 #, c-format msgid "" "bad key in bmbt root (is %, would reset to %) in inode " "% %s fork\n" msgstr "" #: .././repair/dinode.c:935 #, c-format msgid "out of order bmbt root key % in inode % %s fork\n" msgstr "" #: .././repair/dinode.c:952 #, c-format msgid "" "extent count for ino % %s fork too low (%) for file format\n" msgstr "" #: .././repair/dinode.c:963 #, c-format msgid "bad fwd (right) sibling pointer (saw % should be NULLFSBLOCK)\n" msgstr "" #: .././repair/dinode.c:966 #, c-format msgid "\tin inode % (%s fork) bmap btree block %\n" msgstr "" #: .././repair/dinode.c:1048 #, c-format msgid "local inode % data fork is too large (size = %lld, max = %d)\n" msgstr "" #: .././repair/dinode.c:1056 #, c-format msgid "local inode % attr fork too large (size %d, max = %d)\n" msgstr "" #: .././repair/dinode.c:1063 #, c-format msgid "local inode % attr too small (size = %d, min size = %zd)\n" msgstr "" #: .././repair/dinode.c:1087 #, c-format msgid "" "mismatch between format (%d) and size (%) in symlink ino %\n" msgstr "" #: .././repair/dinode.c:1094 #, c-format msgid "" "mismatch between format (%d) and size (%) in symlink inode " "%\n" msgstr "" #: .././repair/dinode.c:1109 #, c-format msgid "bad number of extents (%d) in symlink % data fork\n" msgstr "" #: .././repair/dinode.c:1121 #, c-format msgid "bad extent #%d offset (%) in symlink % data fork\n" msgstr "" #: .././repair/dinode.c:1127 #, c-format msgid "bad extent #%d count (%) in symlink % data fork\n" msgstr "" #: .././repair/dinode.c:1185 msgid "User quota" msgstr "" #: .././repair/dinode.c:1189 msgid "Group quota" msgstr "" #: .././repair/dinode.c:1193 msgid "Project quota" msgstr "" #: .././repair/dinode.c:1215 #, c-format msgid "" "cannot read inode %, file block %, disk block %\n" msgstr "" #: .././repair/dinode.c:1229 #, c-format msgid "%s: bad CRC for id %u. " msgstr "" #: .././repair/dinode.c:1237 #, c-format msgid "%s: bad UUID for id %u. " msgstr "" #: .././repair/dinode.c:1245 #, c-format msgid "%s: Corrupt quota for id %u. " msgstr "" #: .././repair/dinode.c:1253 msgid "Would correct.\n" msgstr "" #: .././repair/dinode.c:1255 msgid "Corrected.\n" msgstr "" #: .././repair/dinode.c:1298 #, c-format msgid "cannot read inode %, file block %d, NULL disk block\n" msgstr "" #: .././repair/dinode.c:1320 #, c-format msgid "cannot read inode %, file block %d, disk block %\n" msgstr "" #: .././repair/dinode.c:1326 #, c-format msgid "Corrupt symlink remote block %, inode %.\n" msgstr "" #: .././repair/dinode.c:1333 #, c-format msgid "" "Bad symlink buffer CRC, block %, inode %.\n" "Correcting CRC, but symlink may be bad.\n" msgstr "" #: .././repair/dinode.c:1346 #, c-format msgid "bad symlink header ino %, file block %d, disk block %\n" msgstr "" #: .././repair/dinode.c:1389 #, c-format msgid "symlink in inode % too long (%llu chars)\n" msgstr "" #: .././repair/dinode.c:1395 #, c-format msgid "zero size symlink in inode %\n" msgstr "" #: .././repair/dinode.c:1426 #, c-format msgid "found illegal null character in symlink inode %\n" msgstr "" #: .././repair/dinode.c:1451 #, c-format msgid "inode % has bad inode type (IFMNT)\n" msgstr "" #: .././repair/dinode.c:1462 #, c-format msgid "size of character device inode % != 0 (% bytes)\n" msgstr "" #: .././repair/dinode.c:1467 #, c-format msgid "size of block device inode % != 0 (% bytes)\n" msgstr "" #: .././repair/dinode.c:1472 #, c-format msgid "size of socket inode % != 0 (% bytes)\n" msgstr "" #: .././repair/dinode.c:1477 #, c-format msgid "size of fifo inode % != 0 (% bytes)\n" msgstr "" #: .././repair/dinode.c:1484 #, c-format msgid "size of quota inode % != 0 (% bytes)\n" msgstr "" #: .././repair/dinode.c:1488 #, c-format msgid "Internal error - process_misc_ino_types, illegal type %d\n" msgstr "" #: .././repair/dinode.c:1515 #, c-format msgid "size of character device inode % != 0 (% blocks)\n" msgstr "" #: .././repair/dinode.c:1520 #, c-format msgid "size of block device inode % != 0 (% blocks)\n" msgstr "" #: .././repair/dinode.c:1525 #, c-format msgid "size of socket inode % != 0 (% blocks)\n" msgstr "" #: .././repair/dinode.c:1530 #, c-format msgid "size of fifo inode % != 0 (% blocks)\n" msgstr "" #: .././repair/dinode.c:1608 #, c-format msgid "root inode % has bad type 0x%x\n" msgstr "" #: .././repair/dinode.c:1612 msgid "resetting to directory\n" msgstr "" #: .././repair/dinode.c:1616 msgid "would reset to directory\n" msgstr "" #: .././repair/dinode.c:1622 #, c-format msgid "user quota inode % has bad type 0x%x\n" msgstr "" #: .././repair/dinode.c:1631 #, c-format msgid "group quota inode % has bad type 0x%x\n" msgstr "" #: .././repair/dinode.c:1640 #, c-format msgid "project quota inode % has bad type 0x%x\n" msgstr "" #: .././repair/dinode.c:1650 #, c-format msgid "realtime summary inode % has bad type 0x%x, " msgstr "" #: .././repair/dinode.c:1653 .././repair/dinode.c:1674 msgid "resetting to regular file\n" msgstr "" #: .././repair/dinode.c:1657 .././repair/dinode.c:1678 msgid "would reset to regular file\n" msgstr "" #: .././repair/dinode.c:1662 #, c-format msgid "bad # of extents (%u) for realtime summary inode %\n" msgstr "" #: .././repair/dinode.c:1671 #, c-format msgid "realtime bitmap inode % has bad type 0x%x, " msgstr "" #: .././repair/dinode.c:1683 #, c-format msgid "bad # of extents (%u) for realtime bitmap inode %\n" msgstr "" #: .././repair/dinode.c:1718 #, c-format msgid "" "mismatch between format (%d) and size (%) in directory ino " "%\n" msgstr "" #: .././repair/dinode.c:1724 #, c-format msgid "directory inode % has bad size %\n" msgstr "" #: .././repair/dinode.c:1732 #, c-format msgid "bad data fork in symlink %\n" msgstr "" #: .././repair/dinode.c:1761 #, c-format msgid "found inode % claiming to be a real-time file\n" msgstr "" #: .././repair/dinode.c:1770 #, c-format msgid "" "realtime bitmap inode % has bad size % (should be " "%)\n" msgstr "" #: .././repair/dinode.c:1781 #, c-format msgid "" "realtime summary inode % has bad size % (should be %d)\n" msgstr "" #: .././repair/dinode.c:1809 #, c-format msgid "bad attr fork offset %d in dev inode %, should be %d\n" msgstr "" #: .././repair/dinode.c:1821 #, c-format msgid "bad attr fork offset %d in inode %, max=%d\n" msgstr "" #: .././repair/dinode.c:1828 #, c-format msgid "unexpected inode format %d\n" msgstr "" #: .././repair/dinode.c:1849 #, c-format msgid "correcting nblocks for inode %, was %llu - counted %\n" msgstr "" #: .././repair/dinode.c:1856 #, c-format msgid "bad nblocks %llu for inode %, would reset to %\n" msgstr "" #: .././repair/dinode.c:1864 #, c-format msgid "too many data fork extents (%) in inode %\n" msgstr "" #: .././repair/dinode.c:1871 #, c-format msgid "correcting nextents for inode %, was %d - counted %\n" msgstr "" #: .././repair/dinode.c:1879 #, c-format msgid "bad nextents %d for inode %, would reset to %\n" msgstr "" #: .././repair/dinode.c:1887 #, c-format msgid "too many attr fork extents (%) in inode %\n" msgstr "" #: .././repair/dinode.c:1894 #, c-format msgid "correcting anextents for inode %, was %d - counted %\n" msgstr "" #: .././repair/dinode.c:1901 #, c-format msgid "bad anextents %d for inode %, would reset to %\n" msgstr "" #: .././repair/dinode.c:1913 #, c-format msgid "nblocks (%) smaller than nextents for inode %\n" msgstr "" #: .././repair/dinode.c:1978 .././repair/dinode.c:2016 #, c-format msgid "unknown format %d, ino % (mode = %d)\n" msgstr "" #: .././repair/dinode.c:1983 #, c-format msgid "bad data fork in inode %\n" msgstr "" #: .././repair/dinode.c:2054 #, c-format msgid "bad attribute format %d in inode %, " msgstr "" #: .././repair/dinode.c:2057 msgid "resetting value\n" msgstr "" #: .././repair/dinode.c:2061 msgid "would reset value\n" msgstr "" #: .././repair/dinode.c:2091 .././repair/attr_repair.c:1163 #, c-format msgid "illegal attribute format %d, ino %\n" msgstr "" #: .././repair/dinode.c:2106 #, c-format msgid "bad attribute fork in inode %" msgstr "" #: .././repair/dinode.c:2109 msgid ", clearing attr fork\n" msgstr "" #: .././repair/dinode.c:2114 msgid ", would clear attr fork\n" msgstr "" #: .././repair/dinode.c:2142 #, c-format msgid "illegal attribute fmt %d, ino %\n" msgstr "" #: .././repair/dinode.c:2162 #, c-format msgid "problem with attribute contents in inode %\n" msgstr "" #: .././repair/dinode.c:2170 msgid "would clear attr fork\n" msgstr "" #: .././repair/dinode.c:2203 #, c-format msgid "" "clearing obsolete nlink field in version 2 inode %, was %d, now 0\n" msgstr "" #: .././repair/dinode.c:2209 #, c-format msgid "" "would clear obsolete nlink field in version 2 inode %, currently %d\n" msgstr "" #: .././repair/dinode.c:2228 #, c-format msgid "Bad %s nsec %u on inode %, " msgstr "" #: .././repair/dinode.c:2230 .././repair/dinode.c:2731 #: .././repair/dinode.c:2753 msgid "would reset to zero\n" msgstr "" #: .././repair/dinode.c:2232 .././repair/dinode.c:2725 #: .././repair/dinode.c:2748 msgid "resetting to zero\n" msgstr "" #: .././repair/dinode.c:2310 #, c-format msgid "bad CRC for inode %%c" msgstr "" #: .././repair/dinode.c:2314 msgid " will rewrite\n" msgstr "" #: .././repair/dinode.c:2317 msgid " would rewrite\n" msgstr "" #: .././repair/dinode.c:2324 #, c-format msgid "bad magic number 0x%x on inode %%c" msgstr "" #: .././repair/dinode.c:2329 msgid " resetting magic number\n" msgstr "" #: .././repair/dinode.c:2333 msgid " would reset magic number\n" msgstr "" #: .././repair/dinode.c:2340 #, c-format msgid "bad version number 0x%x on inode %%c" msgstr "" #: .././repair/dinode.c:2345 msgid " resetting version number\n" msgstr "" #: .././repair/dinode.c:2350 msgid " would reset version number\n" msgstr "" #: .././repair/dinode.c:2363 #, c-format msgid "inode identifier %llu mismatch on inode %\n" msgstr "" #: .././repair/dinode.c:2374 #, c-format msgid "UUID mismatch on inode %\n" msgstr "" #: .././repair/dinode.c:2387 #, c-format msgid "bad (negative) size % on inode %\n" msgstr "" #: .././repair/dinode.c:2411 #, c-format msgid "free inode % contains errors, " msgstr "" #: .././repair/dinode.c:2414 msgid "corrected\n" msgstr "" #: .././repair/dinode.c:2429 #, c-format msgid "imap claims a free inode % is in use, " msgstr "" #: .././repair/dinode.c:2431 msgid "correcting imap and clearing inode\n" msgstr "" #: .././repair/dinode.c:2436 msgid "would correct imap and clear inode\n" msgstr "" #: .././repair/dinode.c:2453 #, c-format msgid "bad inode format in inode %\n" msgstr "" #: .././repair/dinode.c:2469 #, c-format msgid "Bad flags set in inode %\n" msgstr "" #: .././repair/dinode.c:2480 #, c-format msgid "inode % has RT flag set but there is no RT device\n" msgstr "" #: .././repair/dinode.c:2492 #, c-format msgid "inode % not rt bitmap\n" msgstr "" #: .././repair/dinode.c:2506 #, c-format msgid "directory flags set on non-directory inode %\n" msgstr "" #: .././repair/dinode.c:2520 #, c-format msgid "file flags set on non-file inode %\n" msgstr "" #: .././repair/dinode.c:2529 msgid "fixing bad flags.\n" msgstr "" #: .././repair/dinode.c:2533 msgid "would fix bad flags.\n" msgstr "" #: .././repair/dinode.c:2548 #, c-format msgid "Bad flags2 set in inode %\n" msgstr "" #: .././repair/dinode.c:2559 #, c-format msgid "DAX flag set on special inode %\n" msgstr "" #: .././repair/dinode.c:2570 #, c-format msgid "" "inode % is marked reflinked but file system does not support " "reflink\n" msgstr "" #: .././repair/dinode.c:2581 #, c-format msgid "reflink flag set on non-file inode %\n" msgstr "" #: .././repair/dinode.c:2592 #, c-format msgid "Cannot have a reflinked realtime inode %\n" msgstr "" #: .././repair/dinode.c:2602 #, c-format msgid "" "inode % has CoW extent size hint but file system does not support " "reflink\n" msgstr "" #: .././repair/dinode.c:2613 #, c-format msgid "CoW extent size flag set on non-file, non-directory inode %\n" msgstr "" #: .././repair/dinode.c:2624 #, c-format msgid "Cannot have CoW extent size hint on a realtime inode %\n" msgstr "" #: .././repair/dinode.c:2632 msgid "fixing bad flags2.\n" msgstr "" #: .././repair/dinode.c:2636 msgid "would fix bad flags2.\n" msgstr "" #: .././repair/dinode.c:2654 #, c-format msgid "Would clear next_unlinked in inode %\n" msgstr "" #: .././repair/dinode.c:2658 #, c-format msgid "Cleared next_unlinked in inode %\n" msgstr "" #: .././repair/dinode.c:2702 #, c-format msgid "bad inode type %#o inode %\n" msgstr "" #: .././repair/dinode.c:2722 #, c-format msgid "Bad extent size %u on inode %, " msgstr "" #: .././repair/dinode.c:2745 #, c-format msgid "Bad CoW extent size %u on inode %, " msgstr "" #: .././repair/dinode.c:2818 #, c-format msgid "problem with directory contents in inode %\n" msgstr "" #: .././repair/dinode.c:2826 #, c-format msgid "problem with symbolic link in inode %\n" msgstr "" #: .././repair/dinode.c:2836 #, c-format msgid "problem with quota inode %\n" msgstr "" #: .././repair/dinode.c:2930 #, c-format msgid "processing inode %d/%d\n" msgstr "" #: .././repair/attr_repair.c:57 #, c-format msgid "bad range claimed [%d, %d) in da block\n" msgstr "" #: .././repair/attr_repair.c:64 #, c-format msgid "byte range end [%d %d) in da block larger than blocksize %d\n" msgstr "" #: .././repair/attr_repair.c:71 #, c-format msgid "multiply claimed byte %d in da block\n" msgstr "" #: .././repair/attr_repair.c:151 msgid "No memory for ACL check!\n" msgstr "" #: .././repair/attr_repair.c:159 msgid "" "entry contains illegal value in attribute named SGI_ACL_FILE or " "SGI_ACL_DEFAULT\n" msgstr "" #: .././repair/attr_repair.c:185 msgid "entry contains illegal value in attribute named SGI_MAC_LABEL\n" msgstr "" #: .././repair/attr_repair.c:191 msgid "entry contains illegal value in attribute named SGI_CAP_FILE\n" msgstr "" #: .././repair/attr_repair.c:231 #, c-format msgid "there are no attributes in the fork for inode %\n" msgstr "" #: .././repair/attr_repair.c:239 #, c-format msgid "would junk the attribute fork since count is 0 for inode %\n" msgstr "" #: .././repair/attr_repair.c:259 msgid "zero length name entry in attribute fork," msgstr "" #: .././repair/attr_repair.c:262 .././repair/attr_repair.c:282 #, c-format msgid " truncating attributes for inode % to %d\n" msgstr "" #: .././repair/attr_repair.c:267 .././repair/attr_repair.c:288 #, c-format msgid " would truncate attributes for inode % to %d\n" msgstr "" #: .././repair/attr_repair.c:279 msgid "name or value attribute lengths are too large,\n" msgstr "" #: .././repair/attr_repair.c:299 msgid "entry contains illegal character in shortform attribute name\n" msgstr "" #: .././repair/attr_repair.c:305 msgid "entry has INCOMPLETE flag on in shortform attribute\n" msgstr "" #: .././repair/attr_repair.c:323 #, c-format msgid "removing attribute entry %d for inode %\n" msgstr "" #: .././repair/attr_repair.c:335 #, c-format msgid "would remove attribute entry %d for inode %\n" msgstr "" #: .././repair/attr_repair.c:350 #, c-format msgid "" "would have corrected attribute entry count in inode % from %d to %d\n" msgstr "" #: .././repair/attr_repair.c:354 #, c-format msgid "corrected attribute entry count in inode %, was %d, now %d\n" msgstr "" #: .././repair/attr_repair.c:365 #, c-format msgid "" "would have corrected attribute totsize in inode % from %d to %d\n" msgstr "" #: .././repair/attr_repair.c:370 #, c-format msgid "corrected attribute entry totsize in inode %, was %d, now %d\n" msgstr "" #: .././repair/attr_repair.c:404 #, c-format msgid "remote block for attributes of inode % is missing\n" msgstr "" #: .././repair/attr_repair.c:413 #, c-format msgid "can't read remote block for attributes of inode %\n" msgstr "" #: .././repair/attr_repair.c:420 #, c-format msgid "Corrupt remote block for attributes of inode %\n" msgstr "" #: .././repair/attr_repair.c:463 #, c-format msgid "" "attribute entry %d in attr block %u, inode % has bad name (namelen = " "%d)\n" msgstr "" #: .././repair/attr_repair.c:480 #, c-format msgid "" "bad hashvalue for attribute entry %d in attr block %u, inode %\n" msgstr "" #: .././repair/attr_repair.c:490 #, c-format msgid "" "bad security value for attribute entry %d in attr block %u, inode %\n" msgstr "" #: .././repair/attr_repair.c:524 #, c-format msgid "" "inconsistent remote attribute entry %d in attr block %u, ino %\n" msgstr "" #: .././repair/attr_repair.c:531 #, c-format msgid "cannot malloc enough for remotevalue attribute for inode %\n" msgstr "" #: .././repair/attr_repair.c:533 msgid "SKIPPING this remote attribute\n" msgstr "" #: .././repair/attr_repair.c:539 #, c-format msgid "remote attribute get failed for entry %d, inode %\n" msgstr "" #: .././repair/attr_repair.c:547 #, c-format msgid "remote attribute value check failed for entry %d, inode %\n" msgstr "" #: .././repair/attr_repair.c:586 #, c-format msgid "bad attribute count %d in attr block %u, inode %\n" msgstr "" #: .././repair/attr_repair.c:601 #, c-format msgid "bad attribute nameidx %d in attr block %u, inode %\n" msgstr "" #: .././repair/attr_repair.c:610 #, c-format msgid "attribute entry #%d in attr block %u, inode % is INCOMPLETE\n" msgstr "" #: .././repair/attr_repair.c:621 #, c-format msgid "" "attribute entry %d in attr block %u, inode % claims already used " "space\n" msgstr "" #: .././repair/attr_repair.c:644 #, c-format msgid "" "attribute entry %d in attr block %u, inode % claims used space\n" msgstr "" #: .././repair/attr_repair.c:668 #, c-format msgid "" "- resetting first used heap value from %d to %d in block %u of attribute " "fork of inode %\n" msgstr "" #: .././repair/attr_repair.c:676 #, c-format msgid "" "- would reset first used value from %d to %d in block %u of attribute fork " "of inode %\n" msgstr "" #: .././repair/attr_repair.c:686 #, c-format msgid "" "- resetting usedbytes cnt from %d to %d in block %u of attribute fork of " "inode %\n" msgstr "" #: .././repair/attr_repair.c:694 #, c-format msgid "" "- would reset usedbytes cnt from %d to %d in block %u of attribute fork of " "%\n" msgstr "" #: .././repair/attr_repair.c:749 #, c-format msgid "btree cycle detected in attribute fork for inode %\n" msgstr "" #: .././repair/attr_repair.c:761 #, c-format msgid "can't map block %u for attribute fork for inode %\n" msgstr "" #: .././repair/attr_repair.c:771 #, c-format msgid "" "can't read file block %u (fsbno %) for attribute fork of inode " "%\n" msgstr "" #: .././repair/attr_repair.c:783 #, c-format msgid "bad attribute leaf magic %#x for inode %\n" msgstr "" #: .././repair/attr_repair.c:814 #, c-format msgid "" "bad sibling back pointer for block %u in attribute fork for inode %\n" msgstr "" #: .././repair/attr_repair.c:849 #, c-format msgid "bad hash path in attribute fork for inode %\n" msgstr "" #: .././repair/attr_repair.c:931 #, c-format msgid "expected owner inode %, got %llu, attr block %\n" msgstr "" #: .././repair/attr_repair.c:939 #, c-format msgid "expected block %, got %llu, inode %attr block\n" msgstr "" #: .././repair/attr_repair.c:947 #, c-format msgid "wrong FS UUID, inode % attr block %\n" msgstr "" #: .././repair/attr_repair.c:989 #, c-format msgid "block 0 of inode % attribute fork is missing\n" msgstr "" #: .././repair/attr_repair.c:996 #, c-format msgid "agno of attribute fork of inode % out of regular partition\n" msgstr "" #: .././repair/attr_repair.c:1004 #, c-format msgid "can't read block 0 of inode % attribute fork\n" msgstr "" #: .././repair/attr_repair.c:1028 #, c-format msgid "" "clearing forw/back pointers in block 0 for attributes in inode %\n" msgstr "" #: .././repair/attr_repair.c:1037 #, c-format msgid "" "would clear forw/back pointers in block 0 for attributes in inode %\n" msgstr "" #: .././repair/attr_repair.c:1073 #, c-format msgid "bad attribute leaf magic # %#x for dir ino %\n" msgstr "" #: .././repair/attr_repair.c:1103 #, c-format msgid "Too many ACL entries, count %d\n" msgstr "" #: .././repair/attr_repair.c:1112 msgid "cannot malloc enough for ACL attribute\n" msgstr "" #: .././repair/attr_repair.c:1113 msgid "SKIPPING this ACL\n" msgstr "" #: .././repair/incore_ext.c:123 .././repair/incore_ext.c:542 msgid "couldn't allocate new extent descriptor.\n" msgstr "" #: .././repair/incore_ext.c:220 msgid "duplicate bno extent range\n" msgstr "" #: .././repair/incore_ext.c:349 msgid ": duplicate bno extent range\n" msgstr "" #: .././repair/incore_ext.c:624 .././repair/incore_ext.c:679 msgid "duplicate extent range\n" msgstr "" #: .././repair/incore_ext.c:732 .././repair/incore_ext.c:736 msgid "couldn't malloc dup extent tree descriptor table\n" msgstr "" #: .././repair/incore_ext.c:741 msgid "couldn't malloc free by-bno extent tree descriptor table\n" msgstr "" #: .././repair/incore_ext.c:746 msgid "couldn't malloc free by-bcnt extent tree descriptor table\n" msgstr "" #: .././repair/incore_ext.c:752 msgid "couldn't malloc bno extent tree descriptor\n" msgstr "" #: .././repair/incore_ext.c:756 msgid "couldn't malloc bcnt extent tree descriptor\n" msgstr "" #: .././repair/incore_ext.c:767 msgid "couldn't malloc dup rt extent tree descriptor\n" msgstr "" #: .././repair/prefetch.c:240 .././repair/da_util.c:56 msgid "couldn't malloc dir2 buffer list\n" msgstr "" #: .././repair/prefetch.c:545 msgid "prefetch corruption\n" msgstr "" #: .././repair/prefetch.c:726 .././repair/prefetch.c:849 #, c-format msgid "failed to create prefetch thread: %s\n" msgstr "" #: .././repair/prefetch.c:890 msgid "failed to initialize prefetch mutex\n" msgstr "" #: .././repair/prefetch.c:892 .././repair/prefetch.c:894 msgid "failed to initialize prefetch cond var\n" msgstr "" #: .././repair/xfs_repair.c:78 #, c-format msgid "" "Usage: %s [options] device\n" "\n" "Options:\n" " -f The device is a file\n" " -L Force log zeroing. Do this as a last resort.\n" " -l logdev Specifies the device where the external log resides.\n" " -m maxmem Maximum amount of memory to be used in megabytes.\n" " -n No modify mode, just checks the filesystem for damage.\n" " (Cannot be used together with -e.)\n" " -P Disables prefetching.\n" " -r rtdev Specifies the device where the realtime section resides.\n" " -v Verbose output.\n" " -c subopts Change filesystem parameters - use xfs_admin.\n" " -o subopts Override default behaviour, refer to man page.\n" " -t interval Reporting interval in seconds.\n" " -d Repair dangerously.\n" " -e Exit with a non-zero code if any errors were repaired.\n" " (Cannot be used together with -n.)\n" " -V Reports version and exits.\n" msgstr "" #: .././repair/xfs_repair.c:107 msgid "no error" msgstr "" #: .././repair/xfs_repair.c:108 msgid "bad magic number" msgstr "" #: .././repair/xfs_repair.c:109 msgid "bad blocksize field" msgstr "" #: .././repair/xfs_repair.c:110 msgid "bad blocksize log field" msgstr "" #: .././repair/xfs_repair.c:111 msgid "bad or unsupported version" msgstr "" #: .././repair/xfs_repair.c:113 msgid "filesystem mkfs-in-progress bit set" msgstr "" #: .././repair/xfs_repair.c:115 msgid "inconsistent filesystem geometry information" msgstr "" #: .././repair/xfs_repair.c:117 msgid "bad inode size or inconsistent with number of inodes/block" msgstr "" #: .././repair/xfs_repair.c:118 msgid "bad sector size" msgstr "" #: .././repair/xfs_repair.c:120 msgid "AGF geometry info conflicts with filesystem geometry" msgstr "" #: .././repair/xfs_repair.c:122 msgid "AGI geometry info conflicts with filesystem geometry" msgstr "" #: .././repair/xfs_repair.c:124 msgid "AG superblock geometry info conflicts with filesystem geometry" msgstr "" #: .././repair/xfs_repair.c:125 msgid "attempted to perform I/O beyond EOF" msgstr "" #: .././repair/xfs_repair.c:127 msgid "inconsistent filesystem geometry in realtime filesystem component" msgstr "" #: .././repair/xfs_repair.c:129 msgid "maximum indicated percentage of inodes > 100%" msgstr "" #: .././repair/xfs_repair.c:131 msgid "inconsistent inode alignment value" msgstr "" #: .././repair/xfs_repair.c:133 msgid "not enough secondary superblocks with matching geometry" msgstr "" #: .././repair/xfs_repair.c:135 msgid "bad stripe unit in superblock" msgstr "" #: .././repair/xfs_repair.c:137 msgid "bad stripe width in superblock" msgstr "" #: .././repair/xfs_repair.c:139 msgid "bad shared version number in superblock" msgstr "" #: .././repair/xfs_repair.c:141 msgid "bad CRC in superblock" msgstr "" #: .././repair/xfs_repair.c:143 msgid "inconsistent directory geometry information" msgstr "" #: .././repair/xfs_repair.c:145 msgid "inconsistent log geometry information" msgstr "" #: .././repair/xfs_repair.c:150 #, c-format msgid "bad error code - %d\n" msgstr "" #: .././repair/xfs_repair.c:158 #, c-format msgid "-%c %s option cannot have a value\n" msgstr "" #: .././repair/xfs_repair.c:232 msgid "-o ihash option has been removed and will be ignored\n" msgstr "" #: .././repair/xfs_repair.c:237 msgid "-o bhash option cannot be used with -m option\n" msgstr "" #: .././repair/xfs_repair.c:240 msgid "-o bhash requires a parameter\n" msgstr "" #: .././repair/xfs_repair.c:247 msgid "-o ag_stride requires a parameter\n" msgstr "" #: .././repair/xfs_repair.c:260 msgid "-o phase2_threads requires a parameter\n" msgstr "" #: .././repair/xfs_repair.c:278 msgid "-c lazycount requires a parameter\n" msgstr "" #: .././repair/xfs_repair.c:301 msgid "-m option cannot be used with -o bhash option\n" msgstr "" #: .././repair/xfs_repair.c:349 #, c-format msgid "" "\n" "fatal error -- " msgstr "" #: .././repair/xfs_repair.c:475 #, c-format msgid "sb root inode value % %sinconsistent with calculated value %u\n" msgstr "" #: .././repair/xfs_repair.c:482 #, c-format msgid "resetting superblock root inode pointer to %u\n" msgstr "" #: .././repair/xfs_repair.c:486 #, c-format msgid "would reset superblock root inode pointer to %u\n" msgstr "" #: .././repair/xfs_repair.c:498 #, c-format msgid "" "sb realtime bitmap inode % %sinconsistent with calculated value %u\n" msgstr "" #: .././repair/xfs_repair.c:505 #, c-format msgid "resetting superblock realtime bitmap ino pointer to %u\n" msgstr "" #: .././repair/xfs_repair.c:509 #, c-format msgid "would reset superblock realtime bitmap ino pointer to %u\n" msgstr "" #: .././repair/xfs_repair.c:521 #, c-format msgid "" "sb realtime summary inode % %sinconsistent with calculated value %u\n" msgstr "" #: .././repair/xfs_repair.c:528 #, c-format msgid "resetting superblock realtime summary ino pointer to %u\n" msgstr "" #: .././repair/xfs_repair.c:532 #, c-format msgid "would reset superblock realtime summary ino pointer to %u\n" msgstr "" #: .././repair/xfs_repair.c:588 #, c-format msgid "Maximum metadata LSN (%d:%d) is ahead of log (%d:%d).\n" msgstr "" #: .././repair/xfs_repair.c:592 #, c-format msgid "Would format log to cycle %d.\n" msgstr "" #: .././repair/xfs_repair.c:596 #, c-format msgid "Format log to cycle %d.\n" msgstr "" #: .././repair/xfs_repair.c:647 msgid "" "Cannot get host filesystem geometry.\n" "Repair may fail if there is a sector size mismatch between\n" "the image and the host filesystem.\n" msgstr "" #: .././repair/xfs_repair.c:657 msgid "" "Sector size on host filesystem larger than image sector size.\n" "Cannot turn off direct IO, so exiting.\n" msgstr "" #: .././repair/xfs_repair.c:701 #, c-format msgid "%s: couldn't stat \"%s\"\n" msgstr "" #: .././repair/xfs_repair.c:719 msgid "" "Primary superblock would have been modified.\n" "Cannot proceed further in no_modify mode.\n" "Exiting now.\n" msgstr "" #: .././repair/xfs_repair.c:727 msgid "" "Primary superblock bad after phase 1!\n" "Exiting now.\n" msgstr "" #: .././repair/xfs_repair.c:749 #, c-format msgid "%s: cannot repair this filesystem. Sorry.\n" msgstr "" #: .././repair/xfs_repair.c:824 #, c-format msgid " - reporting progress in intervals of %s\n" msgstr "" #: .././repair/xfs_repair.c:869 #, c-format msgid "" " - max_mem = %lu, icount = %, imem = %, dblock = " "%, dmem = %\n" msgstr "" #: .././repair/xfs_repair.c:878 #, c-format msgid "" "Required memory for repair is greater that the maximum specified\n" "with the -m option. Please increase it to at least %lu.\n" msgstr "" #: .././repair/xfs_repair.c:883 #, c-format msgid "" "Memory available for repair (%luMB) may not be sufficient.\n" "At least %luMB is needed to repair this filesystem efficiently\n" "If repair fails due to lack of memory, please\n" msgstr "" #: .././repair/xfs_repair.c:889 msgid "turn prefetching off (-P) to reduce the memory footprint.\n" msgstr "" #: .././repair/xfs_repair.c:892 #, c-format msgid "increase system RAM and/or swap space to at least %luMB.\n" msgstr "" #: .././repair/xfs_repair.c:907 #, c-format msgid " - block cache size set to %d entries\n" msgstr "" #: .././repair/xfs_repair.c:932 msgid "Found unsupported filesystem features. Exiting now.\n" msgstr "" #: .././repair/xfs_repair.c:950 #, c-format msgid "No modify flag set, skipping phase 5\n" msgstr "" #: .././repair/xfs_repair.c:970 msgid "Inode allocation btrees are too corrupted, skipping phases 6 and 7\n" msgstr "" #: .././repair/xfs_repair.c:976 msgid "Warning: no quota inodes were found. Quotas disabled.\n" msgstr "" #: .././repair/xfs_repair.c:979 msgid "Warning: no quota inodes were found. Quotas would be disabled.\n" msgstr "" #: .././repair/xfs_repair.c:984 msgid "Warning: quota inodes were cleared. Quotas disabled.\n" msgstr "" #: .././repair/xfs_repair.c:987 msgid "Warning: quota inodes would be cleared. Quotas would be disabled.\n" msgstr "" #: .././repair/xfs_repair.c:993 msgid "" "Warning: user quota information was cleared.\n" "User quotas can not be enforced until limit information is recreated.\n" msgstr "" #: .././repair/xfs_repair.c:997 msgid "" "Warning: user quota information would be cleared.\n" "User quotas could not be enforced until limit information was recreated.\n" msgstr "" #: .././repair/xfs_repair.c:1005 msgid "" "Warning: group quota information was cleared.\n" "Group quotas can not be enforced until limit information is recreated.\n" msgstr "" #: .././repair/xfs_repair.c:1009 msgid "" "Warning: group quota information would be cleared.\n" "Group quotas could not be enforced until limit information was recreated.\n" msgstr "" #: .././repair/xfs_repair.c:1017 msgid "" "Warning: project quota information was cleared.\n" "Project quotas can not be enforced until limit information is recreated.\n" msgstr "" #: .././repair/xfs_repair.c:1021 msgid "" "Warning: project quota information would be cleared.\n" "Project quotas could not be enforced until limit information was recreated.\n" msgstr "" #: .././repair/xfs_repair.c:1038 msgid "No modify flag set, skipping filesystem flush and exiting.\n" msgstr "" #: .././repair/xfs_repair.c:1052 .././repair/phase5.c:2182 msgid "couldn't get superblock\n" msgstr "" #: .././repair/xfs_repair.c:1057 msgid "Note - quota info will be regenerated on next quota mount.\n" msgstr "" #: .././repair/xfs_repair.c:1064 #, c-format msgid "" "Note - stripe unit (%d) and width (%d) were copied from a backup " "superblock.\n" "Please reset with mount -o sunit=,swidth= if necessary\n" msgstr "" #: .././repair/xfs_repair.c:1089 msgid "done\n" msgstr "" #: .././repair/xfs_repair.c:1093 msgid "Repair of readonly mount complete. Immediate reboot encouraged.\n" msgstr "" #: .././repair/phase2.c:65 #, c-format msgid "zero_log: cannot find log head/tail (xlog_find_tail=%d)\n" msgstr "" #: .././repair/phase2.c:69 msgid "" "ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n" "filesystem to replay the log or use the -L option to destroy the log and\n" "attempt a repair.\n" msgstr "" #: .././repair/phase2.c:77 #, c-format msgid "zero_log: head block % tail block %\n" msgstr "" #: .././repair/phase2.c:83 msgid "" "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "destroyed because the -L option was used.\n" msgstr "" #: .././repair/phase2.c:87 msgid "" "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "ignored because the -n option was used. Expect spurious inconsistencies\n" "which may be resolved by first mounting the filesystem to replay the log.\n" msgstr "" #: .././repair/phase2.c:92 msgid "" "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running xfs_repair. If you are unable to mount the filesystem, then use\n" "the -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n" msgstr "" #: .././repair/phase2.c:120 msgid "failed to clear log" msgstr "" #: .././repair/phase2.c:154 msgid "" "This filesystem has an external log. Specify log device with the -l " "option.\n" msgstr "" #: .././repair/phase2.c:157 #, c-format msgid "Phase 2 - using external log on %s\n" msgstr "" #: .././repair/phase2.c:159 msgid "Phase 2 - using internal log\n" msgstr "" #: .././repair/phase2.c:162 msgid " - zero log...\n" msgstr "" #: .././repair/phase2.c:165 msgid " - scan filesystem freespace and inode maps...\n" msgstr "" #: .././repair/phase2.c:181 msgid "root inode chunk not found\n" msgstr "" #: .././repair/phase2.c:200 msgid " - found root inode chunk\n" msgstr "" #: .././repair/phase2.c:206 msgid "root inode marked free, " msgstr "" #: .././repair/phase2.c:215 msgid "realtime bitmap inode marked free, " msgstr "" #: .././repair/phase2.c:224 msgid "realtime summary inode marked free, " msgstr "" #: .././repair/phase5.c:211 msgid "could not set up btree block array\n" msgstr "" #: .././repair/phase5.c:232 msgid "error - not enough free space in filesystem\n" msgstr "" #: .././repair/phase5.c:247 #, c-format msgid "could not set up btree rmaps: %s\n" msgstr "" #: .././repair/phase5.c:463 #, c-format msgid "can't rebuild fs trees -- not enough free space on ag %u\n" msgstr "" #: .././repair/phase5.c:486 #, c-format msgid "ag %u - not enough free space to build freespace btrees\n" msgstr "" #: .././repair/phase5.c:521 #, c-format msgid "not enough free blocks left to describe all free blocks in AG %u\n" msgstr "" #: .././repair/phase5.c:1602 msgid "Insufficient memory to construct reverse-map cursor." msgstr "" #: .././repair/phase5.c:1907 msgid "Insufficient memory to construct refcount cursor." msgstr "" #: .././repair/phase5.c:2119 .././repair/phase5.c:2127 msgid "Insufficient memory saving lost blocks.\n" msgstr "" #: .././repair/phase5.c:2238 .././repair/phase3.c:66 .././repair/phase4.c:130 #: .././repair/phase6.c:3197 #, c-format msgid " - agno = %d\n" msgstr "" #: .././repair/phase5.c:2261 #, c-format msgid "unable to rebuild AG %u. Not enough free space in on-disk AG.\n" msgstr "" #: .././repair/phase5.c:2313 #, c-format msgid "unable to rebuild AG %u. No free space.\n" msgstr "" #: .././repair/phase5.c:2483 msgid "Phase 5 - rebuild AG headers and trees...\n" msgstr "" #: .././repair/phase5.c:2512 msgid "cannot alloc sb_icount_ag buffers\n" msgstr "" #: .././repair/phase5.c:2516 msgid "cannot alloc sb_ifree_ag buffers\n" msgstr "" #: .././repair/phase5.c:2520 msgid "cannot alloc sb_fdblocks_ag buffers\n" msgstr "" #: .././repair/phase5.c:2524 msgid "cannot alloc lost block slab\n" msgstr "" #: .././repair/phase5.c:2543 msgid " - generate realtime summary info and bitmap...\n" msgstr "" #: .././repair/phase5.c:2548 msgid " - reset superblock...\n" msgstr "" #: .././repair/phase5.c:2563 #, c-format msgid "unable to add AG %u reverse-mapping data to btree.\n" msgstr "" #: .././repair/phase5.c:2572 msgid "Unable to reinsert lost blocks into filesystem.\n" msgstr "" #: .././repair/agheader.c:28 #, c-format msgid "bad magic # 0x%x for agf %d\n" msgstr "" #: .././repair/agheader.c:37 #, c-format msgid "bad version # %d for agf %d\n" msgstr "" #: .././repair/agheader.c:46 #, c-format msgid "bad sequence # %d for agf %d\n" msgstr "" #: .././repair/agheader.c:56 #, c-format msgid "bad length %d for agf %d, should be %d\n" msgstr "" #: .././repair/agheader.c:69 #, c-format msgid "bad length %d for agf %d, should be %\n" msgstr "" #: .././repair/agheader.c:83 #, c-format msgid "flfirst %d in agf %d too large (max = %u)\n" msgstr "" #: .././repair/agheader.c:91 #, c-format msgid "fllast %d in agf %d too large (max = %u)\n" msgstr "" #: .././repair/agheader.c:108 #, c-format msgid "bad uuid %s for agf %d\n" msgstr "" #: .././repair/agheader.c:127 #, c-format msgid "bad magic # 0x%x for agi %d\n" msgstr "" #: .././repair/agheader.c:136 #, c-format msgid "bad version # %d for agi %d\n" msgstr "" #: .././repair/agheader.c:145 #, c-format msgid "bad sequence # %d for agi %d\n" msgstr "" #: .././repair/agheader.c:155 #, c-format msgid "bad length # %d for agi %d, should be %d\n" msgstr "" #: .././repair/agheader.c:168 #, c-format msgid "bad length # %d for agi %d, should be %\n" msgstr "" #: .././repair/agheader.c:187 #, c-format msgid "bad uuid %s for agi %d\n" msgstr "" #: .././repair/agheader.c:293 #, c-format msgid "zeroing unused portion of %s superblock (AG #%u)\n" msgstr "" #: .././repair/agheader.c:294 .././repair/agheader.c:312 msgid "primary" msgstr "" #: .././repair/agheader.c:294 .././repair/agheader.c:312 msgid "secondary" msgstr "" #: .././repair/agheader.c:311 #, c-format msgid "would zero unused portion of %s superblock (AG #%u)\n" msgstr "" #: .././repair/agheader.c:329 #, c-format msgid "bad flags field in superblock %d\n" msgstr "" #: .././repair/agheader.c:352 #, c-format msgid "non-null user quota inode field in superblock %d\n" msgstr "" #: .././repair/agheader.c:367 #, c-format msgid "non-null group quota inode field in superblock %d\n" msgstr "" #: .././repair/agheader.c:388 #, c-format msgid "non-null project quota inode field in superblock %d\n" msgstr "" #: .././repair/agheader.c:400 #, c-format msgid "non-null quota flags in superblock %d\n" msgstr "" #: .././repair/agheader.c:418 #, c-format msgid "bad inode alignment field in superblock %d\n" msgstr "" #: .././repair/agheader.c:431 #, c-format msgid "bad stripe unit/width fields in superblock %d\n" msgstr "" #: .././repair/agheader.c:449 #, c-format msgid "bad log/data device sector size fields in superblock %d\n" msgstr "" #: .././repair/agheader.c:480 #, c-format msgid "bad on-disk superblock %d - %s\n" msgstr "" #: .././repair/agheader.c:487 #, c-format msgid "primary/secondary superblock %d conflict - %s\n" msgstr "" #: .././repair/avl.c:999 .././libfrog/avl64.c:1020 #, c-format msgid "avl_insert: Warning! duplicate range [%llu,%llu]\n" msgstr "" #: .././repair/avl.c:1194 .././libfrog/avl64.c:1215 #, c-format msgid "Command [fpdir] : " msgstr "" #: .././repair/avl.c:1203 .././libfrog/avl64.c:1224 #, c-format msgid "end of range ? " msgstr "" #: .././repair/avl.c:1214 .././libfrog/avl64.c:1235 #, c-format msgid "Cannot find %d\n" msgstr "" #: .././repair/avl.c:1227 .././libfrog/avl64.c:1248 #, c-format msgid "size of range ? " msgstr "" #: .././repair/avl.c:1238 .././libfrog/avl64.c:1259 #, c-format msgid "End of range ? " msgstr "" #: .././repair/avl.c:1242 .././libfrog/avl64.c:1263 #, c-format msgid "checklen 0/1 ? " msgstr "" #: .././repair/avl.c:1249 .././libfrog/avl64.c:1270 #, c-format msgid "Found something\n" msgstr "" #: .././repair/incore_ino.c:35 msgid "could not allocate nlink array\n" msgstr "" #: .././repair/incore_ino.c:213 msgid "could not allocate ftypes array\n" msgstr "" #: .././repair/incore_ino.c:239 msgid "inode map malloc failed\n" msgstr "" #: .././repair/incore_ino.c:355 msgid "add_aginode_uncertain - duplicate inode range\n" msgstr "" #: .././repair/incore_ino.c:450 msgid "add_inode - duplicate inode range\n" msgstr "" #: .././repair/incore_ino.c:544 #, c-format msgid "good inode list is --\n" msgstr "" #: .././repair/incore_ino.c:547 #, c-format msgid "uncertain inode list is --\n" msgstr "" #: .././repair/incore_ino.c:552 #, c-format msgid "agno %d -- no inodes\n" msgstr "" #: .././repair/incore_ino.c:556 #, c-format msgid "agno %d\n" msgstr "" #: .././repair/incore_ino.c:560 #, c-format msgid "\tptr = %lx, start = 0x%x, free = 0x%llx, confirmed = 0x%llx\n" msgstr "" #: .././repair/incore_ino.c:611 msgid "couldn't malloc parent list table\n" msgstr "" #: .././repair/incore_ino.c:622 .././repair/incore_ino.c:668 msgid "couldn't memalign pentries table\n" msgstr "" #: .././repair/incore_ino.c:726 msgid "could not malloc inode extra data\n" msgstr "" #: .././repair/incore_ino.c:792 msgid "couldn't malloc inode tree descriptor table\n" msgstr "" #: .././repair/incore_ino.c:796 msgid "couldn't malloc uncertain ino tree descriptor table\n" msgstr "" #: .././repair/incore_ino.c:801 msgid "couldn't malloc inode tree descriptor\n" msgstr "" #: .././repair/incore_ino.c:805 msgid "couldn't malloc uncertain ino tree descriptor\n" msgstr "" #: .././repair/incore_ino.c:813 msgid "couldn't malloc uncertain inode cache area\n" msgstr "" #: .././repair/phase1.c:16 msgid "Sorry, could not find valid secondary superblock\n" msgstr "" #: .././repair/phase1.c:17 msgid "Exiting now.\n" msgstr "" #: .././repair/phase1.c:28 #, c-format msgid "could not allocate ag header buffer (%d bytes)\n" msgstr "" #: .././repair/phase1.c:46 msgid "Phase 1 - find and verify superblock...\n" msgstr "" #: .././repair/phase1.c:63 msgid "error reading primary superblock\n" msgstr "" #: .././repair/phase1.c:69 #, c-format msgid "bad primary superblock - %s !!!\n" msgstr "" #: .././repair/phase1.c:76 #, c-format msgid "couldn't verify primary superblock - %s !!!\n" msgstr "" #: .././repair/phase1.c:94 msgid "superblock has a features2 mismatch, correcting\n" msgstr "" #: .././repair/phase1.c:111 #, c-format msgid "Enabling lazy-counters\n" msgstr "" #: .././repair/phase1.c:115 #, c-format msgid "Cannot disable lazy-counters on V5 fs\n" msgstr "" #: .././repair/phase1.c:120 #, c-format msgid "Disabling lazy-counters\n" msgstr "" #: .././repair/phase1.c:123 #, c-format msgid "Lazy-counters are already %s\n" msgstr "" #: .././repair/phase1.c:124 msgid "enabled" msgstr "" #: .././repair/phase1.c:124 msgid "disabled" msgstr "" #: .././repair/phase1.c:131 msgid "resetting shared_vn to zero\n" msgstr "" #: .././repair/phase1.c:138 msgid "writing modified primary superblock\n" msgstr "" #: .././repair/phase1.c:141 msgid "would write modified primary superblock\n" msgstr "" #: .././repair/phase3.c:35 #, c-format msgid "cannot read agi block % for ag %u\n" msgstr "" #: .././repair/phase3.c:107 msgid "Phase 3 - for each AG...\n" msgstr "" #: .././repair/phase3.c:109 msgid " - scan and clear agi unlinked lists...\n" msgstr "" #: .././repair/phase3.c:111 msgid " - scan (but don't clear) agi unlinked lists...\n" msgstr "" #: .././repair/phase3.c:131 msgid " - process known inodes and perform inode discovery...\n" msgstr "" #: .././repair/phase3.c:142 msgid " - process newly discovered inodes...\n" msgstr "" #: .././repair/phase3.c:147 msgid "no memory for uncertain inode counts\n" msgstr "" #: .././repair/phase4.c:153 #, c-format msgid "" "unable to finish adding attr/data fork reverse-mapping data for AG %u.\n" msgstr "" #: .././repair/phase4.c:169 #, c-format msgid "unable to add AG %u metadata reverse-mapping data.\n" msgstr "" #: .././repair/phase4.c:174 #, c-format msgid "unable to merge AG %u metadata reverse-mapping data.\n" msgstr "" #: .././repair/phase4.c:179 #, c-format msgid "%s while checking reverse-mappings" msgstr "" #: .././repair/phase4.c:194 #, c-format msgid "%s while computing reference count records.\n" msgstr "" #: .././repair/phase4.c:209 #, c-format msgid "%s while fixing inode reflink flags.\n" msgstr "" #: .././repair/phase4.c:224 #, c-format msgid "%s while checking reference counts" msgstr "" #: .././repair/phase4.c:278 msgid "Phase 4 - check for duplicate blocks...\n" msgstr "" #: .././repair/phase4.c:279 msgid " - setting up duplicate extent list...\n" msgstr "" #: .././repair/phase4.c:293 msgid "root inode would be lost\n" msgstr "" #: .././repair/phase4.c:295 msgid "root inode lost\n" msgstr "" #: .././repair/phase4.c:312 #, c-format msgid "unknown block state, ag %d, block %d\n" msgstr "" #: .././repair/phase4.c:345 #, c-format msgid "unknown rt extent state, extent %\n" msgstr "" #: .././repair/phase4.c:394 msgid " - check for inodes claiming duplicate blocks...\n" msgstr "" #: .././repair/phase6.c:107 #, c-format msgid "malloc failed add_dotdot_update (%zu bytes)\n" msgstr "" #: .././repair/phase6.c:259 #, c-format msgid "malloc failed in dir_hash_add (%zu bytes)\n" msgstr "" #: .././repair/phase6.c:313 .././spaceman/health.c:182 msgid "ok" msgstr "" #: .././repair/phase6.c:314 msgid "duplicate leaf" msgstr "" #: .././repair/phase6.c:315 msgid "hash value mismatch" msgstr "" #: .././repair/phase6.c:316 msgid "no data entry" msgstr "" #: .././repair/phase6.c:317 msgid "no leaf entry" msgstr "" #: .././repair/phase6.c:318 msgid "bad stale count" msgstr "" #: .././repair/phase6.c:326 #, c-format msgid "bad hash table for directory inode % (%s): " msgstr "" #: .././repair/phase6.c:329 msgid "rebuilding\n" msgstr "" #: .././repair/phase6.c:331 msgid "would rebuild\n" msgstr "" #: .././repair/phase6.c:367 msgid "calloc failed in dir_hash_init\n" msgstr "" #: .././repair/phase6.c:511 msgid "ran out of disk space!\n" msgstr "" #: .././repair/phase6.c:513 #, c-format msgid "xfs_trans_reserve returned %d\n" msgstr "" #: .././repair/phase6.c:542 .././repair/phase6.c:643 #, c-format msgid "couldn't iget realtime bitmap inode -- error - %d\n" msgstr "" #: .././repair/phase6.c:580 .././repair/phase6.c:684 .././repair/phase6.c:756 #: .././repair/phase6.c:826 .././repair/phase6.c:930 .././repair/rmap.c:1484 #, c-format msgid "%s: commit failed, error %d\n" msgstr "" #: .././repair/phase6.c:601 #, c-format msgid "couldn't allocate realtime bitmap, error = %d\n" msgstr "" #: .././repair/phase6.c:614 #, c-format msgid "allocation of the realtime bitmap failed, error = %d\n" msgstr "" #: .././repair/phase6.c:656 #, c-format msgid "couldn't map realtime bitmap block %, error = %d\n" msgstr "" #: .././repair/phase6.c:669 #, c-format msgid "" "can't access block % (fsbno %) of realtime bitmap inode " "%\n" msgstr "" #: .././repair/phase6.c:714 .././repair/phase6.c:788 #, c-format msgid "couldn't iget realtime summary inode -- error - %d\n" msgstr "" #: .././repair/phase6.c:727 #, c-format msgid "couldn't map realtime summary inode block %, error = %d\n" msgstr "" #: .././repair/phase6.c:740 #, c-format msgid "" "can't access block % (fsbno %) of realtime summary inode " "%\n" msgstr "" #: .././repair/phase6.c:847 #, c-format msgid "couldn't allocate realtime summary inode, error = %d\n" msgstr "" #: .././repair/phase6.c:860 #, c-format msgid "allocation of the realtime summary ino failed, error = %d\n" msgstr "" #: .././repair/phase6.c:889 #, c-format msgid "could not iget root inode -- error - %d\n" msgstr "" #: .././repair/phase6.c:967 #, c-format msgid "%d - couldn't iget root inode to obtain %s\n" msgstr "" #: .././repair/phase6.c:998 #, c-format msgid "%s inode allocation failed %d\n" msgstr "" #: .././repair/phase6.c:1045 #, c-format msgid "can't make %s, createname error %d\n" msgstr "" #: .././repair/phase6.c:1064 #, c-format msgid "%s directory creation failed -- bmapf error %d\n" msgstr "" #: .././repair/phase6.c:1101 #, c-format msgid "%d - couldn't iget orphanage inode\n" msgstr "" #: .././repair/phase6.c:1114 #, c-format msgid "%d - couldn't iget disconnected inode\n" msgstr "" #: .././repair/phase6.c:1135 .././repair/phase6.c:1172 #: .././repair/phase6.c:1224 #, c-format msgid "space reservation failed (%d), filesystem may be out of space\n" msgstr "" #: .././repair/phase6.c:1145 .././repair/phase6.c:1183 #: .././repair/phase6.c:1234 #, c-format msgid "name create failed in %s (%d), filesystem may be out of space\n" msgstr "" #: .././repair/phase6.c:1158 #, c-format msgid "creation of .. entry failed (%d), filesystem may be out of space\n" msgstr "" #: .././repair/phase6.c:1166 #, c-format msgid "creation of .. entry failed (%d)\n" msgstr "" #: .././repair/phase6.c:1202 #, c-format msgid "name replace op failed (%d), filesystem may be out of space\n" msgstr "" #: .././repair/phase6.c:1209 #, c-format msgid "orphanage name replace op failed (%d)\n" msgstr "" #: .././repair/phase6.c:1243 #, c-format msgid "orphanage name create failed (%d)\n" msgstr "" #: .././repair/phase6.c:1259 msgid ", marking entry to be junked\n" msgstr "" #: .././repair/phase6.c:1263 msgid ", would junk entry\n" msgstr "" #: .././repair/phase6.c:1336 #, c-format msgid "rebuilding directory inode %\n" msgstr "" #: .././repair/phase6.c:1357 #, c-format msgid "error %d invalidating directory %llu blocks\n" msgstr "" #: .././repair/phase6.c:1361 #, c-format msgid "xfs_bmap_last_offset failed -- error - %d\n" msgstr "" #: .././repair/phase6.c:1369 #, c-format msgid "xfs_bunmapi failed -- error - %d\n" msgstr "" #: .././repair/phase6.c:1387 #, c-format msgid "xfs_dir_init failed -- error - %d\n" msgstr "" #: .././repair/phase6.c:1394 #, c-format msgid "dir init failed (%d)\n" msgstr "" #: .././repair/phase6.c:1420 #, c-format msgid "" "name create failed in ino % (%d), filesystem may be out of space\n" msgstr "" #: .././repair/phase6.c:1428 #, c-format msgid "name create failed (%d) during rebuild\n" msgstr "" #: .././repair/phase6.c:1472 #, c-format msgid "shrink_inode failed inode % block %u\n" msgstr "" #: .././repair/phase6.c:1477 #, c-format msgid "directory shrink failed (%d)\n" msgstr "" #: .././repair/phase6.c:1563 .././repair/phase6.c:2365 #, c-format msgid "realloc failed in %s (%zu bytes)\n" msgstr "" #: .././repair/phase6.c:1620 #, c-format msgid "empty data block %u in directory inode %: " msgstr "" #: .././repair/phase6.c:1624 #, c-format msgid "corrupt block %u in directory inode %: " msgstr "" #: .././repair/phase6.c:1628 msgid "junking block\n" msgstr "" #: .././repair/phase6.c:1631 msgid "would junk block\n" msgstr "" #: .././repair/phase6.c:1652 #, c-format msgid "" "bad directory block magic # %#x for directory inode % block %d: " msgstr "" #: .././repair/phase6.c:1655 #, c-format msgid "fixing magic # to %#x\n" msgstr "" #: .././repair/phase6.c:1659 #, c-format msgid "would fix magic # to %#x\n" msgstr "" #: .././repair/phase6.c:1680 #, c-format msgid "directory inode % block %u has consecutive free entries: " msgstr "" #: .././repair/phase6.c:1684 msgid "joining together\n" msgstr "" #: .././repair/phase6.c:1693 msgid "would join together\n" msgstr "" #: .././repair/phase6.c:1726 #, c-format msgid "" "entry \"%s\" in directory inode % points to non-existent inode " "%" msgstr "" #: .././repair/phase6.c:1743 #, c-format msgid "" "entry \"%s\" in directory inode % points to free inode %" msgstr "" #: .././repair/phase6.c:1761 .././repair/phase6.c:2695 #, c-format msgid "%s (ino %) in root (%) is not a directory" msgstr "" #: .././repair/phase6.c:1783 .././repair/phase6.c:2717 #, c-format msgid "entry \"%s\" (ino %) in dir % is a duplicate name" msgstr "" #: .././repair/phase6.c:1814 #, c-format msgid "" "entry \"%s\" (ino %) in dir % is not in the the first block" msgstr "" #: .././repair/phase6.c:1841 #, c-format msgid "entry \"%s\" in dir % is not the first entry" msgstr "" #: .././repair/phase6.c:1867 .././repair/phase6.c:2786 #, c-format msgid "" "would fix ftype mismatch (%d/%d) in directory/child inode %/" "%\n" msgstr "" #: .././repair/phase6.c:1872 .././repair/phase6.c:2791 #, c-format msgid "" "fixing ftype mismatch (%d/%d) in directory/child inode %/%\n" msgstr "" #: .././repair/phase6.c:1905 #, c-format msgid "" "entry \"%s\" in dir % points to an already connected directory inode " "%\n" msgstr "" #: .././repair/phase6.c:1914 .././repair/phase6.c:2755 #, c-format msgid "" "entry \"%s\" in dir ino % doesn't have a .. entry, will set it in " "ino %.\n" msgstr "" #: .././repair/phase6.c:1924 #, c-format msgid "" "entry \"%s\" in dir inode % inconsistent with .. value (%) " "in ino %\n" msgstr "" #: .././repair/phase6.c:1936 #, c-format msgid "\twill clear entry \"%s\"\n" msgstr "" #: .././repair/phase6.c:1939 #, c-format msgid "\twould clear entry \"%s\"\n" msgstr "" #: .././repair/phase6.c:1953 #, c-format msgid "directory block fixing failed (%d)\n" msgstr "" #: .././repair/phase6.c:1975 #, c-format msgid "expected owner inode %, got %llu, directory block %\n" msgstr "" #: .././repair/phase6.c:1982 #, c-format msgid "expected block %, got %llu, directory inode %\n" msgstr "" #: .././repair/phase6.c:1989 #, c-format msgid "wrong FS UUID, directory inode % block %\n" msgstr "" #: .././repair/phase6.c:2049 #, c-format msgid "leaf block %u for directory inode % bad CRC\n" msgstr "" #: .././repair/phase6.c:2054 #, c-format msgid "can't read block %u for directory inode %, error %d\n" msgstr "" #: .././repair/phase6.c:2072 .././repair/phase6.c:2195 #, c-format msgid "leaf block %u for directory inode % bad header\n" msgstr "" #: .././repair/phase6.c:2098 #, c-format msgid "leaf block %u for directory inode % bad tail\n" msgstr "" #: .././repair/phase6.c:2152 #, c-format msgid "can't read leaf block %u for directory inode %, error %d\n" msgstr "" #: .././repair/phase6.c:2164 #, c-format msgid "unknown magic number %#x for block %u in directory inode %\n" msgstr "" #: .././repair/phase6.c:2220 #, c-format msgid "can't read freespace block %u for directory inode %, error %d\n" msgstr "" #: .././repair/phase6.c:2235 #, c-format msgid "free block %u for directory inode % bad header\n" msgstr "" #: .././repair/phase6.c:2253 #, c-format msgid "free block %u entry %i for directory ino % bad\n" msgstr "" #: .././repair/phase6.c:2263 #, c-format msgid "free block %u for directory inode % bad nused\n" msgstr "" #: .././repair/phase6.c:2274 #, c-format msgid "missing freetab entry %u for directory inode %\n" msgstr "" #: .././repair/phase6.c:2313 #, c-format msgid "malloc failed in %s (% bytes)\n" msgstr "" #: .././repair/phase6.c:2327 #, c-format msgid "calloc failed in %s (%zu bytes)\n" msgstr "" #: .././repair/phase6.c:2381 #, c-format msgid "can't read data block %u for directory inode % error %d\n" msgstr "" #: .././repair/phase6.c:2488 msgid "would junk entry\n" msgstr "" #: .././repair/phase6.c:2512 msgid "junking entry\n" msgstr "" #: .././repair/phase6.c:2558 #, c-format msgid "would set .. in sf dir inode % to %\n" msgstr "" #: .././repair/phase6.c:2562 #, c-format msgid "setting .. in sf dir inode % to %\n" msgstr "" #: .././repair/phase6.c:2662 #, c-format msgid "" "entry \"%s\" in shortform directory % references non-existent inode " "%\n" msgstr "" #: .././repair/phase6.c:2679 #, c-format msgid "" "entry \"%s\" in shortform directory inode % points to free inode " "%\n" msgstr "" #: .././repair/phase6.c:2741 #, c-format msgid "" "entry \"%s\" in directory inode % references already connected inode " "%.\n" msgstr "" #: .././repair/phase6.c:2764 #, c-format msgid "" "entry \"%s\" in directory inode % not consistent with .. value " "(%) in inode %,\n" msgstr "" #: .././repair/phase6.c:2821 #, c-format msgid "would fix i8count in inode %\n" msgstr "" #: .././repair/phase6.c:2836 #, c-format msgid "fixing i8count in inode %\n" msgstr "" #: .././repair/phase6.c:2856 #, c-format msgid "setting size to % bytes to reflect junked entries\n" msgstr "" #: .././repair/phase6.c:2977 #, c-format msgid "error %d fixing shortform directory %llu\n" msgstr "" #: .././repair/phase6.c:3003 msgid "recreating root directory .. entry\n" msgstr "" #: .././repair/phase6.c:3017 #, c-format msgid "can't make \"..\" entry in root inode %, createname error %d\n" msgstr "" #: .././repair/phase6.c:3023 #, c-format msgid "root inode \"..\" entry recreation failed (%d)\n" msgstr "" #: .././repair/phase6.c:3027 msgid "would recreate root directory .. entry\n" msgstr "" #: .././repair/phase6.c:3051 #, c-format msgid "would create missing \".\" entry in dir ino %\n" msgstr "" #: .././repair/phase6.c:3058 #, c-format msgid "creating missing \".\" entry in dir ino %\n" msgstr "" #: .././repair/phase6.c:3072 #, c-format msgid "can't make \".\" entry in dir ino %, createname error %d\n" msgstr "" #: .././repair/phase6.c:3079 #, c-format msgid "root inode \".\" entry recreation failed (%d)\n" msgstr "" #: .././repair/phase6.c:3164 #, c-format msgid "disconnected dir inode %, " msgstr "" #: .././repair/phase6.c:3166 #, c-format msgid "disconnected inode %, " msgstr "" #: .././repair/phase6.c:3170 #, c-format msgid "moving to %s\n" msgstr "" #: .././repair/phase6.c:3173 #, c-format msgid "would move to %s\n" msgstr "" #: .././repair/phase6.c:3258 msgid "Phase 6 - check inode connectivity...\n" msgstr "" #: .././repair/phase6.c:3272 msgid "reinitializing root directory\n" msgstr "" #: .././repair/phase6.c:3277 msgid "would reinitialize root directory\n" msgstr "" #: .././repair/phase6.c:3283 msgid "reinitializing realtime bitmap inode\n" msgstr "" #: .././repair/phase6.c:3287 msgid "would reinitialize realtime bitmap inode\n" msgstr "" #: .././repair/phase6.c:3293 msgid "reinitializing realtime summary inode\n" msgstr "" #: .././repair/phase6.c:3297 msgid "would reinitialize realtime summary inode\n" msgstr "" #: .././repair/phase6.c:3303 msgid " - resetting contents of realtime bitmap and summary inodes\n" msgstr "" #: .././repair/phase6.c:3306 .././repair/phase6.c:3311 msgid "Warning: realtime bitmap may be inconsistent\n" msgstr "" #: .././repair/phase6.c:3317 msgid " - traversing filesystem ...\n" msgstr "" #: .././repair/phase6.c:3340 msgid " - traversal finished ...\n" msgstr "" #: .././repair/phase6.c:3341 #, c-format msgid " - moving disconnected inodes to %s ...\n" msgstr "" #: .././repair/rmap.c:71 msgid "couldn't allocate per-AG reverse map roots\n" msgstr "" #: .././repair/rmap.c:78 msgid "Insufficient memory while allocating reverse mapping slabs." msgstr "" #: .././repair/rmap.c:83 .././repair/rmap.c:322 msgid "" "Insufficient memory while allocating raw metadata reverse mapping slabs." msgstr "" #: .././repair/rmap.c:89 msgid "Insufficient memory while allocating refcount item slabs." msgstr "" #: .././repair/rmap.c:735 msgid "Insufficient memory while recreating refcount tree." msgstr "" #: .././repair/rmap.c:992 msgid "would rebuild corrupt rmap btrees.\n" msgstr "" #: .././repair/rmap.c:1035 #, c-format msgid "" "Missing reverse-mapping record for (%u/%u) %slen %u owner % %s%soff " "%\n" msgstr "" #: .././repair/rmap.c:1039 .././repair/rmap.c:1057 .././repair/rmap.c:1067 msgid "unwritten " msgstr "" #: .././repair/rmap.c:1043 .././repair/rmap.c:1061 .././repair/rmap.c:1071 msgid "attr " msgstr "" #: .././repair/rmap.c:1045 .././repair/rmap.c:1063 .././repair/rmap.c:1073 msgid "bmbt " msgstr "" #: .././repair/rmap.c:1053 #, c-format msgid "" "Incorrect reverse-mapping: saw (%u/%u) %slen %u owner % %s%soff " "%; should be (%u/%u) %slen %u owner % %s%soff %\n" msgstr "" #: .././repair/rmap.c:1188 #, c-format msgid "clearing reflink flag on inode %\n" msgstr "" #: .././repair/rmap.c:1197 msgid "clearing reflink flag on inodes when possible\n" msgstr "" #: .././repair/rmap.c:1218 #, c-format msgid "setting reflink flag on inode %\n" msgstr "" #: .././repair/rmap.c:1291 #, c-format msgid "Unable to fix reflink flag on inode %.\n" msgstr "" #: .././repair/rmap.c:1352 msgid "would rebuild corrupt refcount btrees.\n" msgstr "" #: .././repair/rmap.c:1385 .././repair/rmap.c:1396 #, c-format msgid "Missing reference count record for (%u/%u) len %u count %u\n" msgstr "" #: .././repair/rmap.c:1407 #, c-format msgid "" "Incorrect reference count: saw (%u/%u) len %u nlinks %u; should be (%u/%u) " "len %u nlinks %u\n" msgstr "" #: .././repair/rmap.c:1448 .././repair/rmap.c:1479 #, c-format msgid "failed to fix AGFL on AG %d, error %d\n" msgstr "" #: .././repair/progress.c:21 msgid "directories" msgstr "" #: .././repair/progress.c:23 msgid "allocation groups" msgstr "" #: .././repair/progress.c:25 msgid "AGI unlinked buckets" msgstr "" #: .././repair/progress.c:29 msgid "realtime extents" msgstr "" #: .././repair/progress.c:31 msgid "unlinked lists" msgstr "" #: .././repair/progress.c:38 #, c-format msgid " - %02d:%02d:%02d: %s - %llu of %llu %s done\n" msgstr "" #: .././repair/progress.c:40 #, c-format msgid " - %02d:%02d:%02d: %s - %llu %s done\n" msgstr "" #: .././repair/progress.c:52 msgid "scanning filesystem freespace" msgstr "" #: .././repair/progress.c:54 msgid "scanning agi unlinked lists" msgstr "" #: .././repair/progress.c:56 msgid "check uncertain AG inodes" msgstr "" #: .././repair/progress.c:58 msgid "process known inodes and inode discovery" msgstr "" #: .././repair/progress.c:60 msgid "process newly discovered inodes" msgstr "" #: .././repair/progress.c:62 msgid "setting up duplicate extent list" msgstr "" #: .././repair/progress.c:64 msgid "initialize realtime bitmap" msgstr "" #: .././repair/progress.c:66 msgid "reset realtime bitmaps" msgstr "" #: .././repair/progress.c:68 msgid "check for inodes claiming duplicate blocks" msgstr "" #: .././repair/progress.c:70 msgid "rebuild AG headers and trees" msgstr "" #: .././repair/progress.c:72 msgid "traversing filesystem" msgstr "" #: .././repair/progress.c:74 msgid "traversing all unattached subtrees" msgstr "" #: .././repair/progress.c:76 msgid "moving disconnected inodes to lost+found" msgstr "" #: .././repair/progress.c:78 msgid "verify and correct link counts" msgstr "" #: .././repair/progress.c:80 msgid "verify link counts" msgstr "" #: .././repair/progress.c:119 msgid "cannot malloc pointer to done vector\n" msgstr "" #: .././repair/progress.c:136 msgid "unable to create progress report thread\n" msgstr "" #: .././repair/progress.c:179 msgid "progress_rpt: cannot malloc progress msg buffer\n" msgstr "" #: .././repair/progress.c:192 msgid "progress_rpt: cannot create timer\n" msgstr "" #: .././repair/progress.c:195 msgid "progress_rpt: cannot set timer\n" msgstr "" #: .././repair/progress.c:219 msgid "progress_rpt: cannot lock progress mutex\n" msgstr "" #: .././repair/progress.c:256 .././repair/progress.c:359 .././scrub/scrub.c:50 #: .././scrub/phase5.c:330 #, c-format msgid "%s" msgstr "" #: .././repair/progress.c:264 #, c-format msgid "" "\t- %02d:%02d:%02d: Phase %d: elapsed time %s - processed %d %s per minute\n" msgstr "" #: .././repair/progress.c:269 #, c-format msgid "" "\t- %02d:%02d:%02d: Phase %d: %%% done - estimated remaining time " "%s\n" msgstr "" #: .././repair/progress.c:277 msgid "progress_rpt: error unlock msg mutex\n" msgstr "" #: .././repair/progress.c:283 msgid "cannot delete timer\n" msgstr "" #: .././repair/progress.c:297 msgid "set_progress_msg: cannot lock progress mutex\n" msgstr "" #: .././repair/progress.c:307 msgid "set_progress_msg: cannot unlock progress mutex\n" msgstr "" #: .././repair/progress.c:327 msgid "print_final_rpt: cannot lock progress mutex\n" msgstr "" #: .././repair/progress.c:363 msgid "print_final_rpt: cannot unlock progress mutex\n" msgstr "" #: .././repair/progress.c:412 #, c-format msgid "%02d:%02d:%02d" msgstr "" #: .././repair/progress.c:434 #, c-format msgid "%d week" msgstr "" #: .././repair/progress.c:435 .././repair/progress.c:445 #: .././repair/progress.c:461 .././repair/progress.c:479 #: .././repair/progress.c:494 msgid "s" msgstr "" #: .././repair/progress.c:444 #, c-format msgid "%d day" msgstr "" #: .././repair/progress.c:451 .././repair/progress.c:468 #: .././repair/progress.c:486 .././repair/progress.c:496 msgid ", " msgstr "" #: .././repair/progress.c:460 #, c-format msgid "%d hour" msgstr "" #: .././repair/progress.c:478 #, c-format msgid "%d minute" msgstr "" #: .././repair/progress.c:493 #, c-format msgid "%d second" msgstr "" #: .././repair/progress.c:514 #, c-format msgid "" "\n" " XFS_REPAIR Summary %s\n" msgstr "" #: .././repair/progress.c:516 msgid "Phase\t\tStart\t\tEnd\t\tDuration\n" msgstr "" #: .././repair/progress.c:521 .././repair/progress.c:524 #, c-format msgid "Phase %d:\tSkipped\n" msgstr "" #: .././repair/progress.c:528 #, c-format msgid "Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n" msgstr "" #: .././repair/progress.c:534 #, c-format msgid "" "\n" "Total run time: %s\n" msgstr "" #: .././repair/rt.c:35 msgid "couldn't allocate memory for incore realtime bitmap.\n" msgstr "" #: .././repair/rt.c:39 msgid "couldn't allocate memory for incore realtime summary info.\n" msgstr "" #: .././repair/rt.c:191 #, c-format msgid "can't find block %d for rtbitmap inode\n" msgstr "" #: .././repair/rt.c:199 #, c-format msgid "can't read block %d for rtbitmap inode\n" msgstr "" #: .././repair/rt.c:253 #, c-format msgid "block %d for rtsummary inode is missing\n" msgstr "" #: .././repair/rt.c:261 #, c-format msgid "can't read block %d for rtsummary inode\n" msgstr "" #: .././repair/sb.c:113 msgid "error finding secondary superblock -- failed to memalign buffer\n" msgstr "" #: .././repair/sb.c:150 msgid "found candidate secondary superblock...\n" msgstr "" #: .././repair/sb.c:162 msgid "verified secondary superblock...\n" msgstr "" #: .././repair/sb.c:167 msgid "unable to verify superblock, continuing...\n" msgstr "" #: .././repair/sb.c:217 msgid "" "\n" "attempting to find secondary superblock...\n" msgstr "" #: .././repair/sb.c:533 msgid "failed to memalign superblock buffer\n" msgstr "" #: .././repair/sb.c:540 msgid "couldn't seek to offset 0 in filesystem\n" msgstr "" #: .././repair/sb.c:550 msgid "primary superblock write failed!\n" msgstr "" #: .././repair/sb.c:568 #, c-format msgid "error reading superblock %u -- failed to memalign buffer\n" msgstr "" #: .././repair/sb.c:579 #, c-format msgid "error reading superblock %u -- seek to offset % failed\n" msgstr "" #: .././repair/sb.c:588 #, c-format msgid "superblock read failed, offset %, size %d, ag %u, rval %d\n" msgstr "" #: .././repair/sb.c:635 msgid "couldn't malloc geometry structure\n" msgstr "" #: .././repair/sb.c:787 msgid "" "Only two AGs detected and they do not match - cannot validate filesystem " "geometry.\n" "Use the -o force_geometry option to proceed.\n" msgstr "" #: .././repair/sb.c:803 msgid "" "Only one AG detected - cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n" msgstr "" #: .././repair/sb.c:818 msgid "Not enough matching superblocks - cannot proceed.\n" msgstr "" #: .././repair/sb.c:833 msgid "could not read superblock\n" msgstr "" #: .././repair/da_util.c:73 msgid "attribute" msgstr "" #: .././repair/da_util.c:132 .././repair/da_util.c:561 #, c-format msgid "can't read %s block %u for inode %\n" msgstr "" #: .././repair/da_util.c:145 #, c-format msgid "found non-root LEAFN node in inode % bno = %u\n" msgstr "" #: .././repair/da_util.c:156 #, c-format msgid "bad %s magic number 0x%x in inode % bno = %u\n" msgstr "" #: .././repair/da_util.c:167 #, c-format msgid "corrupt %s tree block %u for inode %\n" msgstr "" #: .././repair/da_util.c:175 #, c-format msgid "bad %s record count in inode %, count = %d, max = %d\n" msgstr "" #: .././repair/da_util.c:189 #, c-format msgid "bad header depth for directory inode %\n" msgstr "" #: .././repair/da_util.c:200 #, c-format msgid "bad %s btree for inode %\n" msgstr "" #: .././repair/da_util.c:250 #, c-format msgid "release_da_cursor_int got unexpected non-null bp, dabno = %u\n" msgstr "" #: .././repair/da_util.c:328 #, c-format msgid "%s block used/count inconsistency - %d/%hu\n" msgstr "" #: .././repair/da_util.c:338 #, c-format msgid "%s block hashvalue inconsistency, expected > %u / saw %u\n" msgstr "" #: .././repair/da_util.c:346 #, c-format msgid "bad %s forward block pointer, expected 0, saw %u\n" msgstr "" #: .././repair/da_util.c:351 #, c-format msgid "bad %s block in inode %\n" msgstr "" #: .././repair/da_util.c:381 #, c-format msgid "" "correcting bad hashval in non-leaf %s block\n" "\tin (level %d) in inode %.\n" msgstr "" #: .././repair/da_util.c:389 #, c-format msgid "" "would correct bad hashval in non-leaf %s block\n" "\tin (level %d) in inode %.\n" msgstr "" #: .././repair/da_util.c:550 #, c-format msgid "can't get map info for %s block %u of inode %\n" msgstr "" #: .././repair/da_util.c:578 #, c-format msgid "bad magic number %x in %s block %u for inode %\n" msgstr "" #: .././repair/da_util.c:585 #, c-format msgid "bad back pointer in %s block %u for inode %\n" msgstr "" #: .././repair/da_util.c:591 #, c-format msgid "entry count %d too large in %s block %u for inode %\n" msgstr "" #: .././repair/da_util.c:598 #, c-format msgid "bad level %d in %s block %u for inode %\n" msgstr "" #: .././repair/da_util.c:662 #, c-format msgid "" "correcting bad hashval in interior %s block\n" "\tin (level %d) in inode %.\n" msgstr "" #: .././repair/da_util.c:670 #, c-format msgid "" "would correct bad hashval in interior %s block\n" "\tin (level %d) in inode %.\n" msgstr "" #: .././repair/threads.c:36 #, c-format msgid "cannot create worker threads, error = [%d] %s\n" msgstr "" #: .././repair/threads.c:51 #, c-format msgid "cannot allocate worker item, error = [%d] %s\n" msgstr "" #: .././repair/threads.c:63 #, c-format msgid "cannot terminate worker item, error = [%d] %s\n" msgstr "" #: .././repair/scan.c:74 .././repair/scan.c:129 #, c-format msgid "can't read btree block %d/%d\n" msgstr "" #: .././repair/scan.c:78 .././repair/scan.c:141 #, c-format msgid "btree block %d/%d is suspect, error %d\n" msgstr "" #: .././repair/scan.c:202 #, c-format msgid "bad magic # %#x in inode % (%s fork) bmbt block %\n" msgstr "" #: .././repair/scan.c:208 #, c-format msgid "" "expected level %d got %d in inode %, (%s fork) bmbt block %\n" msgstr "" #: .././repair/scan.c:218 #, c-format msgid "expected owner inode %, got %llu, bmbt block %\n" msgstr "" #: .././repair/scan.c:228 #, c-format msgid "expected block %, got %llu, bmbt block %\n" msgstr "" #: .././repair/scan.c:238 #, c-format msgid "wrong FS UUID, bmbt block %\n" msgstr "" #: .././repair/scan.c:258 #, c-format msgid "" "bad fwd (right) sibling pointer (saw % parent block says %)\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" #: .././repair/scan.c:268 #, c-format msgid "" "bad back (left) sibling pointer (saw %llu parent block says %)\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" #: .././repair/scan.c:283 #, c-format msgid "" "bad back (left) sibling pointer (saw %llu should be NULL (0))\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" #: .././repair/scan.c:331 #, c-format msgid "inode 0x%bmap block 0x% claimed, state is %d\n" msgstr "" #: .././repair/scan.c:338 #, c-format msgid "inode 0x% bmap block 0x% claimed, state is %d\n" msgstr "" #: .././repair/scan.c:353 #, c-format msgid "bad state %d, inode % bmap block 0x%\n" msgstr "" #: .././repair/scan.c:384 #, c-format msgid "couldn't add inode % bmbt block % reverse-mapping data." msgstr "" #: .././repair/scan.c:392 .././repair/scan.c:443 #, c-format msgid "inode % bad # of bmap records (%u, min - %u, max - %u)\n" msgstr "" #: .././repair/scan.c:422 #, c-format msgid "" "out-of-order bmap key (file offset) in inode %, %s fork, fsbno " "%\n" msgstr "" #: .././repair/scan.c:460 #, c-format msgid "bad bmap btree ptr 0x%llx in ino %\n" msgstr "" #: .././repair/scan.c:488 #, c-format msgid "" "correcting bt key (was %llu, now %) in inode %\n" "\t\t%s fork, btree block %\n" msgstr "" #: .././repair/scan.c:500 #, c-format msgid "" "bad btree key (is %llu, should be %) in inode %\n" "\t\t%s fork, btree block %\n" msgstr "" #: .././repair/scan.c:518 #, c-format msgid "" "bad fwd (right) sibling pointer (saw % should be NULLFSBLOCK)\n" "\tin inode % (%s fork) bmap btree block %\n" msgstr "" #: .././repair/scan.c:577 .././repair/scan.c:944 #, c-format msgid "bad magic # %#x in bt%s block %d/%d\n" msgstr "" #: .././repair/scan.c:595 .././repair/scan.c:963 #, c-format msgid "expected level %d got %d in bt%s block %d/%d\n" msgstr "" #: .././repair/scan.c:609 #, c-format msgid "" "%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" #: .././repair/scan.c:629 .././repair/scan.c:731 .././repair/scan.c:994 #: .././repair/scan.c:1138 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n" msgstr "" #: .././repair/scan.c:647 .././repair/scan.c:1029 .././repair/scan.c:1316 #, c-format msgid "invalid start block %u in record %u of %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:653 .././repair/scan.c:1035 .././repair/scan.c:1322 #, c-format msgid "invalid length %u in record %u of %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:701 #, c-format msgid "block (%d,%d-%d) multiply claimed by %s space tree, state - %d\n" msgstr "" #: .././repair/scan.c:818 #, c-format msgid "" "Static meta block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" #: .././repair/scan.c:827 #, c-format msgid "AG meta block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" #: .././repair/scan.c:835 #, c-format msgid "inode block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" #: .././repair/scan.c:843 #, c-format msgid "" "AG refcount block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" #: .././repair/scan.c:852 #, c-format msgid "in use block (%d,%d-%d) mismatch in %s tree, state - %d,%\n" msgstr "" #: .././repair/scan.c:874 #, c-format msgid "unknown block (%d,%d-%d) mismatch on %s tree, state - %d,%\n" msgstr "" #: .././repair/scan.c:975 #, c-format msgid "%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" #: .././repair/scan.c:1019 #, c-format msgid "invalid flags in record %u of %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:1048 #, c-format msgid "invalid owner in rmap btree record %d (% %u) block %u/%u\n" msgstr "" #: .././repair/scan.c:1055 #, c-format msgid "" "record %d of block (%u/%u) in %s btree cannot have non-inode owner with " "flags\n" msgstr "" #: .././repair/scan.c:1059 #, c-format msgid "" "record %d of block (%u/%u) in %s btree cannot have non-inode owner with " "offset\n" msgstr "" #: .././repair/scan.c:1080 #, c-format msgid "" "out-of-order rmap btree record %d (%u % % %u) block %u/%u\n" msgstr "" #: .././repair/scan.c:1089 .././repair/scan.c:1368 #, c-format msgid "" "record %d in block (%u/%u) of %s tree should be merged with previous record\n" msgstr "" #: .././repair/scan.c:1104 #, c-format msgid "record %d greater than high key of block (%u/%u) in %s tree\n" msgstr "" #: .././repair/scan.c:1160 #, c-format msgid "invalid flags in key %u of %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:1166 #, c-format msgid "key %d greater than high key of block (%u/%u) in %s tree\n" msgstr "" #: .././repair/scan.c:1192 #, c-format msgid "invalid flags in high key %u of %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:1244 #, c-format msgid "bad magic # %#x in %s btree block %d/%d\n" msgstr "" #: .././repair/scan.c:1252 #, c-format msgid "expected level %d got %d in %s btree block %d/%d\n" msgstr "" #: .././repair/scan.c:1266 #, c-format msgid "%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" #: .././repair/scan.c:1285 .././repair/scan.c:1402 #, c-format msgid "bad btree nrecs (%u, min=%u, max=%u) in %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:1303 #, c-format msgid "" "leftover CoW extent has incorrect refcount in record %u of %s btree block %u/" "%u\n" msgstr "" #: .././repair/scan.c:1308 #, c-format msgid "" "leftover CoW extent has invalid startblock in record %u of %s btree block %u/" "%u\n" msgstr "" #: .././repair/scan.c:1343 #, c-format msgid "extent (%u/%u) len %u claimed, state is %d\n" msgstr "" #: .././repair/scan.c:1350 #, c-format msgid "invalid reference count %u in record %u of %s btree block %u/%u\n" msgstr "" #: .././repair/scan.c:1357 #, c-format msgid "out-of-order %s btree record %d (%u %u) block %u/%u\n" msgstr "" #: .././repair/scan.c:1483 #, c-format msgid "badly aligned %s rec (starting inode = %)\n" msgstr "" #: .././repair/scan.c:1497 #, c-format msgid "bad starting inode # (% (0x%x 0x%x)) in %s rec, skipping rec\n" msgstr "" #: .././repair/scan.c:1506 #, c-format msgid "bad ending inode # (% (0x%x 0x%zx)) in %s rec, skipping rec\n" msgstr "" #: .././repair/scan.c:1571 #, c-format msgid "" "ir_holemask/ir_free mismatch, %s chunk %d/%u, holemask 0x%x free 0x%llx\n" msgstr "" #: .././repair/scan.c:1658 #, c-format msgid "" "inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n" msgstr "" #: .././repair/scan.c:1676 #, c-format msgid "" "inode rec for ino % (%d/%d) overlaps existing rec (start %d/%d)\n" msgstr "" #: .././repair/scan.c:1700 #, c-format msgid "ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n" msgstr "" #: .././repair/scan.c:1708 .././repair/scan.c:1898 #, c-format msgid "invalid inode count, inode chunk %d/%u, count %d ninodes %d\n" msgstr "" #: .././repair/scan.c:1762 #, c-format msgid "" "sparse inode chunk claims inode block, finobt block - agno %d, bno %d, inopb " "%d\n" msgstr "" #: .././repair/scan.c:1777 .././repair/scan.c:1789 #, c-format msgid "" "inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb " "%d\n" msgstr "" #: .././repair/scan.c:1799 #, c-format msgid "" "inode chunk claims used block, finobt block - agno %d, bno %d, inopb %d\n" msgstr "" #: .././repair/scan.c:1821 #, c-format msgid "" "finobt rec for ino % (%d/%u) does not match existing rec (%d/%d)\n" msgstr "" #: .././repair/scan.c:1863 #, c-format msgid "undiscovered finobt record, ino % (%d/%u)\n" msgstr "" #: .././repair/scan.c:1885 #, c-format msgid "" "finobt ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n" msgstr "" #: .././repair/scan.c:1891 #, c-format msgid "finobt record with no free inodes, inode chunk %d/%u\n" msgstr "" #: .././repair/scan.c:1946 #, c-format msgid "bad magic # %#x in inobt block %d/%d\n" msgstr "" #: .././repair/scan.c:1954 #, c-format msgid "expected level %d got %d in inobt block %d/%d\n" msgstr "" #: .././repair/scan.c:1977 #, c-format msgid "inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n" msgstr "" #: .././repair/scan.c:2000 #, c-format msgid "dubious inode btree block header %d/%d\n" msgstr "" #: .././repair/scan.c:2108 #, c-format msgid "bad agbno %u in agfl, agno %d\n" msgstr "" #: .././repair/scan.c:2137 #, c-format msgid "can't read agfl block for ag %d\n" msgstr "" #: .././repair/scan.c:2141 #, c-format msgid "agfl has bad CRC for ag %d\n" msgstr "" #: .././repair/scan.c:2157 #, c-format msgid "freeblk count %d != flcount %d in ag %d\n" msgstr "" #: .././repair/scan.c:2184 #, c-format msgid "bad agbno %u for btbno root, agno %d\n" msgstr "" #: .././repair/scan.c:2196 #, c-format msgid "bad agbno %u for btbcnt root, agno %d\n" msgstr "" #: .././repair/scan.c:2215 #, c-format msgid "bad rmapbt block count %u, saw %u\n" msgstr "" #: .././repair/scan.c:2219 #, c-format msgid "bad agbno %u for rmapbt root, agno %d\n" msgstr "" #: .././repair/scan.c:2236 #, c-format msgid "bad refcountbt block count %u, saw %u\n" msgstr "" #: .././repair/scan.c:2240 #, c-format msgid "bad agbno %u for refcntbt root, agno %d\n" msgstr "" #: .././repair/scan.c:2258 #, c-format msgid "agf_btreeblks %u, counted % in ag %u\n" msgstr "" #: .././repair/scan.c:2282 #, c-format msgid "bad agbno %u for inobt root, agno %d\n" msgstr "" #: .././repair/scan.c:2295 #, c-format msgid "bad agbno %u for finobt root, agno %d\n" msgstr "" #: .././repair/scan.c:2312 #, c-format msgid "agi_freecount %u, counted %u in ag %u finobt\n" msgstr "" #: .././repair/scan.c:2322 #, c-format msgid "agi unlinked bucket %d is %u in ag %u (inode=%)\n" msgstr "" #: .././repair/scan.c:2353 msgid "can't allocate memory for superblock\n" msgstr "" #: .././repair/scan.c:2360 msgid "root superblock" msgstr "" #: .././repair/scan.c:2369 msgid "agf block" msgstr "" #: .././repair/scan.c:2378 msgid "agi block" msgstr "" #: .././repair/scan.c:2399 #, c-format msgid "reset bad sb for ag %d\n" msgstr "" #: .././repair/scan.c:2402 #, c-format msgid "would reset bad sb for ag %d\n" msgstr "" #: .././repair/scan.c:2407 #, c-format msgid "reset bad agf for ag %d\n" msgstr "" #: .././repair/scan.c:2410 #, c-format msgid "would reset bad agf for ag %d\n" msgstr "" #: .././repair/scan.c:2415 #, c-format msgid "reset bad agi for ag %d\n" msgstr "" #: .././repair/scan.c:2418 #, c-format msgid "would reset bad agi for ag %d\n" msgstr "" #: .././repair/scan.c:2423 #, c-format msgid "bad uncorrected agheader %d, skipping ag...\n" msgstr "" #: .././repair/scan.c:2486 #, c-format msgid "can't get %s for ag %d\n" msgstr "" #: .././repair/scan.c:2504 msgid "no memory for ag header counts\n" msgstr "" #: .././repair/scan.c:2530 #, c-format msgid "sb_icount %, counted %\n" msgstr "" #: .././repair/scan.c:2535 #, c-format msgid "sb_ifree %, counted %\n" msgstr "" #: .././repair/scan.c:2540 #, c-format msgid "sb_fdblocks %, counted %\n" msgstr "" #: .././repair/scan.c:2546 #, c-format msgid "used blocks %, counted %\n" msgstr "" #: .././rtcp/xfs_rtcp.c:19 #, c-format msgid "%s [-e extsize] [-p] [-V] source target\n" msgstr "" #: .././rtcp/xfs_rtcp.c:58 #, c-format msgid "%s: must specify files to copy\n" msgstr "" #: .././rtcp/xfs_rtcp.c:73 #, c-format msgid "%s: stat of %s failed\n" msgstr "" #: .././rtcp/xfs_rtcp.c:80 #, c-format msgid "%s: final argument is not directory\n" msgstr "" #: .././rtcp/xfs_rtcp.c:127 #, c-format msgid "%s: failed stat on %s: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:148 #, c-format msgid "%s: %s filesystem has no realtime partition\n" msgstr "" #: .././rtcp/xfs_rtcp.c:169 .././rtcp/xfs_rtcp.c:197 #, c-format msgid "%s: open of %s failed: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:186 #, c-format msgid "%s: set attributes on %s failed: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:204 #, c-format msgid "%s: get attributes of %s failed: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:214 .././rtcp/xfs_rtcp.c:251 #, c-format msgid "%s: %s is not a realtime file.\n" msgstr "" #: .././rtcp/xfs_rtcp.c:224 #, c-format msgid "%s: %s file extent size is %d, instead of %d.\n" msgstr "" #: .././rtcp/xfs_rtcp.c:237 .././rtcp/xfs_rtcp.c:260 #, c-format msgid "%s: open of %s source failed: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:274 #, c-format msgid "%s: couldn't get direct I/O information: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:284 #, c-format msgid "%s: extent size %d not a multiple of %d.\n" msgstr "" #: .././rtcp/xfs_rtcp.c:298 #, c-format msgid "The size of %s is not a multiple of %d.\n" msgstr "" #: .././rtcp/xfs_rtcp.c:301 #, c-format msgid "%s will be padded to %lld bytes.\n" msgstr "" #: .././rtcp/xfs_rtcp.c:307 #, c-format msgid "" "Use the -p option to pad %s to a size which is a multiple of %d bytes.\n" msgstr "" #: .././rtcp/xfs_rtcp.c:349 #, c-format msgid "%s: write error: %s\n" msgstr "" #: .././rtcp/xfs_rtcp.c:377 #, c-format msgid "%s: could not open %s: %s\n" msgstr "" #: .././libfrog/fsgeom.c:46 #, c-format msgid "" "meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u\n" " =%-22s reflink=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d\n" "log =%-22s bsize=%-6d blocks=%u, version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n" msgstr "" #: .././libfrog/linux.c:63 #, c-format msgid "%s: %s possibly contains a mounted filesystem\n" msgstr "" #: .././libfrog/linux.c:97 #, c-format msgid "%s: %s contains a mounted and writable filesystem\n" msgstr "" #: .././libfrog/linux.c:101 #, c-format msgid "%s: %s contains a mounted filesystem\n" msgstr "" #: .././libfrog/linux.c:134 #, c-format msgid "%s: %s - cannot set blocksize %d on block device %s: %s\n" msgstr "" #: .././libfrog/linux.c:167 #, c-format msgid "%s: cannot stat the device file \"%s\": %s\n" msgstr "" #: .././libfrog/linux.c:202 #, c-format msgid "%s: can't determine device size\n" msgstr "" #: .././libfrog/linux.c:210 #, c-format msgid "%s: warning - cannot get sector size from block device %s: %s\n" msgstr "" #: .././libfrog/linux.c:264 #, c-format msgid "%s: can't determine memory size\n" msgstr "" #: .././libfrog/paths.c:352 #, c-format msgid "%s: unable to extract mount options for \"%s\"\n" msgstr "" #: .././libfrog/paths.c:452 #, c-format msgid "%s: cannot setup path for mount %s: %s\n" msgstr "" #: .././libfrog/paths.c:474 #, c-format msgid "%s: cannot find mount point for path `%s': %s\n" msgstr "" #: .././libfrog/paths.c:502 #, c-format msgid "%s: cannot setup path for project %s: %s\n" msgstr "" #: .././libfrog/paths.c:543 #, c-format msgid "%s: cannot initialise path table: %s\n" msgstr "" #: .././libfrog/paths.c:563 #, c-format msgid "%s: cannot setup path for project dir %s: %s\n" msgstr "" #: .././libfrog/topology.c:155 #, c-format msgid "%s: %s appears to contain an existing filesystem (%s).\n" msgstr "" #: .././libfrog/topology.c:159 #, c-format msgid "%s: %s appears to contain a partition table (%s).\n" msgstr "" #: .././libfrog/topology.c:163 #, c-format msgid "%s: %s appears to contain something weird according to blkid\n" msgstr "" #: .././libfrog/topology.c:172 #, c-format msgid "%s: probe of %s failed, cannot detect existing filesystem.\n" msgstr "" #: .././libfrog/topology.c:194 #, c-format msgid "%s: Warning: trying to probe topology of a file %s!\n" msgstr "" #: .././libfrog/topology.c:235 #, c-format msgid "warning: device is not properly aligned %s\n" msgstr "" #: .././libfrog/topology.c:240 #, c-format msgid "Use -f to force usage of a misaligned device\n" msgstr "" #: .././libfrog/topology.c:254 #, c-format msgid "warning: unable to probe device topology for device %s\n" msgstr "" #: .././scrub/phase4.c:76 msgid "creating repair workqueue" msgstr "" #: .././scrub/phase4.c:85 msgid "queueing repair work" msgstr "" #: .././scrub/phase4.c:92 msgid "finishing repair work" msgstr "" #: .././scrub/phase7.c:42 msgid "retrieving summary counts" msgstr "" #: .././scrub/phase7.c:140 msgid "setting up block counter" msgstr "" #: .././scrub/phase7.c:150 msgid "counting blocks" msgstr "" #: .././scrub/phase7.c:158 msgid "counting inodes" msgstr "" #: .././scrub/phase7.c:165 .././scrub/phase6.c:729 msgid "estimating verify work" msgstr "" #: .././scrub/phase7.c:191 msgid "data blocks" msgstr "" #: .././scrub/phase7.c:193 msgid "realtime blocks" msgstr "" #: .././scrub/phase7.c:206 #, c-format msgid "%.1f%s data used; %.1f%s realtime data used; %.*f%s inodes used.\n" msgstr "" #: .././scrub/phase7.c:212 #, c-format msgid "%.1f%s data found; %.1f%s realtime data found; %.*f%s inodes found.\n" msgstr "" #: .././scrub/phase7.c:218 #, c-format msgid "%.1f%s data used; %.*f%s inodes used.\n" msgstr "" #: .././scrub/phase7.c:223 #, c-format msgid "%.1f%s data found; %.*f%s inodes found.\n" msgstr "" #: .././scrub/phase7.c:235 msgid "checked inodes" msgstr "" #: .././scrub/phase7.c:243 #, c-format msgid "%.*f%s inodes counted; %.*f%s inodes checked.\n" msgstr "" #: .././scrub/phase7.c:256 msgid "verified blocks" msgstr "" #: .././scrub/phase7.c:263 #, c-format msgid "%.1f%s data counted; %.1f%s data verified.\n" msgstr "" #: .././scrub/progress.c:81 #, c-format msgid "%u % % %s" msgstr "" #: .././scrub/progress.c:103 #, c-format msgid "Phase %u: |" msgstr "" #: .././scrub/progress.c:201 msgid "allocating progress counter" msgstr "" #: .././scrub/progress.c:207 msgid "creating progress reporting thread" msgstr "" #: .././scrub/scrub.c:41 #, c-format msgid "AG %u %s" msgstr "" #: .././scrub/scrub.c:105 msgid "Check incomplete." msgstr "" #: .././scrub/scrub.c:110 .././scrub/scrub.c:113 msgid "Possibly suspect metadata." msgstr "" #: .././scrub/scrub.c:118 msgid "Cross-referencing failed." msgstr "" #: .././scrub/scrub.c:151 .././scrub/scrub.c:723 msgid "Filesystem is shut down, aborting." msgstr "" #: .././scrub/scrub.c:166 msgid "Kernel bug" msgstr "" #: .././scrub/scrub.c:196 msgid "Repairs are required." msgstr "" #: .././scrub/scrub.c:212 msgid "Optimization is possible." msgstr "" #: .././scrub/scrub.c:243 #, c-format msgid "Optimizations of %s are possible." msgstr "" #: .././scrub/scrub.c:262 msgid "adding item to repair list" msgstr "" #: .././scrub/scrub.c:585 msgid "Filesystem is mounted read-only; cannot proceed." msgstr "" #: .././scrub/scrub.c:589 msgid "Filesystem is mounted norecovery; cannot proceed." msgstr "" #: .././scrub/scrub.c:595 #, c-format msgid "Kernel %s %s facility not detected." msgstr "" #: .././scrub/scrub.c:597 msgid "repair" msgstr "" #: .././scrub/scrub.c:597 msgid "scrub" msgstr "" #: .././scrub/scrub.c:703 msgid "Attempting repair." msgstr "" #: .././scrub/scrub.c:706 msgid "Attempting optimization." msgstr "" #: .././scrub/scrub.c:718 msgid "Filesystem is busy, deferring repair." msgstr "" #: .././scrub/scrub.c:748 #, c-format msgid "%s: Don't know how to fix; offline repair required." msgstr "" #: .././scrub/scrub.c:755 msgid "Read-only filesystem; cannot make changes." msgstr "" #: .././scrub/scrub.c:790 msgid "Repair unsuccessful; offline repair required." msgstr "" #: .././scrub/scrub.c:795 msgid "Repairs successful." msgstr "" #: .././scrub/scrub.c:798 msgid "Optimization successful." msgstr "" #: .././scrub/spacemap.c:122 #, c-format msgid "dev %d:%d AG %u fsmap" msgstr "" #: .././scrub/spacemap.c:157 #, c-format msgid "dev %d:%d fsmap" msgstr "" #: .././scrub/spacemap.c:209 msgid "creating fsmap workqueue" msgstr "" #: .././scrub/spacemap.c:217 msgid "queueing rtdev fsmap work" msgstr "" #: .././scrub/spacemap.c:226 msgid "queueing logdev fsmap work" msgstr "" #: .././scrub/spacemap.c:234 msgid "queueing per-AG fsmap work" msgstr "" #: .././scrub/spacemap.c:242 msgid "finishing fsmap work" msgstr "" #: .././scrub/unicrash.c:525 #, c-format msgid "Unicode name \"%s\" in %s contains suspicious text direction overrides." msgstr "" #: .././scrub/unicrash.c:538 #, c-format msgid "Unicode name \"%s\" in %s renders identically to \"%s\"." msgstr "" #: .././scrub/unicrash.c:551 #, c-format msgid "" "Unicode name \"%s\" in %s could be confused with '%s' due to invisible " "characters." msgstr "" #: .././scrub/unicrash.c:562 #, c-format msgid "Unicode name \"%s\" in %s contains control characters." msgstr "" #: .././scrub/unicrash.c:584 #, c-format msgid "Unicode name \"%s\" in %s mixes bidirectional characters." msgstr "" #: .././scrub/unicrash.c:597 #, c-format msgid "Unicode name \"%s\" in %s could be confused with \"%s\"." msgstr "" #: .././scrub/unicrash.c:706 .././scrub/phase6.c:408 .././scrub/phase5.c:189 msgid "extended attribute" msgstr "" #: .././scrub/unicrash.c:722 .././scrub/phase5.c:372 msgid "filesystem label" msgstr "" #: .././scrub/xfs_scrub.c:169 #, c-format msgid "Usage: %s [OPTIONS] mountpoint\n" msgstr "" #: .././scrub/xfs_scrub.c:171 #, c-format msgid "Options:\n" msgstr "" #: .././scrub/xfs_scrub.c:172 #, c-format msgid " -a count Stop after this many errors are found.\n" msgstr "" #: .././scrub/xfs_scrub.c:173 #, c-format msgid " -b Background mode.\n" msgstr "" #: .././scrub/xfs_scrub.c:174 #, c-format msgid " -C fd Print progress information to this fd.\n" msgstr "" #: .././scrub/xfs_scrub.c:175 #, c-format msgid " -e behavior What to do if errors are found.\n" msgstr "" #: .././scrub/xfs_scrub.c:176 #, c-format msgid " -k Do not FITRIM the free space.\n" msgstr "" #: .././scrub/xfs_scrub.c:177 #, c-format msgid " -m path Path to /etc/mtab.\n" msgstr "" #: .././scrub/xfs_scrub.c:178 #, c-format msgid " -n Dry run. Do not modify anything.\n" msgstr "" #: .././scrub/xfs_scrub.c:179 #, c-format msgid " -T Display timing/usage information.\n" msgstr "" #: .././scrub/xfs_scrub.c:180 #, c-format msgid " -v Verbose output.\n" msgstr "" #: .././scrub/xfs_scrub.c:181 #, c-format msgid " -V Print version.\n" msgstr "" #: .././scrub/xfs_scrub.c:182 #, c-format msgid " -x Scrub file data too.\n" msgstr "" #: .././scrub/xfs_scrub.c:266 .././scrub/xfs_scrub.c:317 msgid "getrusage" msgstr "" #: .././scrub/xfs_scrub.c:273 .././scrub/xfs_scrub.c:310 msgid "gettimeofday" msgstr "" #: .././scrub/xfs_scrub.c:279 #, c-format msgid "Phase %u: %s\n" msgstr "" #: .././scrub/xfs_scrub.c:322 #, c-format msgid "Phase %u: " msgstr "" #: .././scrub/xfs_scrub.c:330 #, c-format msgid "%sMemory used: %luk/%luk (%luk/%luk), " msgstr "" #: .././scrub/xfs_scrub.c:335 #, c-format msgid "%sMemory used: %luk, " msgstr "" #: .././scrub/xfs_scrub.c:342 #, c-format msgid "time: %5.2f/%5.2f/%5.2fs\n" msgstr "" #: .././scrub/xfs_scrub.c:361 #, c-format msgid "%sI/O: %.1f%s in, %.1f%s out, %.1f%s tot\n" msgstr "" #: .././scrub/xfs_scrub.c:364 #, c-format msgid "%sI/O rate: %.1f%s/s in, %.1f%s/s out, %.1f%s/s tot\n" msgstr "" #: .././scrub/xfs_scrub.c:381 msgid "Find filesystem geometry." msgstr "" #: .././scrub/xfs_scrub.c:386 msgid "Check internal metadata." msgstr "" #: .././scrub/xfs_scrub.c:391 msgid "Scan all inodes." msgstr "" #: .././scrub/xfs_scrub.c:396 msgid "Defer filesystem repairs." msgstr "" #: .././scrub/xfs_scrub.c:401 msgid "Check directory tree." msgstr "" #: .././scrub/xfs_scrub.c:406 msgid "Verify data file integrity." msgstr "" #: .././scrub/xfs_scrub.c:411 msgid "Check summary counters." msgstr "" #: .././scrub/xfs_scrub.c:437 msgid "Repair filesystem." msgstr "" #: .././scrub/xfs_scrub.c:485 #, c-format msgid "Scrub aborted after phase %d." msgstr "" #: .././scrub/xfs_scrub.c:514 #, c-format msgid "%s: repairs made: %llu; optimizations made: %llu.\n" msgstr "" #: .././scrub/xfs_scrub.c:518 #, c-format msgid "%s: repairs made: %llu.\n" msgstr "" #: .././scrub/xfs_scrub.c:522 #, c-format msgid "%s: optimizations made: %llu.\n" msgstr "" #: .././scrub/xfs_scrub.c:537 msgid "No problems found." msgstr "" #: .././scrub/xfs_scrub.c:542 #, c-format msgid "%s: unfixable errors found: %llu\n" msgstr "" #: .././scrub/xfs_scrub.c:544 #, c-format msgid "unfixable errors found: %llu" msgstr "" #: .././scrub/xfs_scrub.c:549 #, c-format msgid "%s: corruptions found: %llu\n" msgstr "" #: .././scrub/xfs_scrub.c:551 #, c-format msgid "corruptions found: %llu" msgstr "" #: .././scrub/xfs_scrub.c:556 #, c-format msgid "%s: operational errors found: %llu\n" msgstr "" #: .././scrub/xfs_scrub.c:558 #, c-format msgid "operational errors found: %llu" msgstr "" #: .././scrub/xfs_scrub.c:563 #, c-format msgid "%s: warnings found: %llu\n" msgstr "" #: .././scrub/xfs_scrub.c:565 #, c-format msgid "warnings found: %llu" msgstr "" #: .././scrub/xfs_scrub.c:577 #, c-format msgid "%s: Re-run xfs_scrub without -n.\n" msgstr "" #: .././scrub/xfs_scrub.c:579 #, c-format msgid "%s: Unmount and run xfs_repair.\n" msgstr "" #: .././scrub/xfs_scrub.c:646 #, c-format msgid "Unknown error behavior \"%s\".\n" msgstr "" #: .././scrub/xfs_scrub.c:739 .././spaceman/info.c:32 #, c-format msgid "%s: Not a XFS mount point.\n" msgstr "" #: .././scrub/xfs_scrub.c:767 msgid "Too many errors; aborting." msgstr "" #: .././scrub/xfs_scrub.c:770 msgid "Injecting error." msgstr "" #: .././scrub/common.c:125 #, c-format msgid "%s." msgstr "" #: .././scrub/common.c:133 #, c-format msgid " (%s line %d)" msgstr "" #: .././scrub/common.c:356 #, c-format msgid "More than %u naming warnings, shutting up." msgstr "" #: .././scrub/common.c:414 #, c-format msgid "inode % (%/%)%s" msgstr "" #: .././scrub/descr.c:57 msgid "error finding description buffer" msgstr "" #: .././scrub/descr.c:64 #, c-format msgid "error %d while rendering description at %s line %d\n" msgstr "" #: .././scrub/descr.c:94 msgid "creating description buffer" msgstr "" #: .././scrub/inodes.c:127 #, c-format msgid "dev %d:%d AG %u inodes" msgstr "" #: .././scrub/inodes.c:187 msgid "Changed too many times during scan; giving up." msgstr "" #: .././scrub/inodes.c:238 msgid "creating bulkstat workqueue" msgstr "" #: .././scrub/inodes.c:246 msgid "queueing bulkstat work" msgstr "" #: .././scrub/inodes.c:254 msgid "finishing bulkstat work" msgstr "" #: .././scrub/phase1.c:41 msgid "Shutting down filesystem!" msgstr "" #: .././scrub/phase1.c:65 msgid "closing mountpoint fd" msgstr "" #: .././scrub/phase1.c:92 msgid "Must be root to run scrub." msgstr "" #: .././scrub/phase1.c:95 msgid "Not an XFS filesystem." msgstr "" #: .././scrub/phase1.c:131 msgid "allocating action lists" msgstr "" #: .././scrub/phase1.c:138 msgid "getting fshandle" msgstr "" #: .././scrub/phase1.c:148 msgid "Kernel metadata scrubbing facility is not available." msgstr "" #: .././scrub/phase1.c:155 msgid "Kernel metadata repair facility is not available. Use -n to scrub." msgstr "" #: .././scrub/phase1.c:162 msgid "Unable to find log device path." msgstr "" #: .././scrub/phase1.c:167 msgid "Unable to find realtime device path." msgstr "" #: .././scrub/phase1.c:180 #, c-format msgid "%s: using %d threads to scrub.\n" msgstr "" #: .././scrub/phase1.c:205 msgid "Invoking online scrub." msgstr "" #: .././scrub/vfs.c:103 msgid "queueing directory scan work" msgstr "" #: .././scrub/vfs.c:196 msgid "queueing subdirectory scan" msgstr "" #: .././scrub/vfs.c:236 msgid "creating directory scan lock" msgstr "" #: .././scrub/vfs.c:241 msgid "creating directory scan signal" msgstr "" #: .././scrub/vfs.c:248 msgid "creating directory scan workqueue" msgstr "" #: .././scrub/vfs.c:254 msgid "queueing directory scan" msgstr "" #: .././scrub/vfs.c:273 msgid "finishing directory scan work" msgstr "" #: .././scrub/vfs.c:309 msgid "fstrim" msgstr "" #: .././scrub/phase6.c:166 #, c-format msgid "media error at data offset %llu length %llu." msgstr "" #: .././scrub/phase6.c:217 msgid "found unexpected unwritten/delalloc attr fork extent." msgstr "" #: .././scrub/phase6.c:223 msgid "found unexpected realtime attr fork extent." msgstr "" #: .././scrub/phase6.c:229 msgid "media error in extended attribute data." msgstr "" #: .././scrub/phase6.c:288 msgid "(unlinked)" msgstr "" #: .././scrub/phase6.c:298 msgid "Disappeared during read error reporting." msgstr "" #: .././scrub/phase6.c:396 #, c-format msgid "disk offset %" msgstr "" #: .././scrub/phase6.c:399 #, c-format msgid "media error in %s." msgstr "" #: .././scrub/phase6.c:409 msgid "file data" msgstr "" #: .././scrub/phase6.c:410 msgid "media error in extent map" msgstr "" #: .././scrub/phase6.c:482 msgid "walking datadev io errors" msgstr "" #: .././scrub/phase6.c:488 msgid "walking rtdev io errors" msgstr "" #: .././scrub/phase6.c:542 msgid "scheduling media verify command" msgstr "" #: .././scrub/phase6.c:595 msgid "finding bad block bitmap" msgstr "" #: .././scrub/phase6.c:601 msgid "setting bad block bitmap" msgstr "" #: .././scrub/phase6.c:621 msgid "creating datadev badblock bitmap" msgstr "" #: .././scrub/phase6.c:627 msgid "creating realtime badblock bitmap" msgstr "" #: .././scrub/phase6.c:635 msgid "creating datadev media verifier" msgstr "" #: .././scrub/phase6.c:644 msgid "creating logdev media verifier" msgstr "" #: .././scrub/phase6.c:654 msgid "creating rtdev media verifier" msgstr "" #: .././scrub/phase6.c:664 msgid "flushing datadev verify pool" msgstr "" #: .././scrub/phase6.c:668 msgid "flushing logdev verify pool" msgstr "" #: .././scrub/phase6.c:672 msgid "flushing rtdev verify pool" msgstr "" #: .././scrub/phase2.c:41 .././spaceman/health.c:200 #, c-format msgid "AG %u" msgstr "" #: .././scrub/phase2.c:75 msgid "Corrupt primary and secondary block mapping metadata." msgstr "" #: .././scrub/phase2.c:78 msgid "Corrupt secondary block mapping metadata." msgstr "" #: .././scrub/phase2.c:80 msgid "Filesystem might not be repairable." msgstr "" #: .././scrub/phase2.c:134 msgid "creating scrub workqueue" msgstr "" #: .././scrub/phase2.c:154 msgid "queueing per-AG scrub work" msgstr "" #: .././scrub/phase2.c:164 msgid "queueing per-FS scrub work" msgstr "" #: .././scrub/phase2.c:171 msgid "finishing scrub work" msgstr "" #: .././scrub/phase3.c:143 msgid "incrementing scanned inode counter" msgstr "" #: .././scrub/phase3.c:174 msgid "creating scanned inode counter" msgstr "" #: .././scrub/phase3.c:187 msgid "summing scanned inode counter" msgstr "" #: .././scrub/phase5.c:50 msgid "Zero length name found." msgstr "" #: .././scrub/phase5.c:69 #, c-format msgid "Control character found in %s name \"%s\"." msgstr "" #: .././scrub/phase5.c:391 msgid "Filesystem has errors, skipping connectivity checks." msgstr "" #: .././spaceman/file.c:30 #, c-format msgid "%c%03d%c %-14s\n" msgstr "" #: .././spaceman/file.c:59 #, c-format msgid "%s: Not on a mounted XFS filesystem.\n" msgstr "" #: .././spaceman/file.c:68 #, c-format msgid "%s: cannot find mount point." msgstr "" #: .././spaceman/file.c:121 msgid "list current open files" msgstr "" #: .././spaceman/freesp.c:47 #, c-format msgid "Too many histogram buckets.\n" msgstr "" #: .././spaceman/freesp.c:163 #, c-format msgid "%s: fsmap malloc failed.\n" msgstr "" #: .././spaceman/freesp.c:188 #, c-format msgid "%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n" msgstr "" #: .././spaceman/freesp.c:221 #, c-format msgid " rtdev %10llu %10llu\n" msgstr "" #: .././spaceman/freesp.c:224 #, c-format msgid "%10u %10llu %10llu\n" msgstr "" #: .././spaceman/freesp.c:239 #, c-format msgid "Unrecognized AG number: %s\n" msgstr "" #: .././spaceman/freesp.c:342 #, c-format msgid " AG extents blocks\n" msgstr "" #: .././spaceman/freesp.c:368 #, c-format msgid "" "\n" "Examine filesystem free space\n" "\n" " -a agno -- Scan only the given AG agno.\n" " -b -- binary histogram bin size\n" " -d -- debug output\n" " -e bsize -- Use fixed histogram bin size of bsize\n" " -g -- Print only a per-AG summary.\n" " -h hbsz -- Use custom histogram bin size of h1.\n" " Multiple specifications are allowed.\n" " -m bmult -- Use histogram bin size multiplier of bmult.\n" " -r -- Display realtime device free space information.\n" " -s -- Emit freespace summary information.\n" "\n" "Only one of -b, -e, -h, or -m may be specified.\n" "\n" msgstr "" #: .././spaceman/freesp.c:397 msgid "Examine filesystem free space" msgstr "" #: .././spaceman/health.c:182 msgid "unhealthy" msgstr "" #: .././spaceman/health.c:216 #, c-format msgid "inode %llu" msgstr "" #: .././spaceman/health.c:251 #, c-format msgid "%s: not on the open filesystem" msgstr "" #: .././spaceman/health.c:288 #, c-format msgid "inode %" msgstr "" #: .././spaceman/health.c:376 .././spaceman/health.c:404 msgid "filesystem" msgstr "" #: .././spaceman/health.c:421 #, c-format msgid "Health status has not been collected for this filesystem.\n" msgstr "" #: .././spaceman/health.c:423 #, c-format msgid "Please run xfs_scrub(8) to remedy this situation.\n" msgstr "" #: .././spaceman/health.c:433 #, c-format msgid "" "\n" "Report all observed filesystem health problems.\n" "\n" " -a agno -- Report health of the given allocation group.\n" " -c -- Report on the health of all inodes.\n" " -f -- Report health of the overall filesystem.\n" " -i inum -- Report health of a given inode number.\n" " -q -- Only report unhealthy metadata.\n" " paths -- Report health of the given file path.\n" "\n" msgstr "" #: .././spaceman/health.c:459 msgid "Report observed XFS health problems." msgstr "" #: .././spaceman/info.c:17 #, c-format msgid "" "\n" " Pretty-prints the filesystem geometry as derived from the superblock.\n" " The output has the same format as mkfs.xfs, xfs_info, and other utilities.\n" " The opened file must be an XFS mount point.\n" "\n" msgstr "" #: .././spaceman/info.c:50 msgid "pretty-print superblock geometry info" msgstr "" #: .././spaceman/init.c:22 #, c-format msgid "Usage: %s [-c cmd] file\n" msgstr "" #: .././spaceman/init.c:97 #, c-format msgid "Not an XFS filesystem!\n" msgstr "" #: .././spaceman/prealloc.c:68 #, c-format msgid "%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n" msgstr "" #: .././spaceman/prealloc.c:78 #, c-format msgid "" "\n" "Remove speculative preallocation\n" "\n" " -g gid -- remove prealloc on files matching group \n" " -m minlen -- only consider files larger than \n" " -p prid -- remove prealloc on files matching project \n" " -s -- wait for removal to complete\n" " -u uid -- remove prealloc on files matching user \n" "\n" "If none of -u, -g, or -p are specified, this command acts on all files.\n" "minlen can take units.\n" "\n" msgstr "" #: .././spaceman/prealloc.c:103 msgid "Remove speculative preallocation" msgstr "" #: .././spaceman/trim.c:43 #, c-format msgid "bad agno value %s\n" msgstr "" #: .././spaceman/trim.c:94 #, c-format msgid "" "\n" "Discard filesystem free space\n" "\n" " -a agno -- trim all the freespace in the given AG agno\n" " -f -- trim all the freespace in the entire filesystem\n" " offset length -- trim the freespace in the range {offset, length}\n" " -m minlen -- skip freespace extents smaller than minlen\n" "\n" "One of -a, -f, or the offset/length pair are required.\n" "\n" msgstr "" #: .././spaceman/trim.c:117 msgid "Discard filesystem free space" msgstr "" xfsprogs-5.3.0/.gitcensus0000644000175000017500000002260013571622637015265 0ustar nathansnathans.gitignore LICENSES/GPL-2.0 LICENSES/LGPL-2.1 Makefile README VERSION configure.ac copy/Makefile copy/xfs_copy.c copy/xfs_copy.h db/Makefile db/addr.c db/addr.h db/agf.c db/agf.h db/agfl.c db/agfl.h db/agi.c db/agi.h db/attr.c db/attr.h db/attrset.c db/attrset.h db/attrshort.c db/attrshort.h db/bit.c db/bit.h db/block.c db/block.h db/bmap.c db/bmap.h db/bmroot.c db/bmroot.h db/btblock.c db/btblock.h db/btdump.c db/btheight.c db/check.c db/check.h db/command.c db/command.h db/convert.c db/crc.c db/crc.h db/debug.c db/debug.h db/dir2.c db/dir2.h db/dir2sf.c db/dir2sf.h db/dquot.c db/dquot.h db/echo.c db/echo.h db/faddr.c db/faddr.h db/field.c db/field.h db/flist.c db/flist.h db/fprint.c db/fprint.h db/frag.c db/frag.h db/freesp.c db/freesp.h db/fsmap.c db/fsmap.h db/fuzz.c db/fuzz.h db/hash.c db/hash.h db/help.c db/help.h db/info.c db/init.c db/init.h db/inode.c db/inode.h db/input.c db/input.h db/io.c db/io.h db/logformat.c db/logformat.h db/malloc.c db/malloc.h db/metadump.c db/metadump.h db/output.c db/output.h db/print.c db/print.h db/quit.c db/quit.h db/sb.c db/sb.h db/sig.c db/sig.h db/strvec.c db/strvec.h db/symlink.c db/symlink.h db/text.c db/text.h db/type.c db/type.h db/write.c db/write.h db/xfs_admin.sh db/xfs_metadump.sh db/xfs_ncheck.sh debian/Makefile debian/changelog debian/compat debian/control debian/copyright debian/local/initramfs.hook debian/postinst debian/rules debian/source/format debian/watch doc/CHANGES doc/CREDITS doc/INSTALL doc/Makefile doc/README-env-vars.txt doc/sparse.txt estimate/Makefile estimate/xfs_estimate.c fsck/Makefile fsck/xfs_fsck.sh fsr/Makefile fsr/xfs_fsr.c growfs/Makefile growfs/xfs_growfs.c include/Makefile include/atomic.h include/bitops.h include/builddefs.in include/buildmacros include/buildrules include/cache.h include/command.h include/handle.h include/hlist.h include/input.h include/install-sh include/jdm.h include/kmem.h include/libxcmd.h include/libxfs.h include/libxlog.h include/linux.h include/list.h include/parent.h include/platform_defs.h.in include/xfs.h include/xfs_arch.h include/xfs_btree_trace.h include/xfs_inode.h include/xfs_log_recover.h include/xfs_metadump.h include/xfs_mount.h include/xfs_multidisk.h include/xfs_trace.h include/xfs_trans.h include/xqm.h io/Makefile io/attr.c io/bmap.c io/bulkstat.c io/copy_file_range.c io/cowextsize.c io/crc32cselftest.c io/encrypt.c io/fadvise.c io/fiemap.c io/file.c io/freeze.c io/fsmap.c io/fsync.c io/getrusage.c io/imap.c io/init.c io/init.h io/inject.c io/io.h io/label.c io/link.c io/log_writes.c io/madvise.c io/mincore.c io/mmap.c io/open.c io/parent.c io/pread.c io/prealloc.c io/pwrite.c io/readdir.c io/reflink.c io/resblks.c io/scrub.c io/seek.c io/sendfile.c io/shutdown.c io/stat.c io/statx.h io/swapext.c io/sync.c io/sync_file_range.c io/truncate.c io/utimes.c io/xfs_bmap.sh io/xfs_freeze.sh io/xfs_mkfile.sh libfrog/Makefile libfrog/avl64.c libfrog/avl64.h libfrog/bitmap.c libfrog/bitmap.h libfrog/bulkstat.c libfrog/bulkstat.h libfrog/convert.c libfrog/convert.h libfrog/crc32.c libfrog/crc32c.h libfrog/crc32cselftest.h libfrog/crc32defs.h libfrog/fsgeom.c libfrog/fsgeom.h libfrog/gen_crc32table.c libfrog/linux.c libfrog/list_sort.c libfrog/logging.c libfrog/logging.h libfrog/paths.c libfrog/paths.h libfrog/platform.h libfrog/projects.c libfrog/projects.h libfrog/ptvar.c libfrog/ptvar.h libfrog/radix-tree.c libfrog/radix-tree.h libfrog/scrub.c libfrog/scrub.h libfrog/topology.c libfrog/topology.h libfrog/util.c libfrog/util.h libfrog/workqueue.c libfrog/workqueue.h libhandle/Makefile libhandle/handle.c libhandle/jdm.c libhandle/libhandle.sym libxcmd/Makefile libxcmd/command.c libxcmd/help.c libxcmd/input.c libxcmd/quit.c libxfs/Makefile libxfs/cache.c libxfs/defer_item.c libxfs/init.c libxfs/init.h libxfs/kmem.c libxfs/libxfs_api_defs.h libxfs/libxfs_io.h libxfs/libxfs_priv.h libxfs/logitem.c libxfs/rdwr.c libxfs/trans.c libxfs/util.c libxfs/xfs_ag.c libxfs/xfs_ag.h libxfs/xfs_ag_resv.c libxfs/xfs_ag_resv.h libxfs/xfs_alloc.c libxfs/xfs_alloc.h libxfs/xfs_alloc_btree.c libxfs/xfs_alloc_btree.h libxfs/xfs_attr.c libxfs/xfs_attr.h libxfs/xfs_attr_leaf.c libxfs/xfs_attr_leaf.h libxfs/xfs_attr_remote.c libxfs/xfs_attr_remote.h libxfs/xfs_attr_sf.h libxfs/xfs_bit.c libxfs/xfs_bit.h libxfs/xfs_bmap.c libxfs/xfs_bmap.h libxfs/xfs_bmap_btree.c libxfs/xfs_bmap_btree.h libxfs/xfs_btree.c libxfs/xfs_btree.h libxfs/xfs_cksum.h libxfs/xfs_da_btree.c libxfs/xfs_da_btree.h libxfs/xfs_da_format.c libxfs/xfs_da_format.h libxfs/xfs_defer.c libxfs/xfs_defer.h libxfs/xfs_dir2.c libxfs/xfs_dir2.h libxfs/xfs_dir2_block.c libxfs/xfs_dir2_data.c libxfs/xfs_dir2_leaf.c libxfs/xfs_dir2_node.c libxfs/xfs_dir2_priv.h libxfs/xfs_dir2_sf.c libxfs/xfs_dquot_buf.c libxfs/xfs_errortag.h libxfs/xfs_format.h libxfs/xfs_fs.h libxfs/xfs_health.h libxfs/xfs_ialloc.c libxfs/xfs_ialloc.h libxfs/xfs_ialloc_btree.c libxfs/xfs_ialloc_btree.h libxfs/xfs_iext_tree.c libxfs/xfs_inode_buf.c libxfs/xfs_inode_buf.h libxfs/xfs_inode_fork.c libxfs/xfs_inode_fork.h libxfs/xfs_log_format.h libxfs/xfs_log_rlimit.c libxfs/xfs_quota_defs.h libxfs/xfs_refcount.c libxfs/xfs_refcount.h libxfs/xfs_refcount_btree.c libxfs/xfs_refcount_btree.h libxfs/xfs_rmap.c libxfs/xfs_rmap.h libxfs/xfs_rmap_btree.c libxfs/xfs_rmap_btree.h libxfs/xfs_rtbitmap.c libxfs/xfs_sb.c libxfs/xfs_sb.h libxfs/xfs_shared.h libxfs/xfs_symlink_remote.c libxfs/xfs_trans_inode.c libxfs/xfs_trans_resv.c libxfs/xfs_trans_resv.h libxfs/xfs_trans_space.h libxfs/xfs_types.c libxfs/xfs_types.h libxlog/Makefile libxlog/util.c libxlog/xfs_log_recover.c logprint/Makefile logprint/log_copy.c logprint/log_dump.c logprint/log_misc.c logprint/log_print_all.c logprint/log_print_trans.c logprint/log_redo.c logprint/logprint.c logprint/logprint.h m4/Makefile m4/manual_format.m4 m4/multilib.m4 m4/package_aiodev.m4 m4/package_attr.m4 m4/package_blkid.m4 m4/package_devmapper.m4 m4/package_globals.m4 m4/package_icu.m4 m4/package_libcdev.m4 m4/package_pthread.m4 m4/package_rt.m4 m4/package_sanitizer.m4 m4/package_services.m4 m4/package_types.m4 m4/package_utilies.m4 m4/package_uuiddev.m4 man/Makefile man/man2/Makefile man/man2/ioctl_xfs_ag_geometry.2 man/man2/ioctl_xfs_bulkstat.2 man/man2/ioctl_xfs_fsbulkstat.2 man/man2/ioctl_xfs_fscounts.2 man/man2/ioctl_xfs_fsgetxattr.2 man/man2/ioctl_xfs_fsgetxattra.2 man/man2/ioctl_xfs_fsinumbers.2 man/man2/ioctl_xfs_fsop_geometry.2 man/man2/ioctl_xfs_fssetxattr.2 man/man2/ioctl_xfs_getbmap.2 man/man2/ioctl_xfs_getbmapa.2 man/man2/ioctl_xfs_getbmapx.2 man/man2/ioctl_xfs_getresblks.2 man/man2/ioctl_xfs_goingdown.2 man/man2/ioctl_xfs_inumbers.2 man/man2/ioctl_xfs_scrub_metadata.2 man/man2/ioctl_xfs_setresblks.2 man/man3/Makefile man/man3/handle.3 man/man3/xfsctl.3 man/man5/Makefile man/man5/projects.5 man/man5/projid.5 man/man5/xfs.5 man/man8/Makefile man/man8/fsck.xfs.8 man/man8/mkfs.xfs.8 man/man8/xfs_admin.8 man/man8/xfs_bmap.8 man/man8/xfs_copy.8 man/man8/xfs_db.8 man/man8/xfs_estimate.8 man/man8/xfs_freeze.8 man/man8/xfs_fsr.8 man/man8/xfs_growfs.8 man/man8/xfs_info.8 man/man8/xfs_io.8 man/man8/xfs_logprint.8 man/man8/xfs_mdrestore.8 man/man8/xfs_metadump.8 man/man8/xfs_mkfile.8 man/man8/xfs_ncheck.8 man/man8/xfs_quota.8 man/man8/xfs_repair.8 man/man8/xfs_rtcp.8 man/man8/xfs_scrub.8 man/man8/xfs_scrub_all.8 man/man8/xfs_spaceman.8 mdrestore/Makefile mdrestore/xfs_mdrestore.c mkfs/Makefile mkfs/proto.c mkfs/xfs_mkfs.c po/Makefile po/de.po po/pl.po quota/Makefile quota/edit.c quota/free.c quota/init.c quota/init.h quota/linux.c quota/path.c quota/project.c quota/quot.c quota/quota.c quota/quota.h quota/report.c quota/state.c quota/util.c release.sh repair/Makefile repair/README repair/agheader.c repair/agheader.h repair/attr_repair.c repair/attr_repair.h repair/avl.c repair/avl.h repair/bmap.c repair/bmap.h repair/btree.c repair/btree.h repair/da_util.c repair/da_util.h repair/dino_chunks.c repair/dinode.c repair/dinode.h repair/dir2.c repair/dir2.h repair/err_protos.h repair/globals.c repair/globals.h repair/incore.c repair/incore.h repair/incore_bmc.c repair/incore_ext.c repair/incore_ino.c repair/init.c repair/phase1.c repair/phase2.c repair/phase3.c repair/phase4.c repair/phase5.c repair/phase6.c repair/phase7.c repair/prefetch.c repair/prefetch.h repair/progress.c repair/progress.h repair/protos.h repair/rmap.c repair/rmap.h repair/rt.c repair/rt.h repair/sb.c repair/scan.c repair/scan.h repair/slab.c repair/slab.h repair/threads.c repair/threads.h repair/versions.c repair/versions.h repair/xfs_repair.c rtcp/Makefile rtcp/xfs_rtcp.c scrub/Makefile scrub/common.c scrub/common.h scrub/counter.c scrub/counter.h scrub/descr.c scrub/descr.h scrub/disk.c scrub/disk.h scrub/filemap.c scrub/filemap.h scrub/fscounters.c scrub/fscounters.h scrub/inodes.c scrub/inodes.h scrub/phase1.c scrub/phase2.c scrub/phase3.c scrub/phase4.c scrub/phase5.c scrub/phase6.c scrub/phase7.c scrub/progress.c scrub/progress.h scrub/read_verify.c scrub/read_verify.h scrub/repair.c scrub/repair.h scrub/scrub.c scrub/scrub.h scrub/spacemap.c scrub/spacemap.h scrub/unicrash.c scrub/unicrash.h scrub/vfs.c scrub/vfs.h scrub/xfs_scrub.c scrub/xfs_scrub.h scrub/xfs_scrub@.service.in scrub/xfs_scrub_all.cron.in scrub/xfs_scrub_all.in scrub/xfs_scrub_all.service.in scrub/xfs_scrub_all.timer scrub/xfs_scrub_fail scrub/xfs_scrub_fail@.service.in spaceman/Makefile spaceman/file.c spaceman/freesp.c spaceman/health.c spaceman/info.c spaceman/init.c spaceman/init.h spaceman/prealloc.c spaceman/space.h spaceman/trim.c spaceman/xfs_info.sh tools/find-api-violations.sh tools/libxfs-apply tools/libxfs-diff tools/xfsbuflock.py xfsprogs-5.3.0/aclocal.m40000644000175000017500000002647413570057250015125 0ustar nathansnathans# generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- dnl serial 11 (pkg-config-0.29) dnl dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/manual_format.m4]) m4_include([m4/multilib.m4]) m4_include([m4/package_attr.m4]) m4_include([m4/package_blkid.m4]) m4_include([m4/package_devmapper.m4]) m4_include([m4/package_globals.m4]) m4_include([m4/package_icu.m4]) m4_include([m4/package_libcdev.m4]) m4_include([m4/package_pthread.m4]) m4_include([m4/package_rt.m4]) m4_include([m4/package_sanitizer.m4]) m4_include([m4/package_services.m4]) m4_include([m4/package_types.m4]) m4_include([m4/package_utilies.m4]) m4_include([m4/package_uuiddev.m4]) xfsprogs-5.3.0/configure0000755000175000017500000177121213570057250015172 0ustar nathansnathans#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for xfsprogs 5.3.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: linux-xfs@vger.kernel.org about your system, including $0: any error possibly output before this message. Then $0: install a modern shell, or manually run the script $0: under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='xfsprogs' PACKAGE_TARNAME='xfsprogs' PACKAGE_VERSION='5.3.0' PACKAGE_STRING='xfsprogs 5.3.0' PACKAGE_BUGREPORT='linux-xfs@vger.kernel.org' PACKAGE_URL='' ac_unique_file="include/libxfs.h" ac_default_prefix=/usr # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS have_zipped_manpages lto_ldflags lto_cflags have_lto gcc_ranlib gcc_ar threadsan_ldflags threadsan_cflags have_threadsan addrsan_ldflags addrsan_cflags have_addrsan ubsan_ldflags ubsan_cflags have_ubsan libblkid crond_dir have_crond systemd_system_unit_dir have_systemd systemd_LIBS systemd_CFLAGS have_hdio_getgeo have_sg_io have_fstatat have_openat have_libicu libicu_LIBS libicu_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG have_libattr have_mallinfo libdevmapper have_devmapper have_map_sync have_statfs_flags have_getfsmap need_internal_fsxattr have_mremap have_fsetxattr have_readdir have_fls have_mntent have_syncfs have_sync_file_range have_copy_file_range have_preadv have_pwritev2 have_fiemap have_fallocate have_getmntent have_sendfile have_mincore have_madvise have_fadvise libpthread libuuid librt libdirsuffix rpmbuild RPMBUILD rpm_version rpm RPM xgettext XGETTEXT msgmerge MSGMERGE msgfmt MSGFMT sort SORT echo ECHO sed awk makedepend zip ZIP tar TAR make MAKE cc pkg_distribution pkg_group pkg_user malloc_lib opt_build debug_build pkg_release pkg_version pkg_name LOCALIZED_FILES root_libdir root_sbindir enable_scrub enable_lto enable_threadsan enable_addrsan enable_ubsan enable_librt enable_lib64 libtermcap enable_editline libeditline enable_readline libreadline enable_blkid enable_gettext enable_shared BUILD_CFLAGS BUILD_CC CPP LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL AWK RANLIB STRIP ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_shared enable_static with_pic enable_fast_install with_aix_soname with_gnu_ld with_sysroot enable_libtool_lock enable_gettext enable_blkid enable_readline enable_editline enable_termcap enable_lib64 enable_librt enable_ubsan enable_addrsan enable_threadsan enable_lto enable_scrub enable_libicu with_systemd_unit_dir with_crond_dir ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH CPP BUILD_CC BUILD_CFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR libicu_CFLAGS libicu_LIBS systemd_CFLAGS systemd_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures xfsprogs 5.3.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/xfsprogs] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of xfsprogs 5.3.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --enable-shared=yes/no Enable use of shared libraries default=yes --enable-gettext=yes/no Enable alternate language support default=yes --enable-blkid=yes/no Enable use of block device id library default=yes --enable-readline=yes/no Enable readline command editing default=no --enable-editline=yes/no Enable editline command editing default=no --enable-termcap=yes/no Enable terminal capabilities library default=no --enable-lib64=yes/no Enable lib64 support default=yes --enable-librt=yes/no Enable librt support default=yes --enable-ubsan=yes/no Enable Undefined Behavior Sanitizer (UBSAN) default=no --enable-addrsan=yes/no Enable Address Sanitizer (ADDRSAN) default=no --enable-threadsan=yes/no Enable Thread Sanitizer (THREADSAN) default=no --enable-lto=yes/no Enable link time optimization (LTO) default=no --enable-scrub=yes/no Enable build of xfs_scrub utility default=yes --enable-libicu=yes/no Enable Unicode name scanning in xfs_scrub (libicu) default=probe Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, [default=aix]. --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-systemd-unit-dir[=DIR] Install systemd system units into DIR. --with-crond-dir[=DIR] Install system crontabs into DIR. Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory LT_SYS_LIBRARY_PATH User-defined run-time library search path. CPP C preprocessor BUILD_CC C compiler for build tools BUILD_CFLAGS C compiler flags for build tools PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path libicu_CFLAGS C compiler flags for libicu, overriding pkg-config libicu_LIBS linker flags for libicu, overriding pkg-config systemd_CFLAGS C compiler flags for systemd, overriding pkg-config systemd_LIBS linker flags for systemd, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF xfsprogs configure 5.3.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ---------------------------------------- ## ## Report this to linux-xfs@vger.kernel.org ## ## ---------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by xfsprogs $as_me 5.3.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` 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 || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in . "$srcdir"/.; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ac_config_headers="$ac_config_headers include/platform_defs.h" # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.6' macro_revision='2.4.6' ltmain=$ac_aux_dir/ltmain.sh # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case $ECHO in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n "$lt_cv_sys_max_cmd_len"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; then reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 $as_echo "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 $as_echo_n "checking for a working dd... " >&6; } if ${ac_cv_path_lt_DD+:} false; then : $as_echo_n "(cached) " >&6 else printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in dd; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 $as_echo "$ac_cv_path_lt_DD" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 $as_echo_n "checking how to truncate binary pipes... " >&6; } if ${lt_cv_truncate_bin+:} false; then : $as_echo_n "(cached) " >&6 else printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 $as_echo "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[012][,.]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac else pic_mode=default fi # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac else enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 $as_echo_n "checking which variant of shared library versioning to provide... " >&6; } # Check whether --with-aix-soname was given. if test "${with_aix_soname+set}" = set; then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else if ${lt_cv_with_aix_soname+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 $as_echo "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o func_cc_basename $compiler cc_basename=$func_cc_basename_result # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/${ac_tool_prefix}file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC=$CC ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test no = "$hard_links"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs=yes ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) export_dynamic_flag_spec='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test no = "$ld_shlibs"; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi export_dynamic_flag_spec='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' $wl-bernotok' allow_undefined_flag=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test yes = "$lt_cv_ld_force_load"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test yes = "$GCC"; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; then archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi link_all_deplibs=no else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' else archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; osf3*) if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test yes = "$GCC"; then wlarc='$wl' archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='$wl-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='$wl-z,text' allow_undefined_flag='$wl-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test no = "$ld_shlibs" && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test yes,yes = "$GCC,$enable_shared"; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen=shl_load else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen=dlopen else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi fi fi fi fi fi ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report what library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC=$lt_save_CC ac_config_commands="$ac_config_commands libtool" # Only expand once: ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "${BUILD_CC+set}" != "set"; then if test $cross_compiling = no; then BUILD_CC="$CC" else for ac_prog in gcc cc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_BUILD_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BUILD_CC"; then ac_cv_prog_BUILD_CC="$BUILD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_BUILD_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi BUILD_CC=$ac_cv_prog_BUILD_CC if test -n "$BUILD_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_CC" >&5 $as_echo "$BUILD_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$BUILD_CC" && break done fi fi if test "${BUILD_CFLAGS+set}" != "set"; then if test $cross_compiling = no; then BUILD_CFLAGS="$CFLAGS" else BUILD_CFLAGS="-g -O2" fi fi # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; else enable_shared=yes fi # Check whether --enable-gettext was given. if test "${enable_gettext+set}" = set; then : enableval=$enable_gettext; else enable_gettext=yes fi # Check whether --enable-blkid was given. if test "${enable_blkid+set}" = set; then : enableval=$enable_blkid; else enable_blkid=yes fi # Check whether --enable-readline was given. if test "${enable_readline+set}" = set; then : enableval=$enable_readline; test $enable_readline = yes && libreadline="-lreadline" else enable_readline=no fi # Check whether --enable-editline was given. if test "${enable_editline+set}" = set; then : enableval=$enable_editline; test $enable_editline = yes && libeditline="-ledit" else enable_editline=no fi # Check whether --enable-termcap was given. if test "${enable_termcap+set}" = set; then : enableval=$enable_termcap; test $enable_termcap = yes && libtermcap="-ltermcap" fi # Check whether --enable-lib64 was given. if test "${enable_lib64+set}" = set; then : enableval=$enable_lib64; else enable_lib64=yes fi # Check whether --enable-librt was given. if test "${enable_librt+set}" = set; then : enableval=$enable_librt; else enable_librt=yes fi # Enable UBSAN; set enable_ubsan=probe below to enable autoprobe. # Check whether --enable-ubsan was given. if test "${enable_ubsan+set}" = set; then : enableval=$enable_ubsan; else enable_ubsan=no fi # Enable ADDRSAN; set enable_addrsan=probe below to enable autoprobe. # Check whether --enable-addrsan was given. if test "${enable_addrsan+set}" = set; then : enableval=$enable_addrsan; else enable_addrsan=no fi # Enable THREADSAN; set enable_threadsan=probe to enable autoprobe. # Check whether --enable-threadsan was given. if test "${enable_threadsan+set}" = set; then : enableval=$enable_threadsan; else enable_threadsan=no fi # Check whether --enable-lto was given. if test "${enable_lto+set}" = set; then : enableval=$enable_lto; else enable_lto=no fi # Enable xfs_scrub build # Check whether --enable-scrub was given. if test "${enable_scrub+set}" = set; then : enableval=$enable_scrub; else enable_scrub=yes fi # Enable libicu for xfs_scrubbing of malicious unicode sequences in names # Check whether --enable-libicu was given. if test "${enable_libicu+set}" = set; then : enableval=$enable_libicu; else enable_libicu=probe fi # # If the user specified a libdir ending in lib64 do not append another # 64 to the library names. # base_libdir=`basename "$libdir"` case $base_libdir in lib64) enable_lib64=no esac # # Some important tools should be installed into the root partitions. # # Check whether exec_prefix=/usr: and install them to /sbin in that # case. If the user choses a different prefix assume he just wants # a local install for testing and not a system install. # case $exec_prefix:$prefix in NONE:NONE | NONE:/usr | /usr:*) root_sbindir='/sbin' root_libdir="/${base_libdir}" ;; *) root_sbindir="${sbindir}" root_libdir="${libdir}" ;; esac # Find localized files. Don't descend into any "dot directories" # (like .git or .pc from quilt). Strangely, the "-print" argument # to "find" is required, to avoid including such directories in the # list. LOCALIZED_FILES="" for lfile in `find ${srcdir} -path './.??*' -prune -o -name '*.c' -type f -print || exit 1`; do LOCALIZED_FILES="$LOCALIZED_FILES \$(TOPDIR)/$lfile" done pkg_name="xfsprogs" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu . ./VERSION pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} pkg_release=$PKG_BUILD test -z "$BUILD_VERSION" || pkg_release="$BUILD_VERSION" DEBUG=${DEBUG:-'-DDEBUG'} debug_build="$DEBUG" OPTIMIZER=${OPTIMIZER:-'-g -O2'} opt_build="$OPTIMIZER" MALLOCLIB=${MALLOCLIB:-''} malloc_lib="$MALLOCLIB" pkg_user=`id -u -n` test -z "$INSTALL_USER" || pkg_user="$INSTALL_USER" pkg_group=`id -g -n` test -z "$INSTALL_GROUP" || pkg_group="$INSTALL_GROUP" pkg_distribution=`uname -s` test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cc="$CC" if test -z ""$cc""; then echo echo FATAL ERROR: cc does not seem to be installed. echo xfsprogs cannot be built without a working C compiler installation. exit 1 fi if test -z "$MAKE"; then # Extract the first word of "gmake", so it can be a program name with args. set dummy gmake; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MAKE+:} false; then : $as_echo_n "(cached) " >&6 else case $MAKE in [\\/]* | ?:[\\/]*) ac_cv_path_MAKE="$MAKE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MAKE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MAKE=$ac_cv_path_MAKE if test -n "$MAKE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE" >&5 $as_echo "$MAKE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$MAKE"; then # Extract the first word of "make", so it can be a program name with args. set dummy make; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MAKE+:} false; then : $as_echo_n "(cached) " >&6 else case $MAKE in [\\/]* | ?:[\\/]*) ac_cv_path_MAKE="$MAKE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MAKE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MAKE=$ac_cv_path_MAKE if test -n "$MAKE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE" >&5 $as_echo "$MAKE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi make=$MAKE if test -z ""$make""; then echo echo FATAL ERROR: make does not seem to be installed. echo xfsprogs cannot be built without a working GNU make installation. exit 1 fi if test -z "$TAR"; then # Extract the first word of "tar", so it can be a program name with args. set dummy tar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_TAR+:} false; then : $as_echo_n "(cached) " >&6 else case $TAR in [\\/]* | ?:[\\/]*) ac_cv_path_TAR="$TAR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_TAR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi TAR=$ac_cv_path_TAR if test -n "$TAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TAR" >&5 $as_echo "$TAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi tar=$TAR if test -z "$ZIP"; then # Extract the first word of "gzip", so it can be a program name with args. set dummy gzip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ZIP+:} false; then : $as_echo_n "(cached) " >&6 else case $ZIP in [\\/]* | ?:[\\/]*) ac_cv_path_ZIP="$ZIP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ZIP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ZIP=$ac_cv_path_ZIP if test -n "$ZIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIP" >&5 $as_echo "$ZIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi zip=$ZIP { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc -MM is supported" >&5 $as_echo_n "checking whether gcc -MM is supported... " >&6; } if ${ac_cv_gcc_nodeps+:} false; then : $as_echo_n "(cached) " >&6 else cat > conftest.c < int main() { exit(0); } EOF ac_cv_gcc_nodeps=no if ${CC} -MM conftest.c >/dev/null 2>&1; then ac_cv_gcc_nodeps=yes fi rm -f conftest.c a.out fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_nodeps" >&5 $as_echo "$ac_cv_gcc_nodeps" >&6; } makedepend="$cc -MM" if test $ac_cv_gcc_nodeps = no; then makedepend=/bin/true fi if test -z "$AWK"; then # Extract the first word of "awk", so it can be a program name with args. set dummy awk; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_AWK+:} false; then : $as_echo_n "(cached) " >&6 else case $AWK in [\\/]* | ?:[\\/]*) ac_cv_path_AWK="$AWK" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="/bin:/usr/bin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_AWK="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi AWK=$ac_cv_path_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi awk=$AWK if test -z "$SED"; then # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else case $SED in [\\/]* | ?:[\\/]*) ac_cv_path_SED="$SED" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="/bin:/usr/bin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SED=$ac_cv_path_SED if test -n "$SED"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi sed=$SED if test -z "$ECHO"; then # Extract the first word of "echo", so it can be a program name with args. set dummy echo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ECHO+:} false; then : $as_echo_n "(cached) " >&6 else case $ECHO in [\\/]* | ?:[\\/]*) ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="/bin:/usr/bin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ECHO="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ECHO=$ac_cv_path_ECHO if test -n "$ECHO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ECHO" >&5 $as_echo "$ECHO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi echo=$ECHO if test -z "$SORT"; then # Extract the first word of "sort", so it can be a program name with args. set dummy sort; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SORT+:} false; then : $as_echo_n "(cached) " >&6 else case $SORT in [\\/]* | ?:[\\/]*) ac_cv_path_SORT="$SORT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="/bin:/usr/bin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SORT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SORT=$ac_cv_path_SORT if test -n "$SORT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SORT" >&5 $as_echo "$SORT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi sort=$SORT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi if test "$enable_gettext" = yes; then if test -z "$MSGFMT"; then # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MSGFMT+:} false; then : $as_echo_n "(cached) " >&6 else case $MSGFMT in [\\/]* | ?:[\\/]*) ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MSGFMT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MSGFMT=$ac_cv_path_MSGFMT if test -n "$MSGFMT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 $as_echo "$MSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi msgfmt=$MSGFMT if test -z ""$msgfmt""; then echo echo FATAL ERROR: msgfmt does not seem to be installed. echo xfsprogs cannot be built without a working gettext installation. exit 1 fi if test -z "$MSGMERGE"; then # Extract the first word of "msgmerge", so it can be a program name with args. set dummy msgmerge; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MSGMERGE+:} false; then : $as_echo_n "(cached) " >&6 else case $MSGMERGE in [\\/]* | ?:[\\/]*) ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MSGMERGE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MSGMERGE=$ac_cv_path_MSGMERGE if test -n "$MSGMERGE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 $as_echo "$MSGMERGE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi msgmerge=$MSGMERGE if test -z ""$msgmerge""; then echo echo FATAL ERROR: msgmerge does not seem to be installed. echo xfsprogs cannot be built without a working gettext installation. exit 1 fi if test -z "$XGETTEXT"; then # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_XGETTEXT+:} false; then : $as_echo_n "(cached) " >&6 else case $XGETTEXT in [\\/]* | ?:[\\/]*) ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_XGETTEXT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi XGETTEXT=$ac_cv_path_XGETTEXT if test -n "$XGETTEXT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 $as_echo "$XGETTEXT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi xgettext=$XGETTEXT if test -z ""$xgettext""; then echo echo FATAL ERROR: xgettext does not seem to be installed. echo xfsprogs cannot be built without a working gettext installation. exit 1 fi fi if test -z "$RPM"; then # Extract the first word of "rpm", so it can be a program name with args. set dummy rpm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RPM+:} false; then : $as_echo_n "(cached) " >&6 else case $RPM in [\\/]* | ?:[\\/]*) ac_cv_path_RPM="$RPM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RPM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RPM=$ac_cv_path_RPM if test -n "$RPM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RPM" >&5 $as_echo "$RPM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi rpm=$RPM rpm_version=0 test -n "$RPM" && test -x "$RPM" && rpm_version=`$RPM --version \ | awk '{print $NF}' | awk -F. '{V=1; print $V}'` if test $rpm_version -ge 4; then # Extract the first word of "rpmbuild", so it can be a program name with args. set dummy rpmbuild; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RPMBUILD+:} false; then : $as_echo_n "(cached) " >&6 else case $RPMBUILD in [\\/]* | ?:[\\/]*) ac_cv_path_RPMBUILD="$RPMBUILD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RPMBUILD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RPMBUILD=$ac_cv_path_RPMBUILD if test -n "$RPMBUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RPMBUILD" >&5 $as_echo "$RPMBUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rpmbuild=$RPMBUILD else rpmbuild=$RPM fi enable_lib64="$enable_lib64" libdirsuffix="" searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test "$enable_lib64" = "yes" -a -n "$searchpath"; then save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) libdirsuffix=64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) libdirsuffix=64 ;; esac ;; esac fi done IFS="$save_IFS" fi if test "$enable_librt" = "yes"; then librt="-lrt" else librt="" fi for ac_header in uuid.h sys/uuid.h uuid/uuid.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test $ac_cv_header_uuid_h = no -a \ $ac_cv_header_sys_uuid_h = no -a \ $ac_cv_header_uuid_uuid_h = no; then echo echo 'FATAL ERROR: could not find a valid UUID header.' echo 'Install the Universally Unique Identifiers development package.' exit 1 fi for ac_func in uuid_compare do : ac_fn_c_check_func "$LINENO" "uuid_compare" "ac_cv_func_uuid_compare" if test "x$ac_cv_func_uuid_compare" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UUID_COMPARE 1 _ACEOF fi done if test $ac_cv_func_uuid_compare = yes; then libuuid="" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_compare in -luuid" >&5 $as_echo_n "checking for uuid_compare in -luuid... " >&6; } if ${ac_cv_lib_uuid_uuid_compare+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char uuid_compare (); int main () { return uuid_compare (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_uuid_uuid_compare=yes else ac_cv_lib_uuid_uuid_compare=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_compare" >&5 $as_echo "$ac_cv_lib_uuid_uuid_compare" >&6; } if test "x$ac_cv_lib_uuid_uuid_compare" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBUUID 1 _ACEOF LIBS="-luuid $LIBS" else echo echo 'FATAL ERROR: could not find a valid UUID library.' echo 'Install the Universally Unique Identifiers library package.' exit 1 fi libuuid="-luuid" fi for ac_header in pthread.h do : ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_H 1 _ACEOF fi done if test $ac_cv_header_pthread_h = no; then for ac_header in pthread.h do : ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_H 1 _ACEOF else echo echo 'FATAL ERROR: could not find a valid pthread header.' exit 1 fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_mutex_init=yes else ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else echo echo 'FATAL ERROR: could not find a valid pthread library.' exit 1 fi libpthread=-lpthread { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fadvise " >&5 $as_echo_n "checking for fadvise ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include int main () { posix_fadvise(0, 1, 0, POSIX_FADV_NORMAL); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_fadvise=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for madvise " >&5 $as_echo_n "checking for madvise ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include int main () { posix_madvise(0, 0, MADV_NORMAL); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_madvise=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mincore " >&5 $as_echo_n "checking for mincore ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include int main () { mincore(0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_mincore=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile " >&5 $as_echo_n "checking for sendfile ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include int main () { sendfile(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_sendfile=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getmntent " >&5 $as_echo_n "checking for getmntent ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { getmntent(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_getmntent=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fallocate" >&5 $as_echo_n "checking for fallocate... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include #include int main () { fallocate(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_fallocate=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fiemap" >&5 $as_echo_n "checking for fiemap... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include #include int main () { struct fiemap *fiemap; ioctl(0, FS_IOC_FIEMAP, (unsigned long)fiemap); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_fiemap=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pwritev2" >&5 $as_echo_n "checking for pwritev2... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _BSD_SOURCE #include int main () { pwritev2(0, 0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_pwritev2=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for preadv" >&5 $as_echo_n "checking for preadv... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _BSD_SOURCE #define _DEFAULT_SOURCE #include int main () { preadv(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_preadv=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for copy_file_range" >&5 $as_echo_n "checking for copy_file_range... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include #include int main () { syscall(__NR_copy_file_range, 0, 0, 0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_copy_file_range=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sync_file_range" >&5 $as_echo_n "checking for sync_file_range... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include int main () { sync_file_range(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_sync_file_range=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syncfs" >&5 $as_echo_n "checking for syncfs... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include int main () { syncfs(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_syncfs=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext for ac_header in mntent.h do : ac_fn_c_check_header_mongrel "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" if test "x$ac_cv_header_mntent_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MNTENT_H 1 _ACEOF have_mntent=yes fi done ac_fn_c_check_decl "$LINENO" "fls" "ac_cv_have_decl_fls" "#include " if test "x$ac_cv_have_decl_fls" = xyes; then : have_fls=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readdir" >&5 $as_echo_n "checking for readdir... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { readdir(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_readdir=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_fn_c_check_decl "$LINENO" "fsetxattr" "ac_cv_have_decl_fsetxattr" "#include #include " if test "x$ac_cv_have_decl_fsetxattr" = xyes; then : have_fsetxattr=yes fi ac_fn_c_check_decl "$LINENO" "mremap" "ac_cv_have_decl_mremap" "#define _GNU_SOURCE #include " if test "x$ac_cv_have_decl_mremap" = xyes; then : have_mremap=yes fi ac_fn_c_check_type "$LINENO" "struct fsxattr" "ac_cv_type_struct_fsxattr" "#include " if test "x$ac_cv_type_struct_fsxattr" = xyes; then : ac_fn_c_check_member "$LINENO" "struct fsxattr" "fsx_cowextsize" "ac_cv_member_struct_fsxattr_fsx_cowextsize" "#include " if test "x$ac_cv_member_struct_fsxattr_fsx_cowextsize" = xyes; then : else need_internal_fsxattr=yes fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GETFSMAP" >&5 $as_echo_n "checking for GETFSMAP... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include #include #include #include int main () { unsigned long x = FS_IOC_GETFSMAP; struct fsmap_head fh; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_getfsmap=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_fn_c_check_type "$LINENO" "struct statfs" "ac_cv_type_struct_statfs" "#include " if test "x$ac_cv_type_struct_statfs" = xyes; then : ac_fn_c_check_member "$LINENO" "struct statfs" "f_flags" "ac_cv_member_struct_statfs_f_flags" "#include " if test "x$ac_cv_member_struct_statfs_f_flags" = xyes; then : have_statfs_flags=yes fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MAP_SYNC" >&5 $as_echo_n "checking for MAP_SYNC... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { int flags = MAP_SYNC | MAP_SHARED_VALIDATE; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_map_sync=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dm_task_create" >&5 $as_echo_n "checking for library containing dm_task_create... " >&6; } if ${ac_cv_search_dm_task_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dm_task_create (); int main () { return dm_task_create (); ; return 0; } _ACEOF for ac_lib in '' devmapper; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dm_task_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_dm_task_create+:} false; then : break fi done if ${ac_cv_search_dm_task_create+:} false; then : else ac_cv_search_dm_task_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dm_task_create" >&5 $as_echo "$ac_cv_search_dm_task_create" >&6; } ac_res=$ac_cv_search_dm_task_create if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" libdevmapper="-ldevmapper" have_devmapper=yes else have_devmapper=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mallinfo " >&5 $as_echo_n "checking for mallinfo ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct mallinfo test; test.arena = 0; test.hblkhd = 0; test.uordblks = 0; test.fordblks = 0; test = mallinfo(); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_mallinfo=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext for ac_header in attr/attributes.h do : ac_fn_c_check_header_mongrel "$LINENO" "attr/attributes.h" "ac_cv_header_attr_attributes_h" "$ac_includes_default" if test "x$ac_cv_header_attr_attributes_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ATTR_ATTRIBUTES_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct attrlist_cursor" >&5 $as_echo_n "checking for struct attrlist_cursor... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct attrlist_cursor *cur; struct attrlist *list; struct attrlist_ent *ent; int flags = ATTR_ROOT; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_libattr=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$enable_scrub" = "yes"; then if test "$enable_libicu" = "yes" || test "$enable_libicu" = "probe"; then if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libicu" >&5 $as_echo_n "checking for libicu... " >&6; } if test -n "$libicu_CFLAGS"; then pkg_cv_libicu_CFLAGS="$libicu_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-i18n\""; } >&5 ($PKG_CONFIG --exists --print-errors "icu-i18n") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libicu_CFLAGS=`$PKG_CONFIG --cflags "icu-i18n" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$libicu_LIBS"; then pkg_cv_libicu_LIBS="$libicu_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-i18n\""; } >&5 ($PKG_CONFIG --exists --print-errors "icu-i18n") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libicu_LIBS=`$PKG_CONFIG --libs "icu-i18n" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then libicu_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "icu-i18n" 2>&1` else libicu_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "icu-i18n" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libicu_PKG_ERRORS" >&5 have_libicu=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } have_libicu=no else libicu_CFLAGS=$pkg_cv_libicu_CFLAGS libicu_LIBS=$pkg_cv_libicu_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_libicu=yes fi fi if test "$enable_libicu" = "yes" && test "$have_libicu" != "yes"; then as_fn_error $? "libicu not found." "$LINENO" 5 fi fi ac_fn_c_check_decl "$LINENO" "openat" "ac_cv_have_decl_openat" "#include #include #include " if test "x$ac_cv_have_decl_openat" = xyes; then : have_openat=yes fi ac_fn_c_check_decl "$LINENO" "fstatat" "ac_cv_have_decl_fstatat" "#define _GNU_SOURCE #include #include #include " if test "x$ac_cv_have_decl_fstatat" = xyes; then : have_fstatat=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sg_io_hdr " >&5 $as_echo_n "checking for struct sg_io_hdr ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct sg_io_hdr hdr; ioctl(0, SG_IO, &hdr); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_sg_io=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct hd_geometry " >&5 $as_echo_n "checking for struct hd_geometry ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct hd_geometry hdr; ioctl(0, HDIO_GETGEO, &hdr); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_hdio_getgeo=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Check whether --with-systemd_unit_dir was given. if test "${with_systemd_unit_dir+set}" = set; then : withval=$with_systemd_unit_dir; else with_systemd_unit_dir=yes fi if test "x${with_systemd_unit_dir}" != "xno"; then : if test "x${with_systemd_unit_dir}" = "xyes"; then : pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for systemd" >&5 $as_echo_n "checking for systemd... " >&6; } if test -n "$systemd_CFLAGS"; then pkg_cv_systemd_CFLAGS="$systemd_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd\""; } >&5 ($PKG_CONFIG --exists --print-errors "systemd") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_systemd_CFLAGS=`$PKG_CONFIG --cflags "systemd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$systemd_LIBS"; then pkg_cv_systemd_LIBS="$systemd_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd\""; } >&5 ($PKG_CONFIG --exists --print-errors "systemd") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_systemd_LIBS=`$PKG_CONFIG --libs "systemd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then systemd_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd" 2>&1` else systemd_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$systemd_PKG_ERRORS" >&5 with_systemd_unit_dir="" elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } with_systemd_unit_dir="" else systemd_CFLAGS=$pkg_cv_systemd_CFLAGS systemd_LIBS=$pkg_cv_systemd_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for systemd system unit dir" >&5 $as_echo_n "checking for systemd system unit dir... " >&6; } systemd_system_unit_dir="${with_systemd_unit_dir}" if test -n "${systemd_system_unit_dir}"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${systemd_system_unit_dir}" >&5 $as_echo "${systemd_system_unit_dir}" >&6; } have_systemd="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } have_systemd="no" fi else have_systemd="disabled" fi # Check whether --with-crond_dir was given. if test "${with_crond_dir+set}" = set; then : withval=$with_crond_dir; else with_crond_dir=yes fi if test "x${with_crond_dir}" != "xno"; then : if test "x${with_crond_dir}" = "xyes"; then : if test -d "/etc/cron.d"; then : with_crond_dir="/etc/cron.d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for system crontab dir" >&5 $as_echo_n "checking for system crontab dir... " >&6; } crond_dir="${with_crond_dir}" if test -n "${crond_dir}"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${crond_dir}" >&5 $as_echo "${crond_dir}" >&6; } have_crond="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } have_crond="no" fi else have_crond="disabled" fi if test "$enable_blkid" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing blkid_probe_all" >&5 $as_echo_n "checking for library containing blkid_probe_all... " >&6; } if ${ac_cv_search_blkid_probe_all+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char blkid_probe_all (); int main () { return blkid_probe_all (); ; return 0; } _ACEOF for ac_lib in '' blkid; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_blkid_probe_all=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_blkid_probe_all+:} false; then : break fi done if ${ac_cv_search_blkid_probe_all+:} false; then : else ac_cv_search_blkid_probe_all=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_blkid_probe_all" >&5 $as_echo "$ac_cv_search_blkid_probe_all" >&6; } ac_res=$ac_cv_search_blkid_probe_all if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi for ac_func in blkid_probe_get_topology do : ac_fn_c_check_func "$LINENO" "blkid_probe_get_topology" "ac_cv_func_blkid_probe_get_topology" if test "x$ac_cv_func_blkid_probe_get_topology" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_BLKID_PROBE_GET_TOPOLOGY 1 _ACEOF fi done if test $ac_cv_func_blkid_probe_get_topology = yes; then libblkid="-lblkid" else echo echo 'FATAL ERROR: could not find a valid BLKID header.' echo 'Install the Block device ID development package.' exit 1 fi fi if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports UBSAN" >&5 $as_echo_n "checking if C compiler supports UBSAN... " >&6; } OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" UBSAN_FLAGS="-fsanitize=undefined" CFLAGS="$CFLAGS $UBSAN_FLAGS" LDFLAGS="$LDFLAGS $UBSAN_FLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ubsan_cflags=$UBSAN_FLAGS ubsan_ldflags=$UBSAN_FLAGS have_ubsan=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" fi if test "$enable_ubsan" = "yes" && test "$have_ubsan" != "yes"; then as_fn_error $? "UBSAN not supported by compiler." "$LINENO" 5 fi if test "$enable_addrsan" = "yes" || test "$enable_addrsan" = "probe"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports ADDRSAN" >&5 $as_echo_n "checking if C compiler supports ADDRSAN... " >&6; } OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" ADDRSAN_FLAGS="-fsanitize=address" CFLAGS="$CFLAGS $ADDRSAN_FLAGS" LDFLAGS="$LDFLAGS $ADDRSAN_FLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } addrsan_cflags=$ADDRSAN_FLAGS addrsan_ldflags=$ADDRSAN_FLAGS have_addrsan=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" fi if test "$enable_addrsan" = "yes" && test "$have_addrsan" != "yes"; then as_fn_error $? "ADDRSAN not supported by compiler." "$LINENO" 5 fi if test "$enable_threadsan" = "yes" || test "$enable_threadsan" = "probe"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports THREADSAN" >&5 $as_echo_n "checking if C compiler supports THREADSAN... " >&6; } OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" THREADSAN_FLAGS="-fsanitize=thread" CFLAGS="$CFLAGS $THREADSAN_FLAGS" LDFLAGS="$LDFLAGS $ADRSAN_FLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } threadsan_cflags=$THREADSAN_FLAGS threadsan_ldflags=$THREADSAN_FLAGS have_threadsan=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" fi if test "$enable_threadsan" = "yes" && test "$have_threadsan" != "yes"; then as_fn_error $? "THREADSAN not supported by compiler." "$LINENO" 5 fi if test "$have_threadsan" = "yes" && test "$have_addrsan" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ADDRSAN and THREADSAN are not known to work together." >&5 $as_echo "$as_me: WARNING: ADDRSAN and THREADSAN are not known to work together." >&2;} fi if test "$enable_lto" = "yes" || test "$enable_lto" = "probe"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports LTO" >&5 $as_echo_n "checking if C compiler supports LTO... " >&6; } OLD_CFLAGS="$CFLAGS" OLD_LDFLAGS="$LDFLAGS" LTO_FLAGS="-flto -ffat-lto-objects" CFLAGS="$CFLAGS $LTO_FLAGS" LDFLAGS="$LDFLAGS $LTO_FLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } lto_cflags=$LTO_FLAGS lto_ldflags=$LTO_FLAGS # Extract the first word of "gcc-ar", so it can be a program name with args. set dummy gcc-ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_gcc_ar+:} false; then : $as_echo_n "(cached) " >&6 else case $gcc_ar in [\\/]* | ?:[\\/]*) ac_cv_path_gcc_ar="$gcc_ar" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_gcc_ar="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi gcc_ar=$ac_cv_path_gcc_ar if test -n "$gcc_ar"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_ar" >&5 $as_echo "$gcc_ar" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "gcc-ranlib", so it can be a program name with args. set dummy gcc-ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_gcc_ranlib+:} false; then : $as_echo_n "(cached) " >&6 else case $gcc_ranlib in [\\/]* | ?:[\\/]*) ac_cv_path_gcc_ranlib="$gcc_ranlib" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_gcc_ranlib="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi gcc_ranlib=$ac_cv_path_gcc_ranlib if test -n "$gcc_ranlib"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_ranlib" >&5 $as_echo "$gcc_ranlib" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -x "$gcc_ar" && test -x "$gcc_ranlib"; then have_lto=yes fi CFLAGS="${OLD_CFLAGS}" LDFLAGS="${OLD_LDFLAGS}" fi if test "$enable_lto" = "yes" && test "$have_lto" != "yes"; then as_fn_error $? "LTO not supported by compiler." "$LINENO" 5 fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 $as_echo "$ac_cv_sizeof_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char *" >&5 $as_echo_n "checking size of char *... " >&6; } if ${ac_cv_sizeof_char_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char *))" "ac_cv_sizeof_char_p" "$ac_includes_default"; then : else if test "$ac_cv_type_char_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (char *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_char_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char_p" >&5 $as_echo "$ac_cv_sizeof_char_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_CHAR_P $ac_cv_sizeof_char_p _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for umode_t" >&5 $as_echo_n "checking for umode_t... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { umode_t umode; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_UMODE_T 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext have_zipped_manpages=false for d in ${prefix}/share/man ${prefix}/man ; do if test -f $d/man1/man.1.gz then have_zipped_manpages=true break fi done ac_config_files="$ac_config_files include/builddefs" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by xfsprogs $as_me 5.3.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ xfsprogs config.status 5.3.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "include/platform_defs.h") CONFIG_HEADERS="$CONFIG_HEADERS include/platform_defs.h" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "include/builddefs") CONFIG_FILES="$CONFIG_FILES include/builddefs" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "libtool":C) # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 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. # GNU Libtool 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool 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 . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi xfsprogs-5.3.0/config.guess0000755000175000017500000012564413034246133015577 0ustar nathansnathans#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2016 Free Software Foundation, Inc. timestamp='2016-10-02' # 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 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 . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # 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 # # Please send patches to . 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 1992-2016 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 case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # 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 tuples: *-*-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=`(uname -p 2>/dev/null || \ /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 ;; earmv*) arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-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) and ABI. case "${UNAME_MACHINE_ARCH}" in earm*) os=netbsdelf ;; 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 # Determine ABI tags. case "${UNAME_MACHINE_ARCH}" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ;; 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/[-_].*//' | cut -d. -f1,2` ;; 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}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${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 ;; *:Sortix:*:*) echo ${UNAME_MACHINE}-unknown-sortix 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` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; 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:*:[4567]) 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/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` 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:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys 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-${LIBC}`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 "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} 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=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${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-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; e2k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; k1om:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} 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-${LIBC}"; exit; } ;; mips64el:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} 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-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} 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 configure 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 ;; x86_64:Haiku:*:*) echo x86_64-unknown-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 ;; SX-ACE:SUPER-UX:*:*) echo sxace-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 eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then 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 case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi 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 ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} 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 ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac cat >&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: xfsprogs-5.3.0/config.sub0000755000175000017500000010676313034246133015243 0ustar nathansnathans#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2016 Free Software Foundation, Inc. timestamp='2016-11-04' # 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 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 . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # 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 # 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 or 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 1992-2016 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-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) 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*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -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 \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | 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 \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-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-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | 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-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | 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-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | 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 ;; asmjs) basic_machine=asmjs-unknown ;; 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 ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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 | 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 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` os=$os"spe" ;; 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*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 ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; 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 ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-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 ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; 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 ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; 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 | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) 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) 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 | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) 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 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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 ;; tile*) basic_machine=$basic_machine-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 ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; 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* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -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* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -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* \ | -onefs* | -tirtos* | -phoenix* | -fuchsia*) # 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 ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -ios) ;; -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 ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) 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 ;; 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: xfsprogs-5.3.0/install-sh0000755000175000017500000001550613570057246015270 0ustar nathansnathans#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # # This script emulates bsd install and also recognises # two environment variables, with the following semantics :- # # $DIST_MANIFEST - if set, the name of the file to append manifest # information in the following format: # File : f mode owner group src target # Directory: d mode owner group target # Symlink : l linkval target # # $DIST_ROOT - if set, prepend to target # # The sematics of all combinations of these two variables # are as follows: # # $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? # -----------------------------+-------------------------- # not set not set | yes no # not set set | yes no # set not set | no yes # set set | yes yes # _usage() { echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" echo "or $prog -S file target (creates \"target\" symlink)" echo "or $prog -T lt_arg [-o owner] [-g group] [-m mode] libtool.lai directory" echo "" echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" echo "behaviour of this command - see comments in the script." echo "The -D flag is only available for the second usage, and causes" echo "the target directory to be created before installing the file." echo "" exit 1 } _chown () { _st=255 if [ $# -eq 3 ] ; then chown $1:$2 $3 _st=$? if [ $_st -ne 0 ] ; then if [ $REAL_UID != '0' ] ; then if [ ! -f $DIST_ROOT/.chown.quiet ] ; then echo '===============================================' echo Ownership of files under ${DIST_ROOT:-/} echo cannot be changed echo '===============================================' if [ -n "$DIST_ROOT" ] ; then touch $DIST_ROOT/.chown.quiet fi fi _st=0 fi fi fi return $_st } _manifest () { echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} } prog=`basename $0` HERE=`pwd` dflag=false Dflag=false Sflag=false Tflag=false DIRMODE=755 FILEMODE=644 OWNER=`id -u` GROUP=`id -g` REAL_UID=$OWNER # default is to install and don't append manifest INSTALL=true MANIFEST=: : ${DIST_ROOT:=${DESTDIR}} [ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false [ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" [ $# -eq 0 ] && _usage if $INSTALL then CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown else CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true fi [ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true while getopts "Dcm:d:S:o:g:T:" c $* do case $c in c) ;; g) GROUP=$OPTARG ;; o) OWNER=$OPTARG ;; m) DIRMODE=`expr $OPTARG` FILEMODE=$DIRMODE ;; D) Dflag=true ;; S) symlink=$OPTARG Sflag=true ;; d) dir=$DIST_ROOT/$OPTARG dflag=true ;; T) lt_install=$OPTARG Tflag=true ;; *) _usage ;; esac done shift `expr $OPTIND - 1` status=0 if $dflag then # # first usage # $MKDIR -p $dir status=$? if [ $status -eq 0 ] then $CHMOD $DIRMODE $dir status=$? fi if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir status=$? fi $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} elif $Sflag then # # fourth usage (symlink) # if [ $# -ne 1 ] then _usage else target=$DIST_ROOT/$1 fi $LN -s -f $symlink $target status=$? $MANIFEST l $symlink ${target#$DIST_ROOT} elif $Tflag then # # -T (install libs built by libtool) # if [ $# -ne 2 ] then _usage else libtool_lai=$1 # source the libtool variables if [ ! -f $libtool_lai ] then echo "$prog: Unable to find libtool library file $libtool_lai" exit 2 fi . ./$libtool_lai target=$DIST_ROOT/$2 fi case $lt_install in so_dot_version) # Loop until we find libfoo.so.x.y.z, then break out. for solib in $library_names do # does it have enough parts? libfoo.so.x.y.z == 5 cnt=`echo "$solib" | sed -e 's/\./ /g' | wc -w` if [ $cnt -eq 5 ] then install_name=$target/$solib $CP $solib $install_name status=$? $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$solib ${install_name#$DIST_ROOT} break fi done ;; so_*) case $lt_install in so_dot_current) # ln -s libfoo.so.x.y.z to libfoo.so.x from_parts=5 # libfoo.so.x.y.z to_parts=3 # libfoo.so.x ;; so_base) # ln -s libfoo.so.x to libfoo.so from_parts=3 # libfoo.so.x to_parts=2 # libfoo.so ;; *) echo "$prog: -T $lt_install invalid" exit 2 ;; esac # Loop until we find the names, then break out. for solib in $library_names do # does it have enough parts? cnt=`echo "$solib" | sed -e 's/\./ /g' | wc -w` if [ $cnt -eq $from_parts ] then from_name=$solib elif [ $cnt -eq $to_parts ] then to_name=$solib fi if [ -n "$from_name" ] && [ -n "$to_name" ] then install_name=$target/$to_name $LN -s -f $from_name $install_name status=$? $MANIFEST l $from_name ${install_name#$DIST_ROOT} break fi done ;; old_lib) install_name=$target/$old_library $CP $old_library $install_name status=$? $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$old_library ${install_name#$DIST_ROOT} ;; *) echo "$prog: -T $lt_install invalid" exit 2 ;; esac case $lt_install in old_lib|so_dot_version) if [ $status -eq 0 ] then $CHMOD $FILEMODE $install_name $CHOWN $OWNER $GROUP $install_name fi ;; esac else list="" dir="" if [ $# -eq 2 ] then # # second usage # f=$1 dir=$DIST_ROOT/$2 if $Dflag then mkdir -p `dirname $dir` fi $CP $f $dir status=$? if [ $status -eq 0 ] then if [ -f $dir/$f ] then $CHMOD $FILEMODE $dir/$f status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir/$f status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f else $CHMOD $FILEMODE $dir status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} fi fi else # # third usage # n=1 while [ $# -gt 0 ] do if [ $# -gt 1 ] then list="$list $1" else dir=$DIST_ROOT/$1 fi shift done # echo DIR=$dir list=\"$list\" for f in $list do $CP $f $dir status=$? if [ $status -eq 0 ] then $CHMOD $FILEMODE $dir/$f status=$? if [ $status -eq 0 ] then $CHOWN $OWNER $GROUP $dir/$f status=$? fi $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f fi [ $status -ne 0 ] && break done fi fi exit $status xfsprogs-5.3.0/ltmain.sh0000644000175000017500000117671413570057245015115 0ustar nathansnathans#! /bin/sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2014-01-03.01 # libtool (GNU libtool) 2.4.6 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2015 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. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.6 Debian-2.4.6-11" package_revision=2.4.6 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2015-01-20.17; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # Copyright (C) 2004-2015 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. # 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. # As a special exception to the GNU General Public License, if you distribute # this file as part of a program or library that is built using GNU Libtool, # you may include this file under the same distribution terms that you use # for the rest of that program. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNES 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 . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1+=\\ \$func_quote_for_eval_result" }' else func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1=\$$1\\ \$func_quote_for_eval_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_for_eval ARG... # -------------------------- # Aesthetically quote ARGs to be evaled later. # This function returns two values: # i) func_quote_for_eval_result # double-quoted, suitable for a subsequent eval # ii) func_quote_for_eval_unquoted_result # has all characters that are still active within double # quotes backslashified. func_quote_for_eval () { $debug_cmd func_quote_for_eval_unquoted_result= func_quote_for_eval_result= while test 0 -lt $#; do case $1 in *[\\\`\"\$]*) _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; *) _G_unquoted_arg=$1 ;; esac if test -n "$func_quote_for_eval_unquoted_result"; then func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" else func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" fi case $_G_unquoted_arg in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_quoted_arg=\"$_G_unquoted_arg\" ;; *) _G_quoted_arg=$_G_unquoted_arg ;; esac if test -n "$func_quote_for_eval_result"; then func_append func_quote_for_eval_result " $_G_quoted_arg" else func_append func_quote_for_eval_result "$_G_quoted_arg" fi shift done } # func_quote_for_expand ARG # ------------------------- # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { $debug_cmd case $1 in *[\\\`\"]*) _G_arg=`$ECHO "$1" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; *) _G_arg=$1 ;; esac case $_G_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_arg=\"$_G_arg\" ;; esac func_quote_for_expand_result=$_G_arg } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_for_expand "$_G_cmd" eval "func_notquiet $func_quote_for_expand_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_for_expand "$_G_cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # Set a version string for this script. scriptversion=2015-10-07.11; # UTC # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # Copyright (C) 2010-2015 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. # 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 . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# warranty; '. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # to the main code. A hook is just a named list of of function, that can # be run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of functions called by FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It is assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd _G_rc_run_hooks=false case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do if eval $_G_hook '"$@"'; then # store returned options list back into positional # parameters for next 'cmd' execution. eval _G_hook_result=\$${_G_hook}_result eval set dummy "$_G_hook_result"; shift _G_rc_run_hooks=: fi done $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list in your hook function, you may remove/edit # any options that you action, and then pass back the remaining unprocessed # options in '_result', escaped suitably for # 'eval'. In this case you also must return $EXIT_SUCCESS to let the # hook's caller know that it should pay attention to # '_result'. Returning $EXIT_FAILURE signalizes that # arguments are left untouched by the hook and therefore caller will ignore the # result variable. # # Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # No change in '$@' (ignored completely by this hook). There is # # no need to do the equivalent (but slower) action: # # func_quote_for_eval ${1+"$@"} # # my_options_prep_result=$func_quote_for_eval_result # false # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # args_changed=false # # # Note that for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: # args_changed=: # ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # args_changed=: # ;; # *) # Make sure the first unrecognised option "$_G_opt" # # is added back to "$@", we could need that later # # if $args_changed is true. # set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # # if $args_changed; then # func_quote_for_eval ${1+"$@"} # my_silent_option_result=$func_quote_for_eval_result # fi # # $args_changed # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # # false # } # func_add_hook func_validate_options my_option_validation # # You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options_finish [ARG]... # ---------------------------- # Finishing the option parse loop (call 'func_options' hooks ATM). func_options_finish () { $debug_cmd _G_func_options_finish_exit=false if func_run_hooks func_options ${1+"$@"}; then func_options_finish_result=$func_run_hooks_result _G_func_options_finish_exit=: fi $_G_func_options_finish_exit } # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd _G_rc_options=false for my_func in options_prep parse_options validate_options options_finish do if eval func_$my_func '${1+"$@"}'; then eval _G_res_var='$'"func_${my_func}_result" eval set dummy "$_G_res_var" ; shift _G_rc_options=: fi done # Save modified positional parameters for caller. As a top-level # options-parser function we always need to set the 'func_options_result' # variable (regardless the $_G_rc_options value). if $_G_rc_options; then func_options_result=$_G_res_var else func_quote_for_eval ${1+"$@"} func_options_result=$func_quote_for_eval_result fi $_G_rc_options } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propagate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before # returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned). func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= _G_rc_options_prep=false if func_run_hooks func_options_prep ${1+"$@"}; then _G_rc_options_prep=: # save modified positional parameters for caller func_options_prep_result=$func_run_hooks_result fi $_G_rc_options_prep } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd func_parse_options_result= _G_rc_parse_options=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. if func_run_hooks func_parse_options ${1+"$@"}; then eval set dummy "$func_run_hooks_result"; shift _G_rc_parse_options=: fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) if test $# = 0 && func_missing_arg $_G_opt; then _G_rc_parse_options=: break fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) _G_rc_parse_options=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift _G_match_parse_options=false break ;; esac $_G_match_parse_options && _G_rc_parse_options=: done if $_G_rc_parse_options; then # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} func_parse_options_result=$func_quote_for_eval_result fi $_G_rc_parse_options } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd _G_rc_validate_options=false # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" if func_run_hooks func_validate_options ${1+"$@"}; then # save modified positional parameters for caller func_validate_options_result=$func_run_hooks_result _G_rc_validate_options=: fi # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE $_G_rc_validate_options } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables after # splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} test "x$func_split_equals_lhs" = "x$1" \ && func_split_equals_rhs= }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /(C)/!b go :more /\./!{ N s|\n# | | b more } :go /^# Written by /,/# warranty; / { s|^# || s|^# *$|| s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| p } /^# Written by / { s|^# || p } /^warranty; /q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname $scriptversion Debian-2.4.6-11 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func__fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= _G_rc_lt_options_prep=: # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; *) _G_rc_lt_options_prep=false ;; esac if $_G_rc_lt_options_prep; then # Pass back the list of options. func_quote_for_eval ${1+"$@"} libtool_options_prep_result=$func_quote_for_eval_result fi $_G_rc_lt_options_prep } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd _G_rc_lt_parse_options=false # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"} ; shift _G_match_lt_parse_options=false break ;; esac $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done if $_G_rc_lt_parse_options; then # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} libtool_parse_options_result=$func_quote_for_eval_result fi $_G_rc_lt_parse_options } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote_for_eval ${1+"$@"} libtool_validate_options_result=$func_quote_for_eval_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix '.c' with the library object suffix, '.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to '-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the '--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the 'install' or 'cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with '-') are ignored. Every other argument is treated as a filename. Files ending in '.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in '.la', then a libtool library is created, only library objects ('.lo' files) may be specified, and '-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created using 'ar' and 'ranlib', or on Windows using 'lib'. If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir=$absdir # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic=$magic # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the '-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the '$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the '$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the '$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg=$1 shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg=$arg case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer # -fuse-ld=* Linker select flags for GCC -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ -specs=*|-fsanitize=*|-fuse-ld=*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_for_eval "$arg" arg=$func_quote_for_eval_result fi ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname=$dlname elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test prog = "$linkmode"; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test unsupported != "$hardcode_direct"; then test -n "$old_library" && linklib=$old_library compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system cannot link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=deplibs fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type '$version_type'" ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles=$dlfiles dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles=$dlprefiles dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release= versuffix= major= newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib=$potent_lib while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | $SED 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test no = "$allow_undefined"; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath=$finalize_shlibpath test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath=$rpath rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath=$rpath if test -n "$libobjs" && test yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; then # We don't need to create a wrapper script. link_command=$compile_var$compile_command$compile_rpath # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; then if test -z "$install_libdir"; then break fi output=$output_objdir/${outputname}i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic for arg do case $arg in -f) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the $objdir's in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: